Total Complexity | 70 |
Total Lines | 900 |
Duplicated Lines | 95.67 % |
Coverage | 73.02% |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like sciapy.level2.density_pp often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | # -*- coding: utf-8 -*- |
||
2 | # vim:fileencoding=utf-8 |
||
3 | # |
||
4 | # Copyright (c) 2018 Stefan Bender |
||
5 | # |
||
6 | # This file is part of sciapy. |
||
7 | # sciapy is free software: you can redistribute it or modify it |
||
8 | # under the terms of the GNU General Public License as published by |
||
9 | # the Free Software Foundation, version 2. |
||
10 | # See accompanying LICENSE file or http://www.gnu.org/licenses/gpl-2.0.html. |
||
11 | 1 | """SCIAMACHY level 2 post-processed number densities interface |
|
12 | |||
13 | Interface classes for the level 2 post-processed retrieval results. |
||
14 | """ |
||
15 | |||
16 | 1 | from __future__ import absolute_import, division, print_function |
|
17 | |||
18 | 1 | import datetime as dt |
|
19 | |||
20 | 1 | import numpy as np |
|
21 | 1 | try: |
|
22 | 1 | from netCDF4 import Dataset as netcdf_file |
|
23 | 1 | fmtargs = {"format": "NETCDF4"} |
|
24 | except ImportError: |
||
25 | try: |
||
26 | from scipy.io.netcdf import netcdf_file |
||
27 | fmtargs = {"version": 1} |
||
28 | except ImportError: |
||
29 | from pupynere import netcdf_file |
||
30 | fmtargs = {"version": 1} |
||
31 | |||
32 | 1 | from .density import scia_densities |
|
33 | |||
34 | 1 | __all__ = ["scia_densities_pp", "scia_density_day"] |
|
35 | |||
36 | |||
37 | 1 | View Code Duplication | class scia_densities_pp(scia_densities): |
|
|||
38 | """Post-processed SCIAMACHY number densities |
||
39 | |||
40 | Extends `scia_densities` with additional post-processing |
||
41 | attributes such as (MSIS) temperature and density, local |
||
42 | solar time, solar zenith angle, and geomagnetic latitudes |
||
43 | and longitudes. |
||
44 | |||
45 | This class only supports writing ascii files but reading to |
||
46 | and writing from netcdf. |
||
47 | |||
48 | Attributes |
||
49 | ---------- |
||
50 | temperature |
||
51 | NRLMSISE-00 temperatures |
||
52 | noem_no |
||
53 | NOEM NO nuimber densities |
||
54 | vmr |
||
55 | NO vmr using the NRLMSISE-00 total air number densities |
||
56 | lst |
||
57 | Apparent local solar times |
||
58 | mst |
||
59 | Mean local solar times |
||
60 | sza |
||
61 | Solar zenith angles |
||
62 | utchour |
||
63 | UTC hours into measurement day |
||
64 | utcdays |
||
65 | Number of days since reference date |
||
66 | gmlats |
||
67 | IGRF-12 geomagentic latitudes |
||
68 | gmlons |
||
69 | IGRF-12 geomagentic longitudes |
||
70 | aacgmgmlats |
||
71 | AACGM geomagentic latitudes |
||
72 | aacgmgmlons |
||
73 | AACGM geomagentic longitudes |
||
74 | |||
75 | Methods |
||
76 | ------- |
||
77 | write_to_textfile |
||
78 | write_to_netcdf |
||
79 | read_from_netcdf |
||
80 | to_xarray |
||
81 | """ |
||
82 | 1 | def __init__(self, ref_date="2000-01-01", |
|
83 | ver=None, data_ver=None): |
||
84 | 1 | self.filename = None |
|
85 | 1 | self.temperature = None |
|
86 | 1 | self.noem_no = None |
|
87 | 1 | self.vmr = None |
|
88 | 1 | self.lst = None |
|
89 | 1 | self.mst = None |
|
90 | 1 | self.sza = None |
|
91 | 1 | self.utchour = None |
|
92 | 1 | self.utcdays = None |
|
93 | 1 | self.gmlats = None |
|
94 | 1 | self.gmlons = None |
|
95 | 1 | self.aacgmgmlats = None |
|
96 | 1 | self.aacgmgmlons = None |
|
97 | 1 | super(scia_densities_pp, self).__init__( |
|
98 | ref_date=ref_date, ver=ver, data_ver=data_ver) |
||
99 | |||
100 | 1 | def write_to_textfile(self, filename): |
|
101 | """Write the variables to ascii table files |
||
102 | |||
103 | Parameters |
||
104 | ---------- |
||
105 | filename: str or file object or io.TextIOBase.buffer |
||
106 | The filename or stream to write the data to. For writing to |
||
107 | stdout in python 3, pass `sys.stdout.buffer`. |
||
108 | """ |
||
109 | if hasattr(filename, 'seek'): |
||
110 | f = filename |
||
111 | else: |
||
112 | f = open(filename, 'w') |
||
113 | |||
114 | header = "%5s %13s %12s %13s %14s %12s %14s %12s %12s %12s %12s %12s" % ("GP_ID", |
||
115 | "Max_Hoehe[km]", "Hoehe[km]", "Min_Hoehe[km]", |
||
116 | "Max_Breite[°]", "Breite[°]", "Min_Breite[°]", |
||
117 | "Laenge[°]", |
||
118 | "Dichte[cm^-3]", "Fehler Mess[cm^-3]", |
||
119 | "Fehler tot[cm^-3]", "Gesamtdichte[cm^-3]") |
||
120 | if self.apriori is not None: |
||
121 | header = header + " %12s" % ("apriori[cm^-3]",) |
||
122 | if self.temperature is not None: |
||
123 | header = header + " %12s" % ("T[K]",) |
||
124 | if self.noem_no is not None: |
||
125 | header = header + " %12s" % ("NOEM_NO[cm^-3]",) |
||
126 | if self.akdiag is not None: |
||
127 | header = header + " %12s" % ("AKdiag",) |
||
128 | if self.lst is not None: |
||
129 | header = header + " %12s" % ("LST",) |
||
130 | if self.mst is not None: |
||
131 | header = header + " %12s" % ("MST",) |
||
132 | if self.sza is not None: |
||
133 | header = header + " %12s" % ("SZA",) |
||
134 | if self.utchour is not None: |
||
135 | header = header + " %12s" % ("Hour",) |
||
136 | if self.utcdays is not None: |
||
137 | header = header + " %12s" % ("Days",) |
||
138 | if self.gmlats is not None: |
||
139 | header = header + " %12s" % ("GeomagLat",) |
||
140 | if self.gmlons is not None: |
||
141 | header = header + " %12s" % ("GeomagLon",) |
||
142 | if self.aacgmgmlats is not None: |
||
143 | header = header + " %12s" % ("AACGMGeomagLat",) |
||
144 | if self.aacgmgmlons is not None: |
||
145 | header = header + " %12s" % ("AACGMGeomagLon",) |
||
146 | print(header, file=f) |
||
147 | |||
148 | oformat = "%5i %+1.5E %+1.5E %+1.5E %+1.5E %+1.5E %+1.5E %+1.5E %+1.5E %+1.5E %+1.5E %+1.5E" |
||
149 | oformata = " %+1.5E" |
||
150 | |||
151 | for i, a in enumerate(self.alts): |
||
152 | for j, b in enumerate(self.lats): |
||
153 | print(oformat % (i * self.nlat + j, |
||
154 | self.alts_max[i], a, self.alts_min[i], |
||
155 | self.lats_max[j], b, self.lats_min[j], self.lons[j], |
||
156 | self.densities[j, i], self.dens_err_meas[j, i], |
||
157 | self.dens_err_tot[j, i], self.dens_tot[j, i]), |
||
158 | end="", file=f) |
||
159 | if self.apriori is not None: |
||
160 | print(" " + oformata % self.apriori[j, i], end="", file=f) |
||
161 | if self.temperature is not None: |
||
162 | print(" " + oformata % self.temperature[j, i], end="", file=f) |
||
163 | if self.noem_no is not None: |
||
164 | print(" " + oformata % self.noem_no[j, i], end="", file=f) |
||
165 | if self.akdiag is not None: |
||
166 | print(" " + oformata % self.akdiag[j, i], end="", file=f) |
||
167 | if self.lst is not None: |
||
168 | print(" " + oformata % self.lst[j], end="", file=f) |
||
169 | if self.mst is not None: |
||
170 | print(" " + oformata % self.mst[j], end="", file=f) |
||
171 | if self.sza is not None: |
||
172 | print(" " + oformata % self.sza[j], end="", file=f) |
||
173 | if self.utchour is not None: |
||
174 | print(" " + oformata % self.utchour[j], end="", file=f) |
||
175 | if self.utcdays is not None: |
||
176 | print(" " + oformata % self.utcdays[j], end="", file=f) |
||
177 | if self.gmlats is not None: |
||
178 | print(" " + oformata % self.gmlats[j], end="", file=f) |
||
179 | if self.gmlons is not None: |
||
180 | print(" " + oformata % self.gmlons[j], end="", file=f) |
||
181 | if self.aacgmgmlats is not None: |
||
182 | print(" " + oformata % self.aacgmgmlats[j], end="", file=f) |
||
183 | if self.aacgmgmlons is not None: |
||
184 | print(" " + oformata % self.aacgmgmlons[j], end="", file=f) |
||
185 | print("", file=f) |
||
186 | |||
187 | 1 | def write_to_netcdf(self, filename, close=True): |
|
188 | """Write variables to netcdf files |
||
189 | |||
190 | This function has no stream, i.e. file object, support. |
||
191 | Uses single precision floats (32 bit) to save space. |
||
192 | |||
193 | Parameters |
||
194 | ---------- |
||
195 | filename: str |
||
196 | The name of the file to write the data to. |
||
197 | """ |
||
198 | # write the base variables first and keep the file open for appending |
||
199 | 1 | ncf = scia_densities.write_to_netcdf(self, filename, close=False) |
|
200 | |||
201 | 1 | if self.temperature is not None: |
|
202 | 1 | ftemp = ncf.createVariable('temperature', |
|
203 | np.dtype('float32').char, ('time', 'latitude', 'altitude')) |
||
204 | 1 | ftemp.units = 'K' |
|
205 | 1 | ftemp.long_name = 'temperature' |
|
206 | 1 | ftemp.model = 'NRLMSIS-00' |
|
207 | 1 | ftemp[0, :] = self.temperature |
|
208 | |||
209 | 1 | if self.noem_no is not None: |
|
210 | 1 | fnoem_no = ncf.createVariable('NOEM_density', |
|
211 | np.dtype('float32').char, ('time', 'latitude', 'altitude')) |
||
212 | 1 | fnoem_no.units = 'cm^{-3}' |
|
213 | 1 | fnoem_no.long_name = 'NOEM NO number density' |
|
214 | 1 | fnoem_no[0, :] = self.noem_no |
|
215 | |||
216 | 1 | if self.vmr is not None: |
|
217 | 1 | fvmr = ncf.createVariable('VMR', |
|
218 | np.dtype('float32').char, ('time', 'latitude', 'altitude')) |
||
219 | 1 | fvmr.units = 'ppb' |
|
220 | 1 | fvmr.long_name = 'volume mixing ratio' |
|
221 | 1 | fvmr[0, :] = self.vmr |
|
222 | |||
223 | 1 | if self.lst is not None: |
|
224 | 1 | flst = ncf.createVariable('app_lst', |
|
225 | np.dtype('float32').char, ('time', 'latitude',)) |
||
226 | 1 | flst.units = 'hours' |
|
227 | 1 | flst.long_name = 'apparent local solar time' |
|
228 | 1 | flst[0, :] = self.lst |
|
229 | |||
230 | 1 | if self.mst is not None: |
|
231 | 1 | fmst = ncf.createVariable('mean_lst', |
|
232 | np.dtype('float32').char, ('time', 'latitude',)) |
||
233 | 1 | fmst.units = 'hours' |
|
234 | 1 | fmst.long_name = 'mean local solar time' |
|
235 | 1 | fmst[0, :] = self.mst |
|
236 | |||
237 | 1 | if self.sza is not None: |
|
238 | 1 | fsza = ncf.createVariable('mean_sza', |
|
239 | np.dtype('float32').char, ('time', 'latitude',)) |
||
240 | 1 | fsza.units = 'degrees' |
|
241 | 1 | fsza.long_name = 'mean solar zenith angle' |
|
242 | 1 | fsza[0, :] = self.sza |
|
243 | |||
244 | 1 | if self.utchour is not None: |
|
245 | 1 | futc = ncf.createVariable('utc_hour', |
|
246 | np.dtype('float32').char, ('time', 'latitude',)) |
||
247 | 1 | futc.units = 'hours' |
|
248 | 1 | futc.long_name = 'measurement utc time' |
|
249 | 1 | futc[0, :] = self.utchour |
|
250 | |||
251 | 1 | if self.utcdays is not None: |
|
252 | 1 | futcd = ncf.createVariable('utc_days', |
|
253 | np.dtype('float32').char, ('time', 'latitude',)) |
||
254 | 1 | futcd.long_name = 'measurement day' |
|
255 | 1 | futcd.units = 'days since {0}'.format(self.date0.isoformat(sep=' ')) |
|
256 | 1 | futcd[0, :] = self.utcdays |
|
257 | |||
258 | 1 | if self.gmlats is not None: |
|
259 | 1 | fgmlats = ncf.createVariable('gm_lats', |
|
260 | np.dtype('float32').char, ('time', 'latitude',)) |
||
261 | 1 | fgmlats.long_name = 'geomagnetic_latitude' |
|
262 | 1 | fgmlats.model = 'IGRF' |
|
263 | 1 | fgmlats.units = 'degrees_north' |
|
264 | 1 | fgmlats[0, :] = self.gmlats |
|
265 | |||
266 | 1 | if self.gmlons is not None: |
|
267 | 1 | fgmlons = ncf.createVariable('gm_lons', |
|
268 | np.dtype('float32').char, ('time', 'latitude',)) |
||
269 | 1 | fgmlons.long_name = 'geomagnetic_longitude' |
|
270 | 1 | fgmlons.model = 'IGRF' |
|
271 | 1 | fgmlons.units = 'degrees_east' |
|
272 | 1 | fgmlons[0, :] = self.gmlons |
|
273 | |||
274 | 1 | if self.aacgmgmlats is not None: |
|
275 | 1 | faacgmgmlats = ncf.createVariable('aacgm_gm_lats', |
|
276 | np.dtype('float32').char, ('time', 'latitude',)) |
||
277 | 1 | faacgmgmlats.long_name = 'geomagnetic_latitude' |
|
278 | 1 | faacgmgmlats.model = 'AACGM' |
|
279 | 1 | faacgmgmlats.units = 'degrees_north' |
|
280 | 1 | faacgmgmlats[0, :] = self.aacgmgmlats |
|
281 | |||
282 | 1 | if self.aacgmgmlons is not None: |
|
283 | 1 | faacgmgmlons = ncf.createVariable('aacgm_gm_lons', |
|
284 | np.dtype('float32').char, ('time', 'latitude',)) |
||
285 | 1 | faacgmgmlons.long_name = 'geomagnetic_longitude' |
|
286 | 1 | faacgmgmlons.model = 'AACGM' |
|
287 | 1 | faacgmgmlons.units = 'degrees_east' |
|
288 | 1 | faacgmgmlons[0, :] = self.aacgmgmlons |
|
289 | |||
290 | 1 | if close: |
|
291 | 1 | ncf.close() |
|
292 | else: |
||
293 | return ncf |
||
294 | |||
295 | 1 | def read_from_netcdf(self, filename, close=True): |
|
296 | """Read post-processed level 2 orbit files |
||
297 | |||
298 | Parameters |
||
299 | ---------- |
||
300 | filename: str |
||
301 | The name of the netcdf file. |
||
302 | """ |
||
303 | # read the base variables first and keep the file open for reading |
||
304 | 1 | ncf = scia_densities.read_from_netcdf(self, filename, close=False) |
|
305 | |||
306 | # additional data... |
||
307 | # MSIS temperature |
||
308 | try: |
||
309 | self.temperature = ncf.variables['temperature'][:] |
||
310 | except: |
||
311 | pass |
||
312 | # NOEM density |
||
313 | try: |
||
314 | self.noem_no = ncf.variables['NOEM_density'][:] |
||
315 | except: |
||
316 | pass |
||
317 | # calculated vmr |
||
318 | try: |
||
319 | self.vmr = ncf.variables['VMR'][:] |
||
320 | except: |
||
321 | pass |
||
322 | # apparent local solar time |
||
323 | try: |
||
324 | self.lst = ncf.variables['app_lst'][:] |
||
325 | except: |
||
326 | pass |
||
327 | # mean local solar time |
||
328 | try: |
||
329 | self.mst = ncf.variables['mean_lst'][:] |
||
330 | except: |
||
331 | pass |
||
332 | # mean solar zenith angle |
||
333 | try: |
||
334 | self.sza = ncf.variables['mean_sza'][:] |
||
335 | except: |
||
336 | pass |
||
337 | # utc hours |
||
338 | try: |
||
339 | self.utchour = ncf.variables['utc_hour'][:] |
||
340 | except: |
||
341 | pass |
||
342 | # utc days |
||
343 | try: |
||
344 | self.utcdays = ncf.variables['utc_days'][:] |
||
345 | except: |
||
346 | pass |
||
347 | |||
348 | if close: |
||
349 | ncf.close() |
||
350 | else: |
||
351 | return ncf |
||
352 | |||
353 | 1 | def to_xarray(self, dateo, orbit): |
|
354 | """Convert the data to :class:`xarray.Dataset` |
||
355 | |||
356 | This is a very simple approach, it dumps the data to a temporary |
||
357 | netcdf file and reads that using :func:`xarray.open_dataset()`. |
||
358 | |||
359 | Parameters |
||
360 | ---------- |
||
361 | dateo: float |
||
362 | The days since the reference date at the equator |
||
363 | crossing of the orbit. Used to set the `time` |
||
364 | dimension of the dataset. |
||
365 | orbit: int |
||
366 | The SCIAMACHY/Envisat orbit number of the retrieved data. |
||
367 | |||
368 | Returns |
||
369 | ------- |
||
370 | dataset: xarray.Dataset |
||
371 | """ |
||
372 | 1 | import tempfile |
|
373 | 1 | try: |
|
374 | 1 | import xarray as xr |
|
375 | except ImportError: |
||
376 | print("Error: xarray not available!") |
||
377 | return None |
||
378 | 1 | with tempfile.NamedTemporaryFile() as tf: |
|
379 | 1 | self.write_to_netcdf(tf.name) |
|
380 | 1 | with xr.open_dataset(tf.name, decode_cf=False) as sdorb: |
|
381 | 1 | sdorb = sdorb.drop(["alt_min", "alt_max", "lat_min", "lat_max"]) |
|
382 | 1 | sdorb["time"] = np.array([dateo], dtype=np.float32) |
|
383 | 1 | sdorb["orbit"] = orbit |
|
384 | 1 | sdorb.load() |
|
385 | 1 | return sdorb |
|
386 | |||
387 | |||
388 | 1 | View Code Duplication | class scia_density_day(object): |
389 | """SCIAMACHY daily number densities combined |
||
390 | |||
391 | Contains a stacked version of the post-processed orbit data |
||
392 | for multiple orbits on a day. Used to combine the results. |
||
393 | |||
394 | Parameters |
||
395 | ---------- |
||
396 | name: str |
||
397 | Name of the retrieved species, default: "NO". |
||
398 | Used to name the netcdf variables appropriately. |
||
399 | ref_date: str, optional |
||
400 | The reference date on which to base the date calculations on. |
||
401 | Default: "2000-01-01" |
||
402 | |||
403 | Attributes |
||
404 | ---------- |
||
405 | alts |
||
406 | Retrieval grid altitudes |
||
407 | lats |
||
408 | Retrieval grid latitudes |
||
409 | no_dens |
||
410 | Retrieved number densities |
||
411 | no_errs |
||
412 | Measurement uncertainty |
||
413 | no_etot |
||
414 | Total uncertainty |
||
415 | no_rstd |
||
416 | Relative measurement uncertainty |
||
417 | no_akd |
||
418 | Averaging kernel diagonal elements |
||
419 | no_apri |
||
420 | Prior number density |
||
421 | temperature |
||
422 | NRLMSISE-00 temperatures |
||
423 | noem_no |
||
424 | NOEM NO nuimber densities |
||
425 | vmr |
||
426 | NO vmr using the NRLMSISE-00 total air number densities |
||
427 | lst |
||
428 | Apparent local solar times |
||
429 | mst |
||
430 | Mean local solar times |
||
431 | sza |
||
432 | Solar zenith angles |
||
433 | utchour |
||
434 | UTC hours into measurement day |
||
435 | utcdays |
||
436 | Number of days since reference date |
||
437 | gmlats |
||
438 | IGRF-12 geomagentic latitudes |
||
439 | gmlons |
||
440 | IGRF-12 geomagentic longitudes |
||
441 | aacgmgmlats |
||
442 | AACGM geomagentic latitudes |
||
443 | aacgmgmlons |
||
444 | AACGM geomagentic longitudes |
||
445 | """ |
||
446 | 1 | def __init__(self, name="NO", ref_date="2000-01-01", author="unknown"): |
|
447 | 1 | self.date0 = (dt.datetime.strptime(ref_date, "%Y-%m-%d") |
|
448 | .replace(tzinfo=dt.timezone.utc)) |
||
449 | 1 | self.alts = None |
|
450 | 1 | self.lats = None |
|
451 | 1 | self.version = None |
|
452 | 1 | self.data_version = None |
|
453 | 1 | self.name = name |
|
454 | 1 | self.author = author |
|
455 | 1 | self.date = [] |
|
456 | 1 | self.time = [] |
|
457 | 1 | self.orbit = [] |
|
458 | 1 | self.no_dens = None |
|
459 | 1 | self.no_errs = None |
|
460 | 1 | self.no_etot = None |
|
461 | 1 | self.no_rstd = None |
|
462 | 1 | self.no_akd = None |
|
463 | 1 | self.no_apri = None |
|
464 | 1 | self.no_noem = None |
|
465 | 1 | self.tot_dens = None |
|
466 | 1 | self.no_vmr = None |
|
467 | 1 | self.lons = None |
|
468 | 1 | self.lst = None |
|
469 | 1 | self.mst = None |
|
470 | 1 | self.sza = None |
|
471 | 1 | self.utchour = None |
|
472 | 1 | self.utcdays = None |
|
473 | 1 | self.gmlats = None |
|
474 | 1 | self.gmlons = None |
|
475 | 1 | self.aacgmgmlats = None |
|
476 | 1 | self.aacgmgmlons = None |
|
477 | |||
478 | 1 | def append(self, cdata): |
|
479 | """Append (stack) the data from one orbit |
||
480 | |||
481 | Parameters |
||
482 | ---------- |
||
483 | cdata: :class:`scia_densities_pp` instance |
||
484 | Post-processed level 2 orbital data. |
||
485 | """ |
||
486 | self.time.extend(cdata.time) |
||
487 | self.date.extend(cdata.date) |
||
488 | self.no_dens = np.ma.dstack((self.no_dens, cdata.no_dens)) |
||
489 | self.no_errs = np.ma.dstack((self.no_errs, cdata.no_errs)) |
||
490 | self.no_etot = np.ma.dstack((self.no_etot, cdata.no_etot)) |
||
491 | self.no_rstd = np.ma.dstack((self.no_rstd, cdata.no_rstd)) |
||
492 | self.no_akd = np.ma.dstack((self.no_akd, cdata.no_akd)) |
||
493 | self.no_apri = np.ma.dstack((self.no_apri, cdata.no_apri)) |
||
494 | self.no_noem = np.ma.dstack((self.no_noem, cdata.no_noem)) |
||
495 | self.tot_dens = np.ma.dstack((self.tot_dens, cdata.tot_dens)) |
||
496 | self.no_vmr = np.ma.dstack((self.no_vmr, cdata.no_vmr)) |
||
497 | self.lons = np.ma.dstack((self.lons, cdata.lons)) |
||
498 | self.lst = np.ma.dstack((self.lst, cdata.lst)) |
||
499 | self.mst = np.ma.dstack((self.mst, cdata.mst)) |
||
500 | self.sza = np.ma.dstack((self.sza, cdata.sza)) |
||
501 | self.utchour = np.ma.dstack((self.utchour, cdata.utchour)) |
||
502 | self.utcdays = np.ma.dstack((self.utcdays, cdata.utcdays)) |
||
503 | self.gmlats = np.ma.dstack((self.gmlats, cdata.gmlats)) |
||
504 | self.gmlons = np.ma.dstack((self.gmlons, cdata.gmlons)) |
||
505 | self.aacgmgmlats = np.ma.dstack((self.aacgmgmlats, cdata.aacgmgmlats)) |
||
506 | self.aacgmgmlons = np.ma.dstack((self.aacgmgmlons, cdata.aacgmgmlons)) |
||
507 | |||
508 | 1 | def append_data(self, date, orbit, equtime, scia_dens): |
|
509 | """Append (stack) the data from one orbit |
||
510 | |||
511 | Updates the data in place. |
||
512 | |||
513 | Parameters |
||
514 | ---------- |
||
515 | date: float |
||
516 | Days since `ref_date` for the time coordinate |
||
517 | orbit: int |
||
518 | SCIAMACHY/Envisat orbit number |
||
519 | equtime: float |
||
520 | UTC hour into the day at the equator |
||
521 | scia_dens: :class:`scia_densities_pp` instance |
||
522 | The post-processed orbit data set |
||
523 | """ |
||
524 | 1 | self.version = scia_dens.version |
|
525 | 1 | self.data_version = scia_dens.data_version |
|
526 | 1 | self.date.append(date) |
|
527 | 1 | self.orbit.append(orbit) |
|
528 | 1 | self.time.append(equtime) |
|
529 | 1 | _dens = scia_dens.densities |
|
530 | 1 | _errs = scia_dens.dens_err_meas |
|
531 | 1 | _etot = scia_dens.dens_err_tot |
|
532 | 1 | _r_std = np.abs(_errs / _dens) * 100.0 |
|
533 | # This is cumbersome and error-prone but check |
||
534 | # if we 'append' for the first time. |
||
535 | # In that case `vstack` doesn't work so we set |
||
536 | # the members first. |
||
537 | 1 | if self.no_dens is None: |
|
538 | # we need altitudes and latitudes only once |
||
539 | 1 | self.alts = scia_dens.alts |
|
540 | 1 | self.lats = scia_dens.lats |
|
541 | 1 | self.no_dens = _dens[np.newaxis] |
|
542 | 1 | self.no_errs = _errs[np.newaxis] |
|
543 | 1 | self.no_etot = _etot[np.newaxis] |
|
544 | 1 | self.no_rstd = _r_std[np.newaxis] |
|
545 | 1 | self.no_akd = scia_dens.akdiag[np.newaxis] |
|
546 | 1 | self.no_apri = scia_dens.apriori[np.newaxis] |
|
547 | 1 | self.temperature = scia_dens.temperature[np.newaxis] |
|
548 | 1 | self.no_noem = scia_dens.noem_no[np.newaxis] |
|
549 | 1 | self.tot_dens = scia_dens.dens_tot[np.newaxis] |
|
550 | 1 | self.no_vmr = scia_dens.vmr[np.newaxis] |
|
551 | 1 | self.lons = scia_dens.lons[np.newaxis] |
|
552 | 1 | self.lst = scia_dens.lst[np.newaxis] |
|
553 | 1 | self.mst = scia_dens.mst[np.newaxis] |
|
554 | 1 | self.sza = scia_dens.sza[np.newaxis] |
|
555 | 1 | self.utchour = scia_dens.utchour[np.newaxis] |
|
556 | 1 | self.utcdays = scia_dens.utcdays[np.newaxis] |
|
557 | 1 | self.gmlats = scia_dens.gmlats[np.newaxis] |
|
558 | 1 | self.gmlons = scia_dens.gmlons[np.newaxis] |
|
559 | 1 | self.aacgmgmlats = scia_dens.aacgmgmlats[np.newaxis] |
|
560 | 1 | self.aacgmgmlons = scia_dens.aacgmgmlons[np.newaxis] |
|
561 | else: |
||
562 | 1 | self.no_dens = np.ma.vstack((self.no_dens, _dens[np.newaxis])) |
|
563 | 1 | self.no_errs = np.ma.vstack((self.no_errs, _errs[np.newaxis])) |
|
564 | 1 | self.no_etot = np.ma.vstack((self.no_etot, _etot[np.newaxis])) |
|
565 | 1 | self.no_rstd = np.ma.vstack((self.no_rstd, _r_std[np.newaxis])) |
|
566 | 1 | self.no_akd = np.ma.vstack((self.no_akd, scia_dens.akdiag[np.newaxis])) |
|
567 | 1 | self.no_apri = np.ma.vstack((self.no_apri, scia_dens.apriori[np.newaxis])) |
|
568 | 1 | self.temperature = np.ma.vstack((self.temperature, scia_dens.temperature[np.newaxis])) |
|
569 | 1 | self.no_noem = np.ma.vstack((self.no_noem, scia_dens.noem_no[np.newaxis])) |
|
570 | 1 | self.tot_dens = np.ma.vstack((self.tot_dens, scia_dens.dens_tot[np.newaxis])) |
|
571 | 1 | self.no_vmr = np.ma.vstack((self.no_vmr, scia_dens.vmr[np.newaxis])) |
|
572 | 1 | self.lons = np.ma.vstack((self.lons, scia_dens.lons[np.newaxis])) |
|
573 | 1 | self.lst = np.ma.vstack((self.lst, scia_dens.lst[np.newaxis])) |
|
574 | 1 | self.mst = np.ma.vstack((self.mst, scia_dens.mst[np.newaxis])) |
|
575 | 1 | self.sza = np.ma.vstack((self.sza, scia_dens.sza[np.newaxis])) |
|
576 | 1 | self.utchour = np.ma.vstack((self.utchour, scia_dens.utchour[np.newaxis])) |
|
577 | 1 | self.utcdays = np.ma.vstack((self.utcdays, scia_dens.utcdays[np.newaxis])) |
|
578 | 1 | self.gmlats = np.ma.vstack((self.gmlats, scia_dens.gmlats[np.newaxis])) |
|
579 | 1 | self.gmlons = np.ma.vstack((self.gmlons, scia_dens.gmlons[np.newaxis])) |
|
580 | 1 | self.aacgmgmlats = np.ma.vstack((self.aacgmgmlats, scia_dens.aacgmgmlats[np.newaxis])) |
|
581 | 1 | self.aacgmgmlons = np.ma.vstack((self.aacgmgmlons, scia_dens.aacgmgmlons[np.newaxis])) |
|
582 | |||
583 | 1 | def write_to_netcdf(self, filename): |
|
584 | """Write variables to netcdf files |
||
585 | |||
586 | Uses single precision floats (32 bit) to save space. |
||
587 | |||
588 | Parameters |
||
589 | ---------- |
||
590 | filename: str |
||
591 | The name of the file to write the data to. |
||
592 | """ |
||
593 | 1 | ncf = netcdf_file(filename, 'w', **fmtargs) |
|
594 | 1 | o = np.asarray(self.orbit) |
|
595 | 1 | d = np.asarray(self.date) |
|
596 | 1 | t = np.asarray(self.time) |
|
597 | |||
598 | 1 | if self.version is not None: |
|
599 | 1 | ncf.version = self.version |
|
600 | 1 | if self.data_version is not None: |
|
601 | 1 | ncf.L2_data_version = self.data_version |
|
602 | 1 | ncf.creation_time = dt.datetime.utcnow().strftime("%a %b %d %Y %H:%M:%S +00:00 (UTC)") |
|
603 | 1 | ncf.author = self.author |
|
604 | |||
605 | 1 | ncf.createDimension('time', None) |
|
606 | 1 | ncf.createDimension('altitude', self.alts.size) |
|
607 | 1 | ncf.createDimension('latitude', self.lats.size) |
|
608 | 1 | forbit = ncf.createVariable('orbit', np.dtype('int32').char, ('time',)) |
|
609 | 1 | forbit.axis = 'T' |
|
610 | 1 | forbit.calendar = 'standard' |
|
611 | 1 | forbit.long_name = 'orbit' |
|
612 | 1 | forbit.standard_name = 'orbit' |
|
613 | 1 | forbit.units = 'orbit number' |
|
614 | # the time coordinate is actually called "date" here |
||
615 | 1 | ftime = ncf.createVariable('time', 'f8', ('time',)) |
|
616 | 1 | ftime.axis = 'T' |
|
617 | 1 | ftime.calendar = 'standard' |
|
618 | 1 | ftime.long_name = 'equatorial crossing time' |
|
619 | 1 | ftime.standard_name = 'time' |
|
620 | 1 | ftime.units = 'days since {0}'.format(self.date0.isoformat(sep=' ')) |
|
621 | #ftime.units = 'days since {0}'.format(self.date0.strftime('%Y-%m-%d %H:%M:%S%z (%Z)')) |
||
622 | #fdate = ncf.createVariable('date', np.dtype('float32').char, ('time',)) |
||
623 | #fdate.axis = 'T' |
||
624 | #fdate.calendar = 'standard' |
||
625 | #fdate.long_name = 'date' |
||
626 | #fdate.standard_name = 'date' |
||
627 | #fdate.units = 'days since 1950-01-01 00:00:00' |
||
628 | 1 | falts = ncf.createVariable('altitude', 'f8', ('altitude',)) |
|
629 | 1 | falts.axis = 'Z' |
|
630 | 1 | falts.long_name = 'altitude' |
|
631 | 1 | falts.standard_name = 'altitude' |
|
632 | 1 | falts.units = 'km' |
|
633 | 1 | falts.positive = 'up' |
|
634 | 1 | flats = ncf.createVariable('latitude', 'f8', ('latitude',)) |
|
635 | 1 | flats.axis = 'Y' |
|
636 | 1 | flats.long_name = 'latitude' |
|
637 | 1 | flats.standard_name = 'latitude' |
|
638 | 1 | flats.units = 'degrees_north' |
|
639 | 1 | flons = ncf.createVariable('longitude', 'f8', ('time', 'latitude',)) |
|
640 | 1 | flons.long_name = 'longitude' |
|
641 | 1 | flons.standard_name = 'longitude' |
|
642 | 1 | flons.units = 'degrees_east' |
|
643 | 1 | fdens = ncf.createVariable('%s_DENS' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
644 | 1 | fdens.units = 'cm^{-3}' |
|
645 | 1 | fdens.long_name = '%s number density' % self.name |
|
646 | 1 | ferrs = ncf.createVariable('%s_ERR' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
647 | 1 | ferrs.units = 'cm^{-3}' |
|
648 | 1 | ferrs.long_name = '%s density measurement error' % self.name |
|
649 | 1 | fetot = ncf.createVariable('%s_ETOT' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
650 | 1 | fetot.units = 'cm^{-3}' |
|
651 | 1 | fetot.long_name = '%s density total error' % self.name |
|
652 | 1 | frstd = ncf.createVariable('%s_RSTD' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
653 | 1 | frstd.units = '%' |
|
654 | 1 | frstd.long_name = '%s relative standard deviation' % self.name |
|
655 | 1 | fakd = ncf.createVariable('%s_AKDIAG' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
656 | 1 | fakd.units = '1' |
|
657 | 1 | fakd.long_name = '%s averaging kernel diagonal element' % self.name |
|
658 | 1 | fapri = ncf.createVariable('%s_APRIORI' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
659 | 1 | fapri.units = 'cm^{-3}' |
|
660 | 1 | fapri.long_name = '%s apriori density' % self.name |
|
661 | 1 | ftemp = ncf.createVariable('MSIS_Temp', 'f8', ('time', 'latitude', 'altitude')) |
|
662 | 1 | ftemp.units = 'K' |
|
663 | 1 | ftemp.long_name = 'MSIS temperature' |
|
664 | 1 | ftemp.model = 'NRLMSIS-00' |
|
665 | 1 | fnoem = ncf.createVariable('%s_NOEM' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
666 | 1 | fnoem.units = 'cm^{-3}' |
|
667 | 1 | fnoem.long_name = 'NOEM %s number density' % self.name |
|
668 | 1 | fdens_tot = ncf.createVariable('MSIS_Dens', 'f8', ('time', 'latitude', 'altitude')) |
|
669 | 1 | fdens_tot.units = 'cm^{-3}' |
|
670 | 1 | fdens_tot.long_name = 'MSIS total number density' |
|
671 | 1 | fdens_tot.model = 'NRLMSIS-00' |
|
672 | 1 | fvmr = ncf.createVariable('%s_VMR' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
673 | 1 | fvmr.units = 'ppb' |
|
674 | 1 | fvmr.long_name = '%s volume mixing ratio' % self.name |
|
675 | 1 | flst = ncf.createVariable('app_LST', 'f8', ('time', 'latitude')) |
|
676 | 1 | flst.units = 'hours' |
|
677 | 1 | flst.long_name = 'apparent local solar time' |
|
678 | 1 | fmst = ncf.createVariable('mean_LST', 'f8', ('time', 'latitude')) |
|
679 | 1 | fmst.units = 'hours' |
|
680 | 1 | fmst.long_name = 'mean local solar time' |
|
681 | 1 | fsza = ncf.createVariable('mean_SZA', 'f8', ('time', 'latitude')) |
|
682 | 1 | fsza.units = 'degrees' |
|
683 | 1 | fsza.long_name = 'solar zenith angle at mean altitude' |
|
684 | 1 | futc = ncf.createVariable('UTC', 'f8', ('time', 'latitude')) |
|
685 | 1 | futc.units = 'hours' |
|
686 | 1 | futc.long_name = 'measurement utc time' |
|
687 | 1 | futcd = ncf.createVariable('utc_days', 'f8', ('time', 'latitude')) |
|
688 | 1 | futcd.long_name = 'measurement utc day' |
|
689 | 1 | futcd.units = 'days since {0}'.format(self.date0.isoformat(sep=' ')) |
|
690 | |||
691 | 1 | fgmlats = ncf.createVariable('gm_lats', 'f8', ('time', 'latitude',)) |
|
692 | 1 | fgmlats.long_name = 'geomagnetic_latitude' |
|
693 | 1 | fgmlats.model = 'IGRF' |
|
694 | 1 | fgmlats.units = 'degrees_north' |
|
695 | |||
696 | 1 | fgmlons = ncf.createVariable('gm_lons', 'f8', ('time', 'latitude',)) |
|
697 | 1 | fgmlons.long_name = 'geomagnetic_longitude' |
|
698 | 1 | fgmlons.model = 'IGRF' |
|
699 | 1 | fgmlons.units = 'degrees_east' |
|
700 | |||
701 | 1 | faacgmgmlats = ncf.createVariable('aacgm_gm_lats', 'f8', ('time', 'latitude',)) |
|
702 | 1 | faacgmgmlats.long_name = 'geomagnetic_latitude' |
|
703 | 1 | faacgmgmlats.model = 'AACGM' |
|
704 | 1 | faacgmgmlats.units = 'degrees_north' |
|
705 | |||
706 | 1 | faacgmgmlons = ncf.createVariable('aacgm_gm_lons', 'f8', ('time', 'latitude',)) |
|
707 | 1 | faacgmgmlons.long_name = 'geomagnetic_longitude' |
|
708 | 1 | faacgmgmlons.model = 'AACGM' |
|
709 | 1 | faacgmgmlons.units = 'degrees_east' |
|
710 | |||
711 | 1 | forbit[:] = o |
|
712 | 1 | ftime[:] = d |
|
713 | 1 | falts[:] = self.alts |
|
714 | 1 | flats[:] = self.lats |
|
715 | 1 | flons[:] = self.lons |
|
716 | 1 | fdens[:] = np.ma.atleast_3d(self.no_dens[:]) |
|
717 | 1 | ferrs[:] = np.ma.atleast_3d(self.no_errs[:]) |
|
718 | 1 | fetot[:] = np.ma.atleast_3d(self.no_etot[:]) |
|
719 | 1 | frstd[:] = np.ma.atleast_3d(self.no_rstd[:]) |
|
720 | 1 | fakd[:] = np.ma.atleast_3d(self.no_akd[:]) |
|
721 | 1 | fapri[:] = np.ma.atleast_3d(self.no_apri[:]) |
|
722 | 1 | ftemp[:] = np.ma.atleast_3d(self.temperature[:]) |
|
723 | 1 | fnoem[:] = np.ma.atleast_3d(self.no_noem[:]) |
|
724 | 1 | fdens_tot[:] = np.ma.atleast_3d(self.tot_dens[:]) |
|
725 | 1 | fvmr[:] = np.ma.atleast_3d(self.no_vmr[:]) |
|
726 | 1 | flst[:] = np.ma.atleast_2d(self.lst[:]) |
|
727 | 1 | fmst[:] = np.ma.atleast_2d(self.mst[:]) |
|
728 | 1 | fsza[:] = np.ma.atleast_2d(self.sza[:]) |
|
729 | 1 | futc[:] = np.ma.atleast_2d(self.utchour[:]) |
|
730 | 1 | futcd[:] = np.ma.atleast_2d(self.utcdays[:]) |
|
731 | 1 | fgmlats[:] = np.ma.atleast_2d(self.gmlats[:]) |
|
732 | 1 | fgmlons[:] = np.ma.atleast_2d(self.gmlons[:]) |
|
733 | 1 | faacgmgmlats[:] = np.ma.atleast_2d(self.aacgmgmlats[:]) |
|
734 | 1 | faacgmgmlons[:] = np.ma.atleast_2d(self.aacgmgmlons[:]) |
|
735 | 1 | ncf.close() |
|
736 | |||
737 | 1 | def to_xarray(self): |
|
738 | """Convert the combined orbit data to :class:`xarray.Dataset` |
||
739 | |||
740 | Exports the data using the same data variables as |
||
741 | when writing to netcdf. |
||
742 | |||
743 | Returns |
||
744 | ------- |
||
745 | dataset: xarray.Dataset |
||
746 | """ |
||
747 | 1 | try: |
|
748 | 1 | import xarray as xr |
|
749 | except ImportError: |
||
750 | print("Error: xarray not available!") |
||
751 | return None |
||
752 | 1 | o = np.asarray(self.orbit) |
|
753 | 1 | d = np.asarray(self.date) |
|
754 | |||
755 | 1 | xr_dens = xr.DataArray(self.no_dens, coords=[d, self.lats, self.alts], |
|
756 | dims=["time", "latitude", "altitude"], |
||
757 | attrs={"units": "cm^{-3}", |
||
758 | "long_name": "{0} number density".format(self.name)}, |
||
759 | name="{0}_DENS".format(self.name)) |
||
760 | |||
761 | 1 | xr_errs = xr.DataArray(self.no_errs, coords=[d, self.lats, self.alts], |
|
762 | dims=["time", "latitude", "altitude"], |
||
763 | attrs={"units": "cm^{-3}", |
||
764 | "long_name": "{0} density measurement error".format(self.name)}, |
||
765 | name="{0}_ERR".format(self.name)) |
||
766 | |||
767 | 1 | xr_etot = xr.DataArray(self.no_etot, coords=[d, self.lats, self.alts], |
|
768 | dims=["time", "latitude", "altitude"], |
||
769 | attrs={"units": "cm^{-3}", |
||
770 | "long_name": "{0} density total error".format(self.name)}, |
||
771 | name="{0}_ETOT".format(self.name)) |
||
772 | |||
773 | 1 | xr_rstd = xr.DataArray(self.no_rstd, coords=[d, self.lats, self.alts], |
|
774 | dims=["time", "latitude", "altitude"], |
||
775 | attrs=dict(units='%', |
||
776 | long_name='{0} relative standard deviation'.format(self.name)), |
||
777 | name="{0}_RSTD".format(self.name)) |
||
778 | |||
779 | 1 | xr_akd = xr.DataArray(self.no_akd, coords=[d, self.lats, self.alts], |
|
780 | dims=["time", "latitude", "altitude"], |
||
781 | attrs=dict(units='1', |
||
782 | long_name='{0} averaging kernel diagonal element'.format(self.name)), |
||
783 | name="{0}_AKDIAG".format(self.name)) |
||
784 | |||
785 | 1 | xr_apri = xr.DataArray(self.no_apri, coords=[d, self.lats, self.alts], |
|
786 | dims=["time", "latitude", "altitude"], |
||
787 | attrs=dict(units='cm^{-3}', long_name='{0} apriori density'.format(self.name)), |
||
788 | name="{0}_APRIORI".format(self.name)) |
||
789 | |||
790 | 1 | xr_noem = xr.DataArray(self.no_noem, coords=[d, self.lats, self.alts], |
|
791 | dims=["time", "latitude", "altitude"], |
||
792 | attrs=dict(units='cm^{-3}', long_name='NOEM {0} number density'.format(self.name)), |
||
793 | name="{0}_NOEM".format(self.name)) |
||
794 | |||
795 | 1 | xr_vmr = xr.DataArray(self.no_vmr, coords=[d, self.lats, self.alts], |
|
796 | dims=["time", "latitude", "altitude"], |
||
797 | attrs=dict(units='ppb', long_name='{0} volume mixing ratio'.format(self.name)), |
||
798 | name="{0}_VMR".format(self.name)) |
||
799 | |||
800 | 1 | xr_dtot = xr.DataArray(self.tot_dens, coords=[d, self.lats, self.alts], |
|
801 | dims=["time", "latitude", "altitude"], |
||
802 | attrs=dict(units='cm^{-3}', long_name='MSIS total number density', |
||
803 | model='NRLMSIS-00'), |
||
804 | name="MSIS_Dens") |
||
805 | |||
806 | 1 | xr_temp = xr.DataArray(self.temperature, coords=[d, self.lats, self.alts], |
|
807 | dims=["time", "latitude", "altitude"], |
||
808 | attrs=dict(units='K', long_name='MSIS temperature', |
||
809 | model="NRLMSIS-00"), |
||
810 | name="MSIS_Temp") |
||
811 | |||
812 | 1 | xr_lons = xr.DataArray(self.lons, coords=[d, self.lats], |
|
813 | dims=["time", "latitude"], |
||
814 | attrs=dict(long_name='longitude', standard_name='longitude', |
||
815 | units='degrees_east'), |
||
816 | name='longitude') |
||
817 | |||
818 | 1 | xr_lst = xr.DataArray(self.lst, coords=[d, self.lats], |
|
819 | dims=["time", "latitude"], |
||
820 | attrs=dict(units='hours', long_name='apparent local solar time'), |
||
821 | name="app_LST") |
||
822 | |||
823 | 1 | xr_mst = xr.DataArray(self.mst, coords=[d, self.lats], |
|
824 | dims=["time", "latitude"], |
||
825 | attrs=dict(units='hours', long_name='mean local solar time'), |
||
826 | name="mean_LST") |
||
827 | |||
828 | 1 | xr_sza = xr.DataArray(self.sza, coords=[d, self.lats], |
|
829 | dims=["time", "latitude"], |
||
830 | attrs=dict(units='degrees', |
||
831 | long_name='solar zenith angle at mean altitude'), |
||
832 | name="mean_SZA") |
||
833 | |||
834 | 1 | xr_utch = xr.DataArray(self.utchour, coords=[d, self.lats], |
|
835 | dims=["time", "latitude"], |
||
836 | attrs=dict(units='hours', |
||
837 | long_name='measurement utc time'), |
||
838 | name="UTC") |
||
839 | |||
840 | 1 | xr_utcd = xr.DataArray(self.utcdays, coords=[d, self.lats], |
|
841 | dims=["time", "latitude"], |
||
842 | attrs=dict(units='days since {0}'.format(self.date0.isoformat(sep=' ')), |
||
843 | long_name='measurement utc day'), |
||
844 | name="utc_days") |
||
845 | |||
846 | 1 | xr_gmlats = xr.DataArray(self.gmlats, coords=[d, self.lats], |
|
847 | dims=["time", "latitude"], |
||
848 | attrs=dict(long_name='geomagnetic_latitude', |
||
849 | model='IGRF', units='degrees_north'), |
||
850 | name="gm_lats") |
||
851 | |||
852 | 1 | xr_gmlons = xr.DataArray(self.gmlons, coords=[d, self.lats], |
|
853 | dims=["time", "latitude"], |
||
854 | attrs=dict(long_name='geomagnetic_longitude', |
||
855 | model='IGRF', units='degrees_east'), |
||
856 | name="gm_lons") |
||
857 | |||
858 | 1 | xr_aacgmgmlats = xr.DataArray(self.aacgmgmlats, coords=[d, self.lats], |
|
859 | dims=["time", "latitude"], |
||
860 | attrs=dict(long_name='geomagnetic_latitude', |
||
861 | model='AACGM', units='degrees_north'), |
||
862 | name="aacgm_gm_lats") |
||
863 | |||
864 | 1 | xr_aacgmgmlons = xr.DataArray(self.aacgmgmlons, coords=[d, self.lats], |
|
865 | dims=["time", "latitude"], |
||
866 | attrs=dict(long_name='geomagnetic_longitude', |
||
867 | model='AACGM', units='degrees_east'), |
||
868 | name="aacgm_gm_lons") |
||
869 | |||
870 | 1 | xr_orbit = xr.DataArray(o, coords=[d], dims=["time"], |
|
871 | attrs=dict(axis='T', calendar='standard', long_name='orbit', |
||
872 | standard_name='orbit', units='orbit number'), |
||
873 | name="orbit") |
||
874 | |||
875 | 1 | xr_ds = xr.Dataset({da.name: da for da in |
|
876 | [xr_dens, xr_errs, xr_etot, xr_rstd, xr_akd, xr_apri, xr_noem, |
||
877 | xr_vmr, xr_dtot, xr_temp, xr_lons, xr_lst, xr_mst, xr_sza, |
||
878 | xr_utch, xr_utcd, xr_gmlats, xr_gmlons, xr_aacgmgmlats, |
||
879 | xr_aacgmgmlons, xr_orbit]}) |
||
880 | |||
881 | 1 | xr_ds["time"].attrs = dict(axis='T', calendar='standard', |
|
882 | long_name='equatorial crossing time', |
||
883 | standard_name='time', |
||
884 | units='days since {0}'.format(self.date0.isoformat(sep=' '))) |
||
885 | |||
886 | 1 | xr_ds["altitude"].attrs = dict(axis='Z', long_name='altitude', |
|
887 | standard_name='altitude', units='km', positive='up') |
||
888 | |||
889 | 1 | xr_ds["latitude"].attrs = dict(axis='Y', long_name='latitude', |
|
890 | standard_name='latitude', units='degrees_north') |
||
891 | |||
892 | 1 | if self.version is not None: |
|
893 | 1 | xr_ds.attrs["version"] = self.version |
|
894 | 1 | if self.data_version is not None: |
|
895 | 1 | xr_ds.attrs["L2_data_version"] = self.data_version |
|
896 | 1 | xr_ds.attrs["creation_time"] = dt.datetime.utcnow().strftime("%a %b %d %Y %H:%M:%S +00:00 (UTC)") |
|
897 | 1 | xr_ds.attrs["author"] = self.author |
|
898 | |||
899 | return xr_ds |
||
900 |