OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
CldMask.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * NAME: CldMask.cpp
4  *
5  * DESCRIPTION: Object class that provides data structures and processes that
6  * compute cloud masks for a given DDProcess object class.
7  *
8  * Created on: April 3, 2021
9  * Author: Sam Anderson, DT
10  *
11  * Modified:
12  *
13  *******************************************************************************/
14 
15 #include <math.h>
16 #include <DDAlgorithm.h>
17 #include <CldMask.h>
18 
19 using namespace std;
20 
21 /**************************************************************************
22  * NAME: CldMaskLand()
23  *
24  * DESCRIPTION: Class Constructor
25  *
26  *************************************************************************/
27 
29 }
30 
31 /**************************************************************************
32  * NAME: CldMaskLand()
33  *
34  * DESCRIPTION: Class Constructor
35  *
36  *************************************************************************/
37 
39  p_ = process;
40  mask_cirrus_ = 0;
41  snowmask_ = 0;
42 }
43 
44 /**************************************************************************
45  * NAME: ~CldMaskLand()
46  *
47  * DESCRIPTION: Class Destructor
48  *
49  *************************************************************************/
50 
52 }
53 
54 /**************************************************************************
55  * NAME: initialize()
56  *
57  * DESCRIPTION: Virtual function initializes data and object classes for
58  * cloud mask operations.
59  *
60  *************************************************************************/
61 
63  return DT_SUCCESS;
64 }
65 
66 /**************************************************************************
67  * NAME: compute()
68  *
69  * DESCRIPTION: Virtual function computes cloud mask over land using spatial
70  * variability of 0.47 (>0.01) and 1.38 um (>0.007) reflectance as well
71  * as absolute value of 1.38 um > 0.1
72  *
73  * INPUT PARAMETERS:
74  *
75  * ISWATH Number of pixels at 1 km resolution along scan
76  * ILINE Number of pixels at 1 km resolution against scan
77  * Refl_3 Reflectance at 0.47 um
78  * Refl_26 Reflectance at 1.38 um
79  *
80  * OUTPUT PARAMETERS:
81  *
82  * CLDMSK_1KM Cloud mask at 1 km resolution
83  * CldMsk_500 Cloud mask at 500m resolution
84  * CldMsk_250 Cloud mask at 250m resolution
85  *
86  *************************************************************************/
87 
88 int CldMaskLand::compute( unsigned char& mask )
89 {
90  int status = DT_SUCCESS;
91 
92  mask = 1;
93 
94  if (p_->rfl_[(size_t)rhot_band::W410] < filltest) {
95  mask = ubytefill;
96  return status;
97  }
98  float m03_avg = 0;
99  float m03_stddev = 0;
100  float m09_avg = 0;
101  float m09_stddev = 0;
102 
103 // Gather 3x3 grid
104  float rfl[NUM_RFL_BANDS][3][3];
105  memset(rfl,0,sizeof(rfl));
106  for (size_t iw=0; iw<NUM_RFL_BANDS; iw++) {
107  for (size_t il=0; il<=2; il++) {
108  for (size_t ip=0; ip<=2; ip++) {
109  rfl[iw][il][ip] = p_->rfla_[iw][il][ip];
110  }
111  }
112  }
113 
114 // M03 W488
115  size_t cnt = 0;
116  for (size_t il=0; il<=2; il++) {
117  for (size_t ip=0; ip<=2; ip++) {
118  if (rfl[(size_t)rhot_band::W490][il][ip] > filltest) {
119  m03_avg += rfl[(size_t)rhot_band::W490][il][ip];
120  cnt++;
121  }
122  }
123  }
124  if (cnt >= 2) {
125  m03_avg /= cnt;
126  cnt = 0;
127  for (size_t il=0; il<=2; il++) {
128  for (size_t ip=0; ip<=2; ip++) {
129  if (rfl[(size_t)rhot_band::W490][il][ip] > filltest) {
130  m03_stddev += pow((rfl[(size_t)rhot_band::W490][il][ip]-m03_avg),2);
131  cnt++;
132  }
133  }
134  }
135  m03_stddev = sqrt(m03_stddev/(cnt-1));
136  } else {
137  m03_stddev = floatfill;
138  }
139 // M09 W1380
140  cnt = 0;
141  for (size_t il=0; il<=2; il++) {
142  for (size_t ip=0; ip<=2; ip++) {
143  if (rfl[(size_t)rhot_band::W1380][il][ip] > filltest) {
144  m09_avg += rfl[(size_t)rhot_band::W1380][il][ip];
145  cnt++;
146  }
147  }
148  }
149  if (cnt >= 2) {
150  m09_avg /= cnt;
151  cnt = 0;
152  for (size_t il=0; il<=2; il++) {
153  for (size_t ip=0; ip<=2; ip++) {
154  if (rfl[(size_t)rhot_band::W1380][il][ip] > filltest) {
155  m09_stddev += pow((rfl[(size_t)rhot_band::W1380][il][ip]-m09_avg),2);
156  cnt++;
157  }
158  }
159  }
160  m09_stddev = sqrt(m09_stddev/(cnt-1));
161  } else {
162  m09_stddev = floatfill;
163  }
164 
165  if ((m03_stddev > filltest && (m03_stddev > THRHLD470_STD)) ||
166  (m09_stddev > filltest && (m09_stddev > THRHLD1380_STD))) {
167  mask = 0;
168  } else {
169  mask = 1;
170  }
171 // -- perform the check on the 1.38 um band (M09)
172  if (rfl[(size_t)rhot_band::W1380][1][1] > THRHLD1380) {
173  mask = 0;
174  }
175 // -- perform check on 488 nm band (M03)
176  if (rfl[(size_t)rhot_band::W490][1][1] > THRHLD470) {
177  mask = 0;
178  }
179 
180  compute_snowmask();
181 
182  return status;
183 }
184 
185 
186 
187 /**************************************************************************
188  * NAME: CldMaskOcean()
189  *
190  * DESCRIPTION: Class Constructor
191  *
192  *************************************************************************/
193 
195 }
196 
197 /**************************************************************************
198  * NAME: CldMaskOcean()
199  *
200  * DESCRIPTION: Class Constructor
201  *
202  *************************************************************************/
203 
205  p_ = proc;
206 }
207 
208 /**************************************************************************
209  * NAME: ~CldMaskOcean()
210  *
211  * DESCRIPTION: Class Destructor
212  *
213  *************************************************************************/
214 
216 }
217 
218 /**************************************************************************
219  * NAME: initialize()
220  *
221  * DESCRIPTION: Virtual function initializes data and object classes for
222  * cloud mask operations.
223  *
224  *************************************************************************/
225 
227  return DT_SUCCESS;
228 }
229 
230 /**************************************************************************
231  * NAME: compute()
232  *
233  * DESCRIPTION: Compute cloud mask. This is a port of the Deep Blue cloud
234  * mask with modifications for compatibility with Dark Target reflectance
235  * units and inversion of the mask bit (here 0 = cloud, 1 = no cloud)
236  *
237  *************************************************************************/
238 
239 int CldMaskOcean::compute( unsigned char& mask )
240 {
241  int status = DT_SUCCESS;
242 
243  if (p_->rfl_[(size_t)rhot_band::W410] < filltest) {
244  mask = ubytefill;
245  return status;
246  }
247  float lat = p_->lat_;
248  float solz = p_->solz_;
249  float m01_avg = 0;
250  float m01_stddev = 0;
251  float m08_avg = 0;
252  float m08_stddev = 0;
253  mask = 1;
254 
255 // Convert to units of normalize radiance
256  float rfl[NUM_RFL_BANDS][3][3];
257  memset(rfl,0,sizeof(rfl));
258  double cossza = cos(solz*DEG2RAD);
259  for (size_t iw=0; iw<NUM_RFL_BANDS; iw++) {
260  for (size_t il=0; il<=2; il++) {
261  for (size_t ip=0; ip<=2; ip++) {
262  if (p_->rfla_[iw][il][ip] < filltest) {
263  rfl[iw][il][ip] = floatfill;
264  } else {
265  rfl[iw][il][ip] = p_->rfla_[iw][il][ip]*cossza/M_PI;
266  }
267  }
268  }
269  }
270 
271 // M01 W412
272  size_t cnt = 0;
273  for (size_t il=0; il<=2; il++) {
274  for (size_t ip=0; ip<=2; ip++) {
275  if (rfl[(size_t)rhot_band::W410][il][ip] > filltest) {
276  m01_avg += rfl[(size_t)rhot_band::W410][il][ip];
277  cnt++;
278  }
279  }
280  }
281  if (cnt >= 2) {
282  m01_avg /= cnt;
283  cnt = 0;
284  for (size_t il=0; il<=2; il++) {
285  for (size_t ip=0; ip<=2; ip++) {
286  if (rfl[(size_t)rhot_band::W410][il][ip] > filltest) {
287  m01_stddev += pow((rfl[(size_t)rhot_band::W410][il][ip]-m01_avg),2);
288  cnt++;
289  }
290  }
291  }
292  m01_stddev = sqrt(m01_stddev/(cnt-1));
293  } else {
294  m01_stddev = floatfill;
295  }
296 // M08 W1240
297  cnt = 0;
298  for (size_t il=0; il<=2; il++) {
299  for (size_t ip=0; ip<=2; ip++) {
300  if (rfl[(size_t)rhot_band::W1240][il][ip] > filltest) {
301  m08_avg += rfl[(size_t)rhot_band::W1240][il][ip];
302  cnt++;
303  }
304  }
305  }
306  if (cnt >= 2) {
307  m08_avg /= cnt;
308  cnt = 0;
309  for (size_t il=0; il<=2; il++) {
310  for (size_t ip=0; ip<=2; ip++) {
311  if (rfl[(size_t)rhot_band::W1240][il][ip] > filltest) {
312  m08_stddev += pow((rfl[(size_t)rhot_band::W1240][il][ip]-m08_avg),2);
313  cnt++;
314  }
315  }
316  }
317  m08_stddev = sqrt(m08_stddev/(cnt-1));
318  } else {
319  m08_stddev = floatfill;
320  }
321  float cosza = cos(solz*DEG2RAD);
322  if (lat > 65.0) {
323  if ((m01_stddev > filltest &&
324  (m01_stddev > M01_STDV_THOLD*cosza)) ||
325  (m08_stddev > filltest &&
326  (m08_stddev > M08_HILAT_STDV_THOLD*cosza))) {
327  mask = 0;
328  } else {
329  mask = 1;
330  }
331  } else {
332  if ((m01_stddev > filltest &&
333  m01_stddev > M01_STDV_THOLD*cosza) ||
334  (m08_stddev > filltest &&
335  m08_stddev > M08_STDV_THOLD*cosza)) {
336  mask = 0;
337  } else {
338  mask = 1;
339  }
340  }
341 // -- perform the check on the 1.38 um band (M09)
342  if (rfl[(size_t)rhot_band::W1380][1][1] > M09_THOLD*cosza) {
343  mask = 0;
344  }
345 // -- perform check on 488 nm band (M03)
346  if (rfl[(size_t)rhot_band::W490][1][1] > M03_THOLD*cosza) {
347  mask = 0;
348  }
349 
350  return status;
351 }
352 
353 
int status
Definition: l1_czcs_hdf.c:32
float rfl[NOWL]
Definition: DbAlgOcean.cpp:41
int compute(unsigned char &mask)
Definition: CldMask.cpp:239
~CldMaskLand()
Definition: CldMask.cpp:51
float * lat
#define M_PI
Definition: pml_iop.h:15
a context in which it is NOT documented to do so subscript which cannot be easily calculated when extracting TONS attitude data from the Terra L0 files Corrected several defects in extraction of entrained ephemeris and and as HDF file for both the L1A and Geolocation enabling retrieval of South Polar DEM data Resolved Bug by changing to opent the geolocation file only after a successful read of the L1A and also by checking for fatal errors from not restoring C5 and to report how many of those high resolution values were water in the new WaterPresent SDS Added valid_range attribute to Land SeaMask Changed to bilinearly interpolate the geoid_height to remove artifacts at one degree lines Made corrections to const qualification of pointers allowed by new version of M API library Removed casts that are no longer for same not the geoid Corrected off by one error in calculation of high resolution offsets Corrected parsing of maneuver list configuration parameter Corrected to set Height SDS to fill values when geolocation when for elevation and land water mask
Definition: HISTORY.txt:114
int initialize()
Definition: CldMask.cpp:62
int compute(unsigned char &mask)
Definition: CldMask.cpp:88
int initialize()
Definition: CldMask.cpp:226
#define DEG2RAD
Definition: GEO_geo.h:174