4 * DESCRIPTION: Executable program to automate generation of VIIRS Deep Blue
5 * Aerosol products from a directory of L1A files specified in the command line.
7 * USAGE: python mkern_viirs.py -i [input directory] -o [output directory]
9 * Created on July 8, 2019
11 * Author: Samuel Anderson
20 from numpy
import linalg
as la
21 from scipy.stats
import lognorm
22 from scipy.integrate
import quad
23 import matplotlib
as mpl
24 import matplotlib.pyplot
as plt
25 import matplotlib.image
as mpimg
26 from mpl_toolkits.mplot3d
import Axes3D
27 from PIL
import Image
as im
30 from netCDF4
import num2date
32 import mie_kern
as mkrn
33 LOG = logging.getLogger(
'mkern_viirs')
34 from itertools
import permutations
35 from random
import sample
36 from scipy.linalg
import dft
46 description =
'''Generate mie kernal transforms.'''
47 usage =
"usage: python mkern_viirs.py -i [input directory] -o [output directory]"
50 parser = optparse.OptionParser(description=description,usage=usage,version=version)
53 mandatoryGroup = optparse.OptionGroup(parser,
"Mandatory Arguments",
54 "At a minimum these arguments must be specified")
56 mandatoryGroup.add_option(
'-i',
'--in',
60 help=
"The full path of the input directory of L1B files to be processed")
62 mandatoryGroup.add_option(
'-o',
'--out',
66 help=
"The output directory path")
68 parser.add_option_group(mandatoryGroup)
71 optionalGroup = optparse.OptionGroup(parser,
"Extra Options",
72 "These options may be used to customize behavior of this program.")
74 optionalGroup.add_option(
'-k',
'--kern',
78 help=
"The full path of an input kernel file")
80 parser.add_option(
'-v',
'--verbose',
84 help=
'each occurrence increases verbosity 1 level from ERROR: -v=WARNING -vv=INFO -vvv=DEBUG')
86 parser.add_option_group(optionalGroup)
89 (opt, args) = parser.parse_args()
91 levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG]
92 logging.basicConfig(level = levels[opt.verbosity])
98 for m,m_err
in zip(mandatories,mand_errors):
99 if not opt.__dict__[m]:
103 print(
"Incomplete mandatory arguments, aborting...")
107 opt.odir = os.path.expanduser(opt.odir)
108 LOG.info(
'Processing files in %s' % (opt.idir) )
111 dir = alg + datetime.now().isoformat()
112 o_path = os.getcwd() + dir
114 elif os.path.isdir(opt.odir):
116 elif os.path.isdir(os.path.dirname(opt.odir)):
120 print(
"Output path invalid")
124 rgb =
list(permutations(
range(0,256,color_lvl),3))
125 colors = np.array(sample(rgb,120))
126 colors = colors/256.0
132 for re in np.linspace(1.30, 1.60, 10):
134 name = str(int(re*100)) + "_scaled_"
137 mk = mkrn.mie_kern(name, 'oci', m, start, stop, 50)
138 kname = mk.save_all(opt.odir)
140 kname = mk.save_all(opt.odir)
145 mk = mkrn.mie_kern(name,
'oci', m, start, stop, 160)
147 kname = mk.save_all(opt.odir)
151 mk.kernel[:,0] = 4*(mk.wl[0]/mk.wl[:])**4
158 rikern = mk.inverse(rp0, rp1, rp2, rp3)
161 content_oci = os.listdir(opt.idir)
163 for x
in content_oci:
166 inpath = opt.idir +
"/" + x
167 if not os.path.isfile(inpath):
170 fin = tables.open_file(inpath,
'a')
171 refl = np.append(fin.get_node(
"/",
"observation_data/Lt_blue")[8:59], \
172 fin.get_node(
"/",
"observation_data/Lt_red")[1:,:,:],axis=0)
175 toc0 = time.perf_counter()
176 psd = np.tensordot(np.dot(rikern,mk.kernel.T),refl,(((1),(0))))
177 toc1 = time.perf_counter()
178 tpp = (toc1-toc0)/shp[1]/shp[2]
179 print(
"compute inversion", (toc1-toc0),
"sec per oci granule,", tpp,
"sec per pixel", flush=
True)
181 irefl = np.tensordot(mk.kernel,psd,(((1),(0))))
182 toc2 = time.perf_counter()
183 tpp = (toc2-toc1)/shp[1]/shp[2]
184 print(
"reconstruct reflectance", (toc2-toc1),
"sec per oci granule,", tpp,
"sec per pixel", flush=
True)
186 err = la.norm(refl-irefl, ord=2, axis=0)/(la.norm(refl, ord=2, axis=0)+.001)
187 toc3 = time.perf_counter()
188 tpp = (toc3-toc2)/shp[1]/shp[2]
189 print(
"compute rms error", (toc3-toc2),
"sec per oci granule,", tpp,
"sec per pixel", flush=
True)
191 fname = opt.odir +
"/SZ_" + x + mk.name +
".png"
195 fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(50, 30))
196 fig.suptitle(
'Reflectance as a function of wavelength and particle size: ' + \
197 "{: .0e}".format(rp0) +
" " +
"{: .0e}".format(rp1) +
" " + \
198 "{: .0e}".format(rp2) +
" " +
"{: .0e}".format(rp3))
199 axs[0,0].
set(xlabel=
'Wavelength (Nm)', ylabel=
'Reflectance',
200 title=
'Reflectance as a function of Wavelength')
201 axs[0,0].grid(b=
True, which=
'both', axis=
'both')
202 axs[1,0].
set(xlabel=
'Particle Size (Nm)', ylabel=
'Inversion',
203 title=
'Representation as a function of Particle Size')
204 axs[1,0].grid(b=
True, which=
'both', axis=
'both')
205 axs[1,1].
set(xlabel=
'Root sum of squares error ', ylabel=
'Frequency in Granule',
206 title=
'Histogram of errors in reconstructed reflectance')
207 axs[1,1].grid(b=
True, which=
'both', axis=
'both')
208 axs[0,1].
set(title=
'True color image')
210 ro = refl[np.where(mk.wl==670)]
211 go = refl[np.where(mk.wl==550)]
212 bo = refl[np.where(mk.wl==485)]
213 maxo_all = max(np.max(ro), np.max(go), np.max(bo)) + 0.001
218 ga = np.ones_like(ro[0])*gamma
219 rg = np.power(ro[0], ga)
220 gg = np.power(go[0], ga)
221 bg = np.power(bo[0], ga)
224 im_red = im.fromarray(np.uint8(np.clip(rg,0,1.0)*scale))
225 im_green = im.fromarray(np.uint8(np.clip(gg,0,1.0)*scale))
226 im_blue = im.fromarray(np.uint8(np.clip(bg,0,1.0)*scale))
228 im_rgb = im.merge(
"RGB", (im_red, im_green, im_blue))
229 axs[0,1].imshow(im_rgb)
231 for i
in range(0,1700,10):
232 axs[0,0].plot(mk.wl,refl[:,i,column])
233 axs[0,0].plot(mk.wl,irefl[:,i,column], color=colors[
int(7*i)%120])
234 axs[1,0].semilogx(mk.sz,psd[:,i,column], color=colors[
int(7*i)%120])
235 axs[0,1].scatter(column,i,marker=
".",color=colors[
int(7*i)%120])
236 ehist,be = np.histogram(err)
237 axs[1,1].semilogy(be[:-1],ehist)
245 LOG.info(
'Exiting...')
247 if __name__==
'__main__':