4 Created on Fri Nov 20 09:55:41 2015
5 Data might need to be transformed before variance propagation
6 --> see this page for how to do it in python
7 http://scipy.github.io/devdocs/generated/scipy.stats.boxcox.html
8 --> and this page for a discussion about it
9 http://stats.stackexchange.com/questions/18844/when-and-why-to-take-the-log-of-a-distribution-of-numbers
21 """Class to manage uncertainty estimation using an analytical approach.
22 The class takes an optional boolean argument, multiDim, that defaults
23 to False, which signals whether the user wants to follow the contribu
24 tion each band's Lt perturbation to each band's rrs noise estimation.
26 The order of implementation would be to
27 * instantiate a child object specific to a sensor
30 - object.GetBaseline()
31 * process pertubed data files to generate variance
32 - object.UpdVarFromPertDat --> Lt_band by Lt_band
33 - note that obj.UpdateAllVars -->
34 * plot to see all is well
35 * save computed rrs uncertainties back into the baseline file
37 I might write a full sequence method, but for now it's manual
41 def __init__(self,silFile,noisyDir,multiDimVar = False):
60 for band
in self.bands:
66 '''Reads Baseline file
68 Flags: l2bin default flags, namely ATMFAIL(1), LAND(2), HIGLINT(8),
69 HILT(16), HISATZEN(32), STRAYLIGHT(256), CLDICE(512), COCCOLITH(1024),
70 HISOLZEN(4096), LOWLW(16384), CHLFAIL(32768), NAVWARN(65536),
71 MAXAERITER(524288), CHLWARN(2097152), ATMWARN(4194304),
72 NAVFAIL(33554432), FILTER(67108864)
74 flagBits = 1 + 2 + 8 + 16 + 32 + 256 + 512 + 1024 + 4096 + 16384 + \
75 32768 + 65536 + 524288 + 2097152 + 4194304 + 33554432 + 67108864
76 with nc.Dataset(self.
silFile,
'r')
as dsSil:
77 geoGr = dsSil.groups[
'geophysical_data']
78 geoVar = geoGr.variables
79 l2flags = geoVar[
'l2_flags'][:]
80 flagMaskArr = (l2flags & flagBits > 0)
81 for band
in self.bands:
85 self.
attrDict[band] = {
'long_name' :
'Uncertainty in ' +
87 '_FillValue': variable._FillValue,
88 'units': variable.units,
89 'scale_factor':variable.scale_factor,
90 'add_offset':variable.add_offset}
91 self.
dimsDict[band] = variable.dimensions
97 for band_rrs
in self.bands:
100 for bandLt
in self.bands:
101 band_lt =
'Lt_' + bandLt
107 fBaseName = self.
silFile.split(
'/')[-1]
108 for i,ltBand
in enumerate(self.bands):
109 noisyFileName = self.
noisyDir +
'/' + fBaseName + noisySfx +
str(i).zfill(4) +
'.L2'
110 ltKey =
'Lt_' + ltBand
111 print(
"searching for %s" % noisyFileName, flush=
True)
112 with nc.Dataset(noisyFileName)
as nds:
114 print(
"Loading and reading %s" % noisyFileName)
115 ngv = nds.groups[
'geophysical_data'].variables
117 print(
"Processing perturbation of Lt_%s" % ltBand)
121 ltSigma = self.
_ApplyLims(ltSigma,self.sigLimDict[ltBand])
123 for band
in self.bands:
126 sigTemp = ltSigma * (rrsPert - self.
rrsSilDict[band]) / dLt
127 varTemp = sigTemp **2
142 with nc.Dataset(self.
silFile,
'r+')
as dsSil:
143 geoGr = dsSil.groups[
'geophysical_data']
144 geoVar = geoGr.variables
145 for band
in self.bands:
147 if uncProdName
not in geoVar:
150 variable = geoGr.createVariable(uncProdName,dType,dIms)
151 variable.setncatts(self.
attrDict[band])
153 variable=geoVar[uncProdName]
155 variable[:] = self.
rrsUncDict[band][
'Aggregate']
160 def _ApplyLims(sigs,lims):
161 """This function applies thresholds to sigmas from pre-computed
162 upper and lower bounds
165 finiteSigsIdx = np.isfinite(sigs)
166 sigsSub = sigs[finiteSigsIdx]
167 sigsSub[np.where(sigsSub<lims[0])] = lims[0]
168 sigsSub[np.where(sigsSub>lims[1])] = lims[1]
169 sigs[finiteSigsIdx] = sigsSub
173 def _ApplyPolyFit(cf,lt,deg):
174 """This function applies a polynomial fit to the data in lt.
175 cf: coefficients of the polynomial
176 deg: degree of the polynomial
180 y += cf[i] * (lt** (deg - i))
186 """Subclass to AnalyticNoise, specific to SeaWiFS"""
191 self.
bands = [
'412',
'443',
'490',
'510',
'555',
'670',
'765',
'865']
192 self.
coeffsDict={
'412':np.array([-8.28726301e-11,3.85425664e-07,-9.10776926e-04,
193 1.65881862e+00,4.54351582e-01]),
194 '443':np.array([-1.21871258e-10,5.21579320e-07,-1.14574109e-03,
195 1.96509056e+00,4.18921861e-01]),
196 '490':np.array([-2.99068165e-10,1.05225457e-06,-1.90591166e-03,
197 2.66343986e+00,6.67187489e-01]),
198 '510':np.array([-5.68939986e-10,1.67950509e-06,-2.56915149e-03,
199 3.05832773e+00,9.34468454e-01]),
200 '555':np.array([-1.31635902e-09,3.09617393e-06,-3.73473556e-03,
201 3.52394751e+00,3.54105899e-01]),
202 '670':np.array([-8.65458303e-09,1.18857306e-05,-8.37771886e-03,
203 4.64496430e+00,4.14633422e-02]),
204 '765':np.array([-4.96827099e-08,4.50239057e-05,-2.10425126e-02,
205 7.75862055e+00,5.18893137e-02]),
206 '865':np.array([-1.30487418e-07,9.35407901e-05,-3.40988182e-02,
207 9.43414239e+00,7.84956550e-01])
209 self.
sigLimDict={
'412':[0.0008826466289493833,0.058990630111850566],
210 '443':[0.00078708204284562292,0.050110810767361902],
211 '490':[0.00073633772526737848,0.036883976493020949],
212 '510':[0.00074975219339103519,0.031987200608546547],
213 '555':[0.00080870577569697015,0.055925717740595647],
214 '670':[0.0010890690698014294,0.04336828983700642],
215 '765':[0.00093810092188024833,0.026092951412422679],
216 '865':[0.0010906675048335769,0.02122474906498301]
218 self.
colDict = {
'412':
'#001166',
'443':
'#004488',
'490':
'#116688',
219 '510':
'#228844',
'555':
'#667722',
'670':
'#aa2211',
220 '765':
'#770500',
'865':
'#440000'}
221 super(SeaWiFSNoise,self).
__init__(*args,**nargs)
225 """ Expects baseline filepath/name and where pertubed files
229 parser = argparse.ArgumentParser(prog=
"AnalyticNoise")
230 parser.add_argument(
'--version', action=
'version', version=
'%(prog)s ' + __version__)
231 parser.add_argument(
'baselinefile', type=str, help=
' input bseline file',metavar=
"BASELINEFILE")
232 parser.add_argument(
'noiseDir',type=str, help=
'directory where pertubed files are stored',metavar=
"NOISEDIR")
233 args = parser.parse_args()
234 baseLineFile = args.baselinefile
235 noisyDataDir = args.noiseDir
237 noisySfx =
'_wiggledBand_'
238 swf =
SeaWiFSNoise(baseLineFile,noisyDataDir,multiDimVar=
True)
240 swf.BuildUncs(noisySfx,verbose=
True)
243 if __name__ ==
"__main__":