OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
cloud_flag.c
Go to the documentation of this file.
1 #include "l1.h"
2 #include <nc4utils.h>
3 #include <hdf4utils.h>
4 
5 int get_sdps_cld_mask( l1str *l1rec, int32_t ip, char *cld_category ){
6 /*
7  get_sdps_cld_mask - get the cloud mask catergoy, and the cloud/no cloud
8  from the cloud mask file made for SDPS
9 
10  Returns: int the cloud value: 0 no cloud, 1 cloud
11  l1str *l1rec: supply the cloud mask file name, controls
12  int32_t ip: pixel #
13  char *cld_category: the cloud category: 0 - confident_cloudy,
14  1 - probablyclear, 2 - probablyclear, 3 - probablyclear
15 
16  WDR, 29 Mar 2021
17  */
18  static size_t start[] = {0,0}, count[] = {0,0}, fil_np;
19  static int firstCall = 1;
20  static int ncid, d_id, dim_id;
21  static signed char* msk_lcl;
22  static int lastScan = -1;
23 
24  if (firstCall) {
25  char sdsname[HDF4_UTILS_MAX_NAME] = "";
26  char file [FILENAME_MAX] = "";
27 
28  if (!l1_input->cld_msk_file[0]) {
29  printf("-E- %s line %d: no cloud flag file provided\n",
30  __FILE__, __LINE__);
31  exit(1);
32  }
33 
34  strcpy(file, l1_input->cld_msk_file);
35  printf("Loading cloud mask flag file %s\n", file);
36 
37  /* Open the file */
38  if (nc_open(file, 0, &ncid) != NC_NOERR) {
39  fprintf(stderr,
40  "-E- %s %d: file: %s is not netcdf, not acceptable cloud maskfile\n",
41  __FILE__, __LINE__, file);
42  exit(1);
43  }
44  // get the # pixels
45  if (nc_inq_dimid(ncid, "pixels_per_line", &dim_id ) != NC_NOERR) {
46  fprintf(stderr,
47  "-E- %s %d: file: %s Could not read the pixels_per_line id\n",
48  __FILE__, __LINE__, file);
49  exit(1);
50  }
51 
52  if (nc_inq_dimlen(ncid, dim_id, &fil_np ) != NC_NOERR) {
53  fprintf(stderr,
54  "-E- %s %d: file: %s Could not read the pixels_per_line\n",
55  __FILE__, __LINE__, file);
56  exit(1);
57  }
58 
59  strcpy(sdsname, "CF_CATEGORY");
60  if( nc_inq_varid(ncid, sdsname, &d_id ) != NC_NOERR) {
61  fprintf(stderr,
62  "-E- %s %d: file: %s Could not find SDS CF_CATEGORY\n",
63  __FILE__, __LINE__, file);
64  exit(1);
65  }
66  // get the range to process and set it
67  start[1] = l1_input->spixl - 1; // spixl, epixl are 1-origin!
68  count[1] = l1_input->epixl - l1_input->spixl + 1;
69  count[0] = 1;
70  // start[0] will be the line to read
71  if( ( msk_lcl = (signed char *)
72  malloc( count[1] * sizeof( signed char *) ) ) == NULL ) {
73  fprintf(stderr,
74  "-E- %s %d: file: %s Could not allocate cloud mask storage\n",
75  __FILE__, __LINE__, file);
76  exit(1);
77  }
78  firstCall = 0;
79  // end setup
80  }
81 
82  if (lastScan != l1rec->iscan) {
83  start[0] = l1rec->iscan;
84  if( nc_get_vara_schar( ncid, d_id, start, count, msk_lcl ) != NC_NOERR ) {
85  fprintf(stderr,
86  "-E- %s %d: Could not read the cloud mask file line\n",
87  __FILE__, __LINE__);
88  exit(1);
89  }
90  lastScan = l1rec->iscan;
91  }
92 
93 
94  *cld_category = msk_lcl[ip];
95 
96  if (*cld_category < 2 )
97  return (1);
98  else
99  return (0);
100 }
101 
102 char get_cloudmask_meris(l1str *l1rec, int32_t ip) {
103  // Cloud Masking for MERIS and OLCI
104 
105  static int ib443, ib490, ib560, ib620, ib665, ib681, ib709, ib754, ib865, ib885, firstCall = 1;
106  int ipb;
107  float *rhos = l1rec->rhos, *cloud_albedo = l1rec->cloud_albedo;
108  float ftemp, cldtmp;
109  char flagcld;
110  static productInfo_t* rhos_product_info;
111 
112  if (firstCall == 1) {
113  ib443 = bindex_get(443);
114  ib490 = bindex_get(490);
115  ib560 = bindex_get(560);
116  ib620 = bindex_get(620);
117  ib665 = bindex_get(665);
118  ib681 = bindex_get(681);
119  ib709 = bindex_get(709);
120  ib754 = bindex_get(754);
121  ib865 = bindex_get(865);
122  ib885 = bindex_get(885);
123 
124  if (ib443 < 0 || ib490 < 0 || ib560 < 0 || ib620 < 0 || ib665 < 0 || ib681 < 0 || ib709 < 0 || ib754 < 0 || ib865 < 0 || ib885 < 0) {
125  printf("get_habs_cldmask: incompatible sensor wavelengths for this algorithm\n");
126  exit(EXIT_FAILURE);
127  }
128 
129  if (rhos_product_info == NULL) {
130  rhos_product_info = allocateProductInfo();
131  findProductInfo("rhos", l1rec->l1file->sensorID, rhos_product_info);
132  }
133 
134  firstCall = 0;
135  }
136  flagcld = 0;
137  ipb = l1rec->l1file->nbands*ip;
138 
139  if (rhos[ipb + ib443] >= 0.0 &&
140  rhos[ipb + ib560] >= 0.0 &&
141  rhos[ipb + ib620] >= 0.0 &&
142  rhos[ipb + ib665] >= 0.0 &&
143  rhos[ipb + ib681] >= 0.0 &&
144  rhos[ipb + ib709] >= 0.0 &&
145  rhos[ipb + ib754] >= 0.0) {
146  // turbidity signal in water
147  if ((rhos[ipb + ib443] <= rhos_product_info->validMax) &&
148  (rhos[ipb + ib665] <= rhos_product_info->validMax) &&
149  (rhos[ipb + ib620] <= rhos_product_info->validMax) &&
150  (rhos[ipb + ib681] <= rhos_product_info->validMax) &&
151  (rhos[ipb + ib754] <= rhos_product_info->validMax)) {
152 
153  ftemp = (rhos[ipb + ib620] + rhos[ipb + ib665] + rhos[ipb + ib681]) - 3 * rhos[ipb + ib443] - \
154  (rhos[ipb + ib754] - rhos[ipb + ib443]) / (754 - 443)*(620 + 665 + 681 - 3 * 443);
155  } else {
156  ftemp = 0;
157  }
158  //switch to rhos_865 where cldalb fails
159  if (cloud_albedo[ip] >= 0.0) {
160  cldtmp = cloud_albedo[ip];
161  } else {
162  cldtmp = rhos[ipb + ib865];
163  }
164 
165  //remove turbidity signal from cloud albedo
166  if (ftemp > 0) cldtmp = cldtmp - 3 * ftemp;
167 
168  if (cldtmp > 0.08) {
169  flagcld = 1;
170  }
171 
172  // to deal with scum look at relative of NIR and blue for lower albedos
173  if ((rhos[ipb + ib754] <= rhos_product_info->validMax) &&
174  (rhos[ipb + ib709] <= rhos_product_info->validMax) &&
175  (rhos[ipb + ib681] <= rhos_product_info->validMax) &&
176  (rhos[ipb + ib560] <= rhos_product_info->validMax)) {
177 
178  if ((rhos[ipb + ib443] <= rhos_product_info->validMax) &&
179  (rhos[ipb + ib490] <= rhos_product_info->validMax)) {
180  if ((rhos[ipb + ib754] + rhos[ipb + ib709]) > (rhos[ipb + ib443] + rhos[ipb + ib490]) && cldtmp < 0.1 && (rhos[ipb + ib560] > rhos[ipb + ib681])) flagcld = 0;
181  }
182  if (rhos[ipb + ib665] <= rhos_product_info->validMax) {
183  if (((rhos[ipb + ib754] + rhos[ipb + ib709]) - (rhos[ipb + ib665] + rhos[ipb + ib681])) > 0.01 && cldtmp < 0.15 && (rhos[ipb + ib560] > rhos[ipb + ib681])) flagcld = 0;
184  if ((((rhos[ipb + ib754] + rhos[ipb + ib709]) - (rhos[ipb + ib665] + rhos[ipb + ib681])) / cldtmp) > 0.1 && (rhos[ipb + ib560] > rhos[ipb + ib681])) flagcld = 0;
185  }
186  }
187  if (rhos[ipb + ib665] <= rhos_product_info->validMax) {
188  if ((rhos[ipb + ib665] > 0.1) && (cldtmp > 0.15)) {
189  flagcld = 1;
190  }
191  }
192  if ((rhos[ipb + ib865] >= rhos_product_info->validMin) &&
193  (rhos[ipb + ib865] <= rhos_product_info->validMax)) {
194  // flag high glint
195  if (rhos[ipb + ib865] - cloud_albedo[ip] > 0.25) {
196  flagcld = 1;
197  }
198  } else {
199  flagcld = 1;
200  }
201  }
202 
203  if (l1rec->iscan == l1rec->l1file->nscan) {
204  freeProductInfo(rhos_product_info);
205  }
206 
207  return (flagcld);
208 }
209 
210 char get_cloudmask_modis(l1str *l1rec, int32_t ip) {
211  // Cloud Masking for MODIS
212  static int firstCall = 1;
213  static int ib469, ib555, ib645, ib667, ib859, ib1240, ib2130;
214  int ipb;
215  float *rhos = l1rec->rhos, *cloud_albedo = l1rec->cloud_albedo;
216  float ftemp, ftemp2, ftemp3;
217  float cloudthr = 0.027;
218  char flagcld;
219 
220  if (firstCall == 1) {
221  ib469 = bindex_get(469);
222  ib555 = bindex_get(555);
223  ib645 = bindex_get(645);
224  ib667 = bindex_get(667);
225  ib859 = bindex_get(859);
226  ib1240 = bindex_get(1240);
227  ib2130 = bindex_get(2130);
228  if (ib469 < 0 || ib555 < 0 || ib645 < 0 || ib667 < 0 || ib859 < 0 || ib1240 < 0 || ib2130 < 0) {
229  printf("get_habs_cldmask: incompatible sensor wavelengths for this algorithm\n");
230  exit(EXIT_FAILURE);
231  }
232  firstCall = 0;
233  }
234 
235  ipb = l1rec->l1file->nbands*ip;
236  flagcld = 0;
237  ftemp = 0; //rhos[ipb+ib667];
238  // first correct for turbid water
239 
240  if (rhos[ipb + ib667] < 0.0) ftemp = 0.0;
241  ftemp2 = cloud_albedo[ip] - ftemp;
242 
243  if (ftemp2 > 0.027) flagcld = 1;
244 
245  // non-water check 1240 is bright relative to 859 and the combination is bright
246  // this may hit glint by accident, need to be checked.
247 
248  if (rhos[ipb + ib1240] / rhos[ipb + ib859] > 0.5 && (rhos[ipb + ib1240] + rhos[ipb + ib2130]) > 0.10) flagcld = 1;
249 
250 
251  // now try to correct for glint
252  // region check was thrown out {IF (region = "OM") cloudthr = 0.04} rjh 11/2/2015
253 
254  ftemp = rhos[ipb + ib645] - rhos[ipb + ib555] + (rhos[ipb + ib555] - rhos[ipb + ib859])*(645.0 - 555.0) / (859.0 - 555.0);
255  ftemp2 = cloud_albedo[ip] + ftemp;
256  if (ftemp2 < cloudthr) flagcld = 0;
257  if (rhos[ipb + ib859] / rhos[ipb + ib1240] > 4.0) flagcld = 0;
258 
259  // scum areas
260 
261  if ((rhos[ipb + ib859] - rhos[ipb + ib469]) > 0.01 && cloud_albedo[ip] < 0.30) flagcld = 0;
262  if ((rhos[ipb + ib859] - rhos[ipb + ib645]) > 0.01 && cloud_albedo[ip] < 0.15) flagcld = 0;
263  if (rhos[ipb + ib1240] < 0.2)
264  ftemp2 = ftemp2 - (rhos[ipb + ib859] - rhos[ipb + ib1240]) * fabs(rhos[ipb + ib859] - rhos[ipb + ib1240]) / cloudthr;
265 
266  ftemp3 = ftemp2;
267  if (ftemp2 < cloudthr * 2) {
268  if ((rhos[ipb + ib555] - rhos[ipb + ib1240]) > (rhos[ipb + ib469] - rhos[ipb + ib1240])) {
269  ftemp3 = ftemp2 - (rhos[ipb + ib555] - rhos[ipb + ib1240]);
270  } else {
271  ftemp3 = ftemp2 - (rhos[ipb + ib469] - rhos[ipb + ib1240]);
272  }
273  }
274 
275  if (ftemp3 < cloudthr) flagcld = 0;
276 
277  return (flagcld);
278 }
279 
280 char get_cldmask(l1str *l1rec, int32_t ip) {
281  //function for cloud mask by pixel
282  switch (l1rec->l1file->sensorID) {
283  case MERIS:
284  case OLCIS3A:
285  case OLCIS3B:
286  return (get_cloudmask_meris(l1rec, ip));
287  break;
288  case MODISA:
289  case MODIST:
290  return (get_cloudmask_modis(l1rec, ip));
291  break;
292  default:
293  printf("HABS cldmsk not supported for this sensor (%s).\n",
294  sensorId2SensorName(l1rec->l1file->sensorID));
295  exit(EXIT_FAILURE);
296  }
297  return (0);
298 }
char get_cldmask(l1str *l1rec, int32_t ip)
Definition: cloud_flag.c:280
#define OLCIS3A
Definition: sensorDefs.h:32
void freeProductInfo(productInfo_t *info)
#define NULL
Definition: decode_rs.h:63
read l1rec
#define MERIS
Definition: sensorDefs.h:22
#define MODIST
Definition: sensorDefs.h:18
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
int bindex_get(int32_t wave)
Definition: windex.c:45
productInfo_t * allocateProductInfo()
l1_input_t * l1_input
Definition: l1_options.c:9
int get_sdps_cld_mask(l1str *l1rec, int32_t ip, char *cld_category)
Definition: cloud_flag.c:5
int findProductInfo(const char *productName, int sensorId, productInfo_t *info)
const char * sensorId2SensorName(int sensorId)
Definition: sensorInfo.c:198
char get_cloudmask_modis(l1str *l1rec, int32_t ip)
Definition: cloud_flag.c:210
#define fabs(a)
Definition: misc.h:93
char get_cloudmask_meris(l1str *l1rec, int32_t ip)
Definition: cloud_flag.c:102
#define HDF4_UTILS_MAX_NAME
Definition: hdf4utils.h:11
#define OLCIS3B
Definition: sensorDefs.h:41
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
#define MODISA
Definition: sensorDefs.h:19
int count
Definition: decode_rs.h:79