Total Complexity | 72 |
Total Lines | 910 |
Duplicated Lines | 95.71 % |
Coverage | 72.29% |
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, _UTC |
|
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 | |||
192 | Parameters |
||
193 | ---------- |
||
194 | filename: str |
||
195 | The name of the file to write the data to. |
||
196 | """ |
||
197 | # write the base variables first and keep the file open for appending |
||
198 | 1 | ncf = scia_densities.write_to_netcdf(self, filename, close=False) |
|
199 | |||
200 | 1 | if self.temperature is not None: |
|
201 | 1 | ftemp = ncf.createVariable('temperature', |
|
202 | np.dtype('float64').char, ('time', 'latitude', 'altitude')) |
||
203 | 1 | ftemp.units = 'K' |
|
204 | 1 | ftemp.long_name = 'temperature' |
|
205 | 1 | ftemp.model = 'NRLMSIS-00' |
|
206 | 1 | ftemp[0, :] = self.temperature |
|
207 | |||
208 | 1 | if self.noem_no is not None: |
|
209 | 1 | fnoem_no = ncf.createVariable('NOEM_density', |
|
210 | np.dtype('float64').char, ('time', 'latitude', 'altitude')) |
||
211 | 1 | fnoem_no.units = 'cm^{-3}' |
|
212 | 1 | fnoem_no.long_name = 'NOEM NO number density' |
|
213 | 1 | fnoem_no[0, :] = self.noem_no |
|
214 | |||
215 | 1 | if self.vmr is not None: |
|
216 | 1 | fvmr = ncf.createVariable('VMR', |
|
217 | np.dtype('float64').char, ('time', 'latitude', 'altitude')) |
||
218 | 1 | fvmr.units = 'ppb' |
|
219 | 1 | fvmr.long_name = 'volume mixing ratio' |
|
220 | 1 | fvmr[0, :] = self.vmr |
|
221 | |||
222 | 1 | if self.lst is not None: |
|
223 | 1 | flst = ncf.createVariable('app_lst', |
|
224 | np.dtype('float64').char, ('time', 'latitude',)) |
||
225 | 1 | flst.units = 'hours' |
|
226 | 1 | flst.long_name = 'apparent local solar time' |
|
227 | 1 | flst[0, :] = self.lst |
|
228 | |||
229 | 1 | if self.mst is not None: |
|
230 | 1 | fmst = ncf.createVariable('mean_lst', |
|
231 | np.dtype('float64').char, ('time', 'latitude',)) |
||
232 | 1 | fmst.units = 'hours' |
|
233 | 1 | fmst.long_name = 'mean local solar time' |
|
234 | 1 | fmst[0, :] = self.mst |
|
235 | |||
236 | 1 | if self.sza is not None: |
|
237 | 1 | fsza = ncf.createVariable('mean_sza', |
|
238 | np.dtype('float64').char, ('time', 'latitude',)) |
||
239 | 1 | fsza.units = 'degrees' |
|
240 | 1 | fsza.long_name = 'mean solar zenith angle' |
|
241 | 1 | fsza[0, :] = self.sza |
|
242 | |||
243 | 1 | if self.utchour is not None: |
|
244 | 1 | futc = ncf.createVariable('utc_hour', |
|
245 | np.dtype('float64').char, ('time', 'latitude',)) |
||
246 | 1 | futc.units = 'hours' |
|
247 | 1 | futc.long_name = 'measurement utc time' |
|
248 | 1 | futc[0, :] = self.utchour |
|
249 | |||
250 | 1 | if self.utcdays is not None: |
|
251 | 1 | futcd = ncf.createVariable('utc_days', |
|
252 | np.dtype('float64').char, ('time', 'latitude',)) |
||
253 | 1 | futcd.long_name = 'measurement day' |
|
254 | 1 | futcd.units = 'days since {0}'.format(self.date0.isoformat(sep=' ')) |
|
255 | 1 | futcd[0, :] = self.utcdays |
|
256 | |||
257 | 1 | if self.gmlats is not None: |
|
258 | 1 | fgmlats = ncf.createVariable('gm_lats', |
|
259 | np.dtype('float64').char, ('time', 'latitude',)) |
||
260 | 1 | fgmlats.long_name = 'geomagnetic_latitude' |
|
261 | 1 | fgmlats.model = 'IGRF' |
|
262 | 1 | fgmlats.units = 'degrees_north' |
|
263 | 1 | fgmlats[0, :] = self.gmlats |
|
264 | |||
265 | 1 | if self.gmlons is not None: |
|
266 | 1 | fgmlons = ncf.createVariable('gm_lons', |
|
267 | np.dtype('float64').char, ('time', 'latitude',)) |
||
268 | 1 | fgmlons.long_name = 'geomagnetic_longitude' |
|
269 | 1 | fgmlons.model = 'IGRF' |
|
270 | 1 | fgmlons.units = 'degrees_east' |
|
271 | 1 | fgmlons[0, :] = self.gmlons |
|
272 | |||
273 | 1 | if self.aacgmgmlats is not None: |
|
274 | 1 | faacgmgmlats = ncf.createVariable('aacgm_gm_lats', |
|
275 | np.dtype('float64').char, ('time', 'latitude',)) |
||
276 | 1 | faacgmgmlats.long_name = 'geomagnetic_latitude' |
|
277 | 1 | faacgmgmlats.model = 'AACGM' |
|
278 | 1 | faacgmgmlats.units = 'degrees_north' |
|
279 | 1 | faacgmgmlats[0, :] = self.aacgmgmlats |
|
280 | |||
281 | 1 | if self.aacgmgmlons is not None: |
|
282 | 1 | faacgmgmlons = ncf.createVariable('aacgm_gm_lons', |
|
283 | np.dtype('float64').char, ('time', 'latitude',)) |
||
284 | 1 | faacgmgmlons.long_name = 'geomagnetic_longitude' |
|
285 | 1 | faacgmgmlons.model = 'AACGM' |
|
286 | 1 | faacgmgmlons.units = 'degrees_east' |
|
287 | 1 | faacgmgmlons[0, :] = self.aacgmgmlons |
|
288 | |||
289 | 1 | if close: |
|
290 | 1 | ncf.close() |
|
291 | else: |
||
292 | return ncf |
||
293 | |||
294 | 1 | def read_from_netcdf(self, filename, close=True): |
|
295 | """Read post-processed level 2 orbit files |
||
296 | |||
297 | Parameters |
||
298 | ---------- |
||
299 | filename: str |
||
300 | The name of the netcdf file. |
||
301 | """ |
||
302 | # read the base variables first and keep the file open for reading |
||
303 | 1 | ncf = scia_densities.read_from_netcdf(self, filename, close=False) |
|
304 | |||
305 | # additional data... |
||
306 | # MSIS temperature |
||
307 | try: |
||
308 | self.temperature = ncf.variables['temperature'][:] |
||
309 | except: |
||
310 | pass |
||
311 | # NOEM density |
||
312 | try: |
||
313 | self.noem_no = ncf.variables['NOEM_density'][:] |
||
314 | except: |
||
315 | pass |
||
316 | # calculated vmr |
||
317 | try: |
||
318 | self.vmr = ncf.variables['VMR'][:] |
||
319 | except: |
||
320 | pass |
||
321 | # apparent local solar time |
||
322 | try: |
||
323 | self.lst = ncf.variables['app_lst'][:] |
||
324 | except: |
||
325 | pass |
||
326 | # mean local solar time |
||
327 | try: |
||
328 | self.mst = ncf.variables['mean_lst'][:] |
||
329 | except: |
||
330 | pass |
||
331 | # mean solar zenith angle |
||
332 | try: |
||
333 | self.sza = ncf.variables['mean_sza'][:] |
||
334 | except: |
||
335 | pass |
||
336 | # utc hours |
||
337 | try: |
||
338 | self.utchour = ncf.variables['utc_hour'][:] |
||
339 | except: |
||
340 | pass |
||
341 | # utc days |
||
342 | try: |
||
343 | self.utcdays = ncf.variables['utc_days'][:] |
||
344 | except: |
||
345 | pass |
||
346 | |||
347 | if close: |
||
348 | ncf.close() |
||
349 | else: |
||
350 | return ncf |
||
351 | |||
352 | 1 | def to_xarray(self, dateo, orbit): |
|
353 | """Convert the data to :class:`xarray.Dataset` |
||
354 | |||
355 | This is a very simple approach, it dumps the data to a temporary |
||
356 | netcdf file and reads that using :func:`xarray.open_dataset()`. |
||
357 | |||
358 | Parameters |
||
359 | ---------- |
||
360 | dateo: float |
||
361 | The days since the reference date at the equator |
||
362 | crossing of the orbit. Used to set the `time` |
||
363 | dimension of the dataset. |
||
364 | orbit: int |
||
365 | The SCIAMACHY/Envisat orbit number of the retrieved data. |
||
366 | |||
367 | Returns |
||
368 | ------- |
||
369 | dataset: xarray.Dataset |
||
370 | """ |
||
371 | 1 | import tempfile |
|
372 | 1 | try: |
|
373 | 1 | import xarray as xr |
|
374 | except ImportError: |
||
375 | print("Error: xarray not available!") |
||
376 | return None |
||
377 | 1 | with tempfile.NamedTemporaryFile() as tf: |
|
378 | 1 | self.write_to_netcdf(tf.name) |
|
379 | 1 | with xr.open_dataset(tf.name, decode_cf=False) as sdorb: |
|
380 | 1 | sdorb = sdorb.drop(["alt_min", "alt_max", "lat_min", "lat_max"]) |
|
381 | 1 | sdorb["time"] = np.array([dateo], dtype=np.float64) |
|
382 | 1 | sdorb["orbit"] = orbit |
|
383 | 1 | sdorb.load() |
|
384 | 1 | return sdorb |
|
385 | |||
386 | |||
387 | 1 | View Code Duplication | class scia_density_day(object): |
388 | """SCIAMACHY daily number densities combined |
||
389 | |||
390 | Contains a stacked version of the post-processed orbit data |
||
391 | for multiple orbits on a day. Used to combine the results. |
||
392 | |||
393 | Parameters |
||
394 | ---------- |
||
395 | name: str |
||
396 | Name of the retrieved species, default: "NO". |
||
397 | Used to name the netcdf variables appropriately. |
||
398 | ref_date: str, optional |
||
399 | The reference date on which to base the date calculations on. |
||
400 | Default: "2000-01-01" |
||
401 | |||
402 | Attributes |
||
403 | ---------- |
||
404 | alts |
||
405 | Retrieval grid altitudes |
||
406 | lats |
||
407 | Retrieval grid latitudes |
||
408 | no_dens |
||
409 | Retrieved number densities |
||
410 | no_errs |
||
411 | Measurement uncertainty |
||
412 | no_etot |
||
413 | Total uncertainty |
||
414 | no_rstd |
||
415 | Relative measurement uncertainty |
||
416 | no_akd |
||
417 | Averaging kernel diagonal elements |
||
418 | no_apri |
||
419 | Prior number density |
||
420 | temperature |
||
421 | NRLMSISE-00 temperatures |
||
422 | noem_no |
||
423 | NOEM NO nuimber densities |
||
424 | vmr |
||
425 | NO vmr using the NRLMSISE-00 total air number densities |
||
426 | lst |
||
427 | Apparent local solar times |
||
428 | mst |
||
429 | Mean local solar times |
||
430 | sza |
||
431 | Solar zenith angles |
||
432 | utchour |
||
433 | UTC hours into measurement day |
||
434 | utcdays |
||
435 | Number of days since reference date |
||
436 | gmlats |
||
437 | IGRF-12 geomagentic latitudes |
||
438 | gmlons |
||
439 | IGRF-12 geomagentic longitudes |
||
440 | aacgmgmlats |
||
441 | AACGM geomagentic latitudes |
||
442 | aacgmgmlons |
||
443 | AACGM geomagentic longitudes |
||
444 | """ |
||
445 | 1 | def __init__(self, name="NO", ref_date="2000-01-01", author="unknown"): |
|
446 | 1 | self.date0 = (dt.datetime.strptime(ref_date, "%Y-%m-%d") |
|
447 | .replace(tzinfo=_UTC)) |
||
448 | 1 | self.alts = None |
|
449 | 1 | self.lats = None |
|
450 | 1 | self.version = None |
|
451 | 1 | self.data_version = None |
|
452 | 1 | self.name = name |
|
453 | 1 | self.author = author |
|
454 | 1 | self.date = [] |
|
455 | 1 | self.time = [] |
|
456 | 1 | self.orbit = [] |
|
457 | 1 | self.no_dens = None |
|
458 | 1 | self.no_errs = None |
|
459 | 1 | self.no_etot = None |
|
460 | 1 | self.no_rstd = None |
|
461 | 1 | self.no_akd = None |
|
462 | 1 | self.no_apri = None |
|
463 | 1 | self.no_noem = None |
|
464 | 1 | self.temperature = 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 | def _vstack_or_new(a, b): |
|
525 | # Check if we 'stack' for the first time (a is None), |
||
526 | # in that case we assign first. |
||
527 | 1 | if a is None: |
|
528 | 1 | return b[None] |
|
529 | 1 | return np.ma.vstack((a, b[None])) |
|
530 | |||
531 | 1 | self.version = scia_dens.version |
|
532 | 1 | self.data_version = scia_dens.data_version |
|
533 | 1 | self.date.append(date) |
|
534 | 1 | self.orbit.append(orbit) |
|
535 | 1 | self.time.append(equtime) |
|
536 | 1 | _dens = scia_dens.densities |
|
537 | 1 | _errs = scia_dens.dens_err_meas |
|
538 | 1 | _etot = scia_dens.dens_err_tot |
|
539 | 1 | _r_std = np.abs(_errs / _dens) * 100.0 |
|
540 | 1 | if self.alts is None: |
|
541 | # we need altitudes and latitudes only once |
||
542 | 1 | self.alts = scia_dens.alts |
|
543 | 1 | self.lats = scia_dens.lats |
|
544 | 1 | self.no_dens = _vstack_or_new(self.no_dens, _dens) |
|
545 | 1 | self.no_errs = _vstack_or_new(self.no_errs, _errs) |
|
546 | 1 | self.no_etot = _vstack_or_new(self.no_etot, _etot) |
|
547 | 1 | self.no_rstd = _vstack_or_new(self.no_rstd, _r_std) |
|
548 | 1 | self.no_akd = _vstack_or_new(self.no_akd, scia_dens.akdiag) |
|
549 | 1 | self.no_apri = _vstack_or_new(self.no_apri, scia_dens.apriori) |
|
550 | 1 | self.temperature = _vstack_or_new(self.temperature, scia_dens.temperature) |
|
551 | 1 | self.no_noem = _vstack_or_new(self.no_noem, scia_dens.noem_no) |
|
552 | 1 | self.tot_dens = _vstack_or_new(self.tot_dens, scia_dens.dens_tot) |
|
553 | 1 | self.no_vmr = _vstack_or_new(self.no_vmr, scia_dens.vmr) |
|
554 | 1 | self.lons = _vstack_or_new(self.lons, scia_dens.lons) |
|
555 | 1 | self.lst = _vstack_or_new(self.lst, scia_dens.lst) |
|
556 | 1 | self.mst = _vstack_or_new(self.mst, scia_dens.mst) |
|
557 | 1 | self.sza = _vstack_or_new(self.sza, scia_dens.sza) |
|
558 | 1 | self.utchour = _vstack_or_new(self.utchour, scia_dens.utchour) |
|
559 | 1 | self.utcdays = _vstack_or_new(self.utcdays, scia_dens.utcdays) |
|
560 | 1 | self.gmlats = _vstack_or_new(self.gmlats, scia_dens.gmlats) |
|
561 | 1 | self.gmlons = _vstack_or_new(self.gmlons, scia_dens.gmlons) |
|
562 | 1 | self.aacgmgmlats = _vstack_or_new(self.aacgmgmlats, scia_dens.aacgmgmlats) |
|
563 | 1 | self.aacgmgmlons = _vstack_or_new(self.aacgmgmlons, scia_dens.aacgmgmlons) |
|
564 | |||
565 | 1 | def write_to_netcdf(self, filename): |
|
566 | """Write variables to netcdf files |
||
567 | |||
568 | Parameters |
||
569 | ---------- |
||
570 | filename: str |
||
571 | The name of the file to write the data to. |
||
572 | """ |
||
573 | 1 | _var_dicts = { |
|
574 | "2.1": { |
||
575 | "dens_tot": { |
||
576 | "name": "TOT_DENS", |
||
577 | "long_name": "total number density (NRLMSIS-00)", |
||
578 | "model": None, |
||
579 | }, |
||
580 | "temperature": { |
||
581 | "name": "temperature", |
||
582 | "long_name": "temperature", |
||
583 | "model": "NRLMSIS-00", |
||
584 | }, |
||
585 | }, |
||
586 | "2.2": { |
||
587 | "dens_tot": { |
||
588 | "name": "MSIS_Dens", |
||
589 | "long_name": "MSIS total number density", |
||
590 | "model": "NRLMSIS-00", |
||
591 | }, |
||
592 | "temperature": { |
||
593 | "name": "MSIS_Temp", |
||
594 | "long_name": "MSIS temperature", |
||
595 | "model": "NRLMSIS-00", |
||
596 | }, |
||
597 | }, |
||
598 | } |
||
599 | |||
600 | 1 | ncf = netcdf_file(filename, 'w', **fmtargs) |
|
601 | 1 | o = np.asarray(self.orbit) |
|
602 | 1 | d = np.asarray(self.date) |
|
603 | 1 | t = np.asarray(self.time) |
|
604 | |||
605 | 1 | if self.version is not None: |
|
606 | 1 | ncf.version = self.version |
|
607 | 1 | if self.data_version is not None: |
|
608 | 1 | ncf.L2_data_version = self.data_version |
|
609 | 1 | ncf.creation_time = dt.datetime.utcnow().strftime("%a %b %d %Y %H:%M:%S +00:00 (UTC)") |
|
610 | 1 | ncf.author = self.author |
|
611 | |||
612 | 1 | ncf.createDimension('time', None) |
|
613 | 1 | ncf.createDimension('altitude', self.alts.size) |
|
614 | 1 | ncf.createDimension('latitude', self.lats.size) |
|
615 | 1 | forbit = ncf.createVariable('orbit', np.dtype('int32').char, ('time',)) |
|
616 | 1 | forbit.axis = 'T' |
|
617 | 1 | forbit.calendar = 'standard' |
|
618 | 1 | forbit.long_name = 'orbit' |
|
619 | 1 | forbit.standard_name = 'orbit' |
|
620 | 1 | forbit.units = 'orbit number' |
|
621 | # the time coordinate is actually called "date" here |
||
622 | 1 | ftime = ncf.createVariable('time', 'f8', ('time',)) |
|
623 | 1 | ftime.axis = 'T' |
|
624 | 1 | ftime.calendar = 'standard' |
|
625 | 1 | ftime.long_name = 'equatorial crossing time' |
|
626 | 1 | ftime.standard_name = 'time' |
|
627 | 1 | ftime.units = 'days since {0}'.format(self.date0.isoformat(sep=' ')) |
|
628 | #ftime.units = 'days since {0}'.format(self.date0.strftime('%Y-%m-%d %H:%M:%S%z (%Z)')) |
||
629 | #fdate = ncf.createVariable('date', np.dtype('float64').char, ('time',)) |
||
630 | #fdate.axis = 'T' |
||
631 | #fdate.calendar = 'standard' |
||
632 | #fdate.long_name = 'date' |
||
633 | #fdate.standard_name = 'date' |
||
634 | #fdate.units = 'days since 1950-01-01 00:00:00' |
||
635 | 1 | falts = ncf.createVariable('altitude', 'f8', ('altitude',)) |
|
636 | 1 | falts.axis = 'Z' |
|
637 | 1 | falts.long_name = 'altitude' |
|
638 | 1 | falts.standard_name = 'altitude' |
|
639 | 1 | falts.units = 'km' |
|
640 | 1 | falts.positive = 'up' |
|
641 | 1 | flats = ncf.createVariable('latitude', 'f8', ('latitude',)) |
|
642 | 1 | flats.axis = 'Y' |
|
643 | 1 | flats.long_name = 'latitude' |
|
644 | 1 | flats.standard_name = 'latitude' |
|
645 | 1 | flats.units = 'degrees_north' |
|
646 | 1 | flons = ncf.createVariable('longitude', 'f8', ('time', 'latitude',)) |
|
647 | 1 | flons.long_name = 'longitude' |
|
648 | 1 | flons.standard_name = 'longitude' |
|
649 | 1 | flons.units = 'degrees_east' |
|
650 | 1 | fdens = ncf.createVariable('%s_DENS' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
651 | 1 | fdens.units = 'cm^{-3}' |
|
652 | 1 | fdens.long_name = '%s number density' % self.name |
|
653 | 1 | ferrs = ncf.createVariable('%s_ERR' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
654 | 1 | ferrs.units = 'cm^{-3}' |
|
655 | 1 | ferrs.long_name = '%s density measurement error' % self.name |
|
656 | 1 | fetot = ncf.createVariable('%s_ETOT' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
657 | 1 | fetot.units = 'cm^{-3}' |
|
658 | 1 | fetot.long_name = '%s density total error' % self.name |
|
659 | 1 | frstd = ncf.createVariable('%s_RSTD' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
660 | 1 | frstd.units = '%' |
|
661 | 1 | frstd.long_name = '%s relative standard deviation' % self.name |
|
662 | 1 | fakd = ncf.createVariable('%s_AKDIAG' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
663 | 1 | fakd.units = '1' |
|
664 | 1 | fakd.long_name = '%s averaging kernel diagonal element' % self.name |
|
665 | 1 | fapri = ncf.createVariable('%s_APRIORI' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
666 | 1 | fapri.units = 'cm^{-3}' |
|
667 | 1 | fapri.long_name = '%s apriori density' % self.name |
|
668 | 1 | ftemp = ncf.createVariable(_var_dicts[self.version]["temperature"]["name"], |
|
669 | 'f8', ('time', 'latitude', 'altitude')) |
||
670 | 1 | ftemp.long_name = _var_dicts[self.version]["temperature"]["long_name"] |
|
671 | 1 | ftemp.model = 'NRLMSIS-00' |
|
672 | 1 | ftemp.units = 'K' |
|
673 | 1 | fdens_tot = ncf.createVariable(_var_dicts[self.version]["dens_tot"]["name"], |
|
674 | 'f8', ('time', 'latitude', 'altitude')) |
||
675 | 1 | fdens_tot.long_name = _var_dicts[self.version]["dens_tot"]["long_name"] |
|
676 | 1 | fdens_tot.units = 'cm^{-3}' |
|
677 | 1 | if _var_dicts[self.version]["dens_tot"]["model"] is not None: |
|
678 | 1 | fdens_tot.model = _var_dicts[self.version]["dens_tot"]["model"] |
|
679 | 1 | fnoem = ncf.createVariable('%s_NOEM' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
680 | 1 | fnoem.units = 'cm^{-3}' |
|
681 | 1 | fnoem.long_name = 'NOEM %s number density' % self.name |
|
682 | 1 | fvmr = ncf.createVariable('%s_VMR' % self.name, 'f8', ('time', 'latitude', 'altitude')) |
|
683 | 1 | fvmr.units = 'ppb' |
|
684 | 1 | fvmr.long_name = '%s volume mixing ratio' % self.name |
|
685 | 1 | flst = ncf.createVariable('app_LST', 'f8', ('time', 'latitude')) |
|
686 | 1 | flst.units = 'hours' |
|
687 | 1 | flst.long_name = 'apparent local solar time' |
|
688 | 1 | fmst = ncf.createVariable('mean_LST', 'f8', ('time', 'latitude')) |
|
689 | 1 | fmst.units = 'hours' |
|
690 | 1 | fmst.long_name = 'mean local solar time' |
|
691 | 1 | fsza = ncf.createVariable('mean_SZA', 'f8', ('time', 'latitude')) |
|
692 | 1 | fsza.units = 'degrees' |
|
693 | 1 | fsza.long_name = 'solar zenith angle at mean altitude' |
|
694 | 1 | futc = ncf.createVariable('UTC', 'f8', ('time', 'latitude')) |
|
695 | 1 | futc.units = 'hours' |
|
696 | 1 | futc.long_name = 'measurement utc time' |
|
697 | 1 | futcd = ncf.createVariable('utc_days', 'f8', ('time', 'latitude')) |
|
698 | 1 | futcd.long_name = 'measurement utc day' |
|
699 | 1 | futcd.units = 'days since {0}'.format(self.date0.isoformat(sep=' ')) |
|
700 | |||
701 | 1 | fgmlats = ncf.createVariable('gm_lats', 'f8', ('time', 'latitude',)) |
|
702 | 1 | fgmlats.long_name = 'geomagnetic_latitude' |
|
703 | 1 | fgmlats.model = 'IGRF' |
|
704 | 1 | fgmlats.units = 'degrees_north' |
|
705 | |||
706 | 1 | fgmlons = ncf.createVariable('gm_lons', 'f8', ('time', 'latitude',)) |
|
707 | 1 | fgmlons.long_name = 'geomagnetic_longitude' |
|
708 | 1 | fgmlons.model = 'IGRF' |
|
709 | 1 | fgmlons.units = 'degrees_east' |
|
710 | |||
711 | 1 | faacgmgmlats = ncf.createVariable('aacgm_gm_lats', 'f8', ('time', 'latitude',)) |
|
712 | 1 | faacgmgmlats.long_name = 'geomagnetic_latitude' |
|
713 | 1 | faacgmgmlats.model = 'AACGM' |
|
714 | 1 | faacgmgmlats.units = 'degrees_north' |
|
715 | |||
716 | 1 | faacgmgmlons = ncf.createVariable('aacgm_gm_lons', 'f8', ('time', 'latitude',)) |
|
717 | 1 | faacgmgmlons.long_name = 'geomagnetic_longitude' |
|
718 | 1 | faacgmgmlons.model = 'AACGM' |
|
719 | 1 | faacgmgmlons.units = 'degrees_east' |
|
720 | |||
721 | 1 | forbit[:] = o |
|
722 | 1 | ftime[:] = d |
|
723 | 1 | falts[:] = self.alts |
|
724 | 1 | flats[:] = self.lats |
|
725 | 1 | flons[:] = self.lons |
|
726 | 1 | fdens[:] = np.ma.atleast_3d(self.no_dens[:]) |
|
727 | 1 | ferrs[:] = np.ma.atleast_3d(self.no_errs[:]) |
|
728 | 1 | fetot[:] = np.ma.atleast_3d(self.no_etot[:]) |
|
729 | 1 | frstd[:] = np.ma.atleast_3d(self.no_rstd[:]) |
|
730 | 1 | fakd[:] = np.ma.atleast_3d(self.no_akd[:]) |
|
731 | 1 | fapri[:] = np.ma.atleast_3d(self.no_apri[:]) |
|
732 | 1 | ftemp[:] = np.ma.atleast_3d(self.temperature[:]) |
|
733 | 1 | fnoem[:] = np.ma.atleast_3d(self.no_noem[:]) |
|
734 | 1 | fdens_tot[:] = np.ma.atleast_3d(self.tot_dens[:]) |
|
735 | 1 | fvmr[:] = np.ma.atleast_3d(self.no_vmr[:]) |
|
736 | 1 | flst[:] = np.ma.atleast_2d(self.lst[:]) |
|
737 | 1 | fmst[:] = np.ma.atleast_2d(self.mst[:]) |
|
738 | 1 | fsza[:] = np.ma.atleast_2d(self.sza[:]) |
|
739 | 1 | futc[:] = np.ma.atleast_2d(self.utchour[:]) |
|
740 | 1 | futcd[:] = np.ma.atleast_2d(self.utcdays[:]) |
|
741 | 1 | fgmlats[:] = np.ma.atleast_2d(self.gmlats[:]) |
|
742 | 1 | fgmlons[:] = np.ma.atleast_2d(self.gmlons[:]) |
|
743 | 1 | faacgmgmlats[:] = np.ma.atleast_2d(self.aacgmgmlats[:]) |
|
744 | 1 | faacgmgmlons[:] = np.ma.atleast_2d(self.aacgmgmlons[:]) |
|
745 | 1 | ncf.close() |
|
746 | |||
747 | 1 | def to_xarray(self): |
|
748 | """Convert the combined orbit data to :class:`xarray.Dataset` |
||
749 | |||
750 | Exports the data using the same data variables as |
||
751 | when writing to netcdf. |
||
752 | |||
753 | Returns |
||
754 | ------- |
||
755 | dataset: xarray.Dataset |
||
756 | """ |
||
757 | 1 | try: |
|
758 | 1 | import xarray as xr |
|
759 | except ImportError: |
||
760 | print("Error: xarray not available!") |
||
761 | return None |
||
762 | 1 | o = np.asarray(self.orbit) |
|
763 | 1 | d = np.asarray(self.date) |
|
764 | |||
765 | 1 | xr_dens = xr.DataArray(self.no_dens, coords=[d, self.lats, self.alts], |
|
766 | dims=["time", "latitude", "altitude"], |
||
767 | attrs={"units": "cm^{-3}", |
||
768 | "long_name": "{0} number density".format(self.name)}, |
||
769 | name="{0}_DENS".format(self.name)) |
||
770 | |||
771 | 1 | xr_errs = xr.DataArray(self.no_errs, coords=[d, self.lats, self.alts], |
|
772 | dims=["time", "latitude", "altitude"], |
||
773 | attrs={"units": "cm^{-3}", |
||
774 | "long_name": "{0} density measurement error".format(self.name)}, |
||
775 | name="{0}_ERR".format(self.name)) |
||
776 | |||
777 | 1 | xr_etot = xr.DataArray(self.no_etot, coords=[d, self.lats, self.alts], |
|
778 | dims=["time", "latitude", "altitude"], |
||
779 | attrs={"units": "cm^{-3}", |
||
780 | "long_name": "{0} density total error".format(self.name)}, |
||
781 | name="{0}_ETOT".format(self.name)) |
||
782 | |||
783 | 1 | xr_rstd = xr.DataArray(self.no_rstd, coords=[d, self.lats, self.alts], |
|
784 | dims=["time", "latitude", "altitude"], |
||
785 | attrs=dict(units='%', |
||
786 | long_name='{0} relative standard deviation'.format(self.name)), |
||
787 | name="{0}_RSTD".format(self.name)) |
||
788 | |||
789 | 1 | xr_akd = xr.DataArray(self.no_akd, coords=[d, self.lats, self.alts], |
|
790 | dims=["time", "latitude", "altitude"], |
||
791 | attrs=dict(units='1', |
||
792 | long_name='{0} averaging kernel diagonal element'.format(self.name)), |
||
793 | name="{0}_AKDIAG".format(self.name)) |
||
794 | |||
795 | 1 | xr_apri = xr.DataArray(self.no_apri, coords=[d, self.lats, self.alts], |
|
796 | dims=["time", "latitude", "altitude"], |
||
797 | attrs=dict(units='cm^{-3}', long_name='{0} apriori density'.format(self.name)), |
||
798 | name="{0}_APRIORI".format(self.name)) |
||
799 | |||
800 | 1 | xr_noem = xr.DataArray(self.no_noem, coords=[d, self.lats, self.alts], |
|
801 | dims=["time", "latitude", "altitude"], |
||
802 | attrs=dict(units='cm^{-3}', long_name='NOEM {0} number density'.format(self.name)), |
||
803 | name="{0}_NOEM".format(self.name)) |
||
804 | |||
805 | 1 | xr_vmr = xr.DataArray(self.no_vmr, coords=[d, self.lats, self.alts], |
|
806 | dims=["time", "latitude", "altitude"], |
||
807 | attrs=dict(units='ppb', long_name='{0} volume mixing ratio'.format(self.name)), |
||
808 | name="{0}_VMR".format(self.name)) |
||
809 | |||
810 | 1 | xr_dtot = xr.DataArray(self.tot_dens, coords=[d, self.lats, self.alts], |
|
811 | dims=["time", "latitude", "altitude"], |
||
812 | attrs=dict(units='cm^{-3}', long_name='MSIS total number density', |
||
813 | model='NRLMSIS-00'), |
||
814 | name="MSIS_Dens") |
||
815 | |||
816 | 1 | xr_temp = xr.DataArray(self.temperature, coords=[d, self.lats, self.alts], |
|
817 | dims=["time", "latitude", "altitude"], |
||
818 | attrs=dict(units='K', long_name='MSIS temperature', |
||
819 | model="NRLMSIS-00"), |
||
820 | name="MSIS_Temp") |
||
821 | |||
822 | 1 | xr_lons = xr.DataArray(self.lons, coords=[d, self.lats], |
|
823 | dims=["time", "latitude"], |
||
824 | attrs=dict(long_name='longitude', standard_name='longitude', |
||
825 | units='degrees_east'), |
||
826 | name='longitude') |
||
827 | |||
828 | 1 | xr_lst = xr.DataArray(self.lst, coords=[d, self.lats], |
|
829 | dims=["time", "latitude"], |
||
830 | attrs=dict(units='hours', long_name='apparent local solar time'), |
||
831 | name="app_LST") |
||
832 | |||
833 | 1 | xr_mst = xr.DataArray(self.mst, coords=[d, self.lats], |
|
834 | dims=["time", "latitude"], |
||
835 | attrs=dict(units='hours', long_name='mean local solar time'), |
||
836 | name="mean_LST") |
||
837 | |||
838 | 1 | xr_sza = xr.DataArray(self.sza, coords=[d, self.lats], |
|
839 | dims=["time", "latitude"], |
||
840 | attrs=dict(units='degrees', |
||
841 | long_name='solar zenith angle at mean altitude'), |
||
842 | name="mean_SZA") |
||
843 | |||
844 | 1 | xr_utch = xr.DataArray(self.utchour, coords=[d, self.lats], |
|
845 | dims=["time", "latitude"], |
||
846 | attrs=dict(units='hours', |
||
847 | long_name='measurement utc time'), |
||
848 | name="UTC") |
||
849 | |||
850 | 1 | xr_utcd = xr.DataArray(self.utcdays, coords=[d, self.lats], |
|
851 | dims=["time", "latitude"], |
||
852 | attrs=dict(units='days since {0}'.format(self.date0.isoformat(sep=' ')), |
||
853 | long_name='measurement utc day'), |
||
854 | name="utc_days") |
||
855 | |||
856 | 1 | xr_gmlats = xr.DataArray(self.gmlats, coords=[d, self.lats], |
|
857 | dims=["time", "latitude"], |
||
858 | attrs=dict(long_name='geomagnetic_latitude', |
||
859 | model='IGRF', units='degrees_north'), |
||
860 | name="gm_lats") |
||
861 | |||
862 | 1 | xr_gmlons = xr.DataArray(self.gmlons, coords=[d, self.lats], |
|
863 | dims=["time", "latitude"], |
||
864 | attrs=dict(long_name='geomagnetic_longitude', |
||
865 | model='IGRF', units='degrees_east'), |
||
866 | name="gm_lons") |
||
867 | |||
868 | 1 | xr_aacgmgmlats = xr.DataArray(self.aacgmgmlats, coords=[d, self.lats], |
|
869 | dims=["time", "latitude"], |
||
870 | attrs=dict(long_name='geomagnetic_latitude', |
||
871 | model='AACGM', units='degrees_north'), |
||
872 | name="aacgm_gm_lats") |
||
873 | |||
874 | 1 | xr_aacgmgmlons = xr.DataArray(self.aacgmgmlons, coords=[d, self.lats], |
|
875 | dims=["time", "latitude"], |
||
876 | attrs=dict(long_name='geomagnetic_longitude', |
||
877 | model='AACGM', units='degrees_east'), |
||
878 | name="aacgm_gm_lons") |
||
879 | |||
880 | 1 | xr_orbit = xr.DataArray(o, coords=[d], dims=["time"], |
|
881 | attrs=dict(axis='T', calendar='standard', long_name='orbit', |
||
882 | standard_name='orbit', units='orbit number'), |
||
883 | name="orbit") |
||
884 | |||
885 | 1 | xr_ds = xr.Dataset({da.name: da for da in |
|
886 | [xr_dens, xr_errs, xr_etot, xr_rstd, xr_akd, xr_apri, xr_noem, |
||
887 | xr_vmr, xr_dtot, xr_temp, xr_lons, xr_lst, xr_mst, xr_sza, |
||
888 | xr_utch, xr_utcd, xr_gmlats, xr_gmlons, xr_aacgmgmlats, |
||
889 | xr_aacgmgmlons, xr_orbit]}) |
||
890 | |||
891 | 1 | xr_ds["time"].attrs = dict(axis='T', calendar='standard', |
|
892 | long_name='equatorial crossing time', |
||
893 | standard_name='time', |
||
894 | units='days since {0}'.format(self.date0.isoformat(sep=' '))) |
||
895 | |||
896 | 1 | xr_ds["altitude"].attrs = dict(axis='Z', long_name='altitude', |
|
897 | standard_name='altitude', units='km', positive='up') |
||
898 | |||
899 | 1 | xr_ds["latitude"].attrs = dict(axis='Y', long_name='latitude', |
|
900 | standard_name='latitude', units='degrees_north') |
||
901 | |||
902 | 1 | if self.version is not None: |
|
903 | 1 | xr_ds.attrs["version"] = self.version |
|
904 | 1 | if self.data_version is not None: |
|
905 | 1 | xr_ds.attrs["L2_data_version"] = self.data_version |
|
906 | 1 | xr_ds.attrs["creation_time"] = dt.datetime.utcnow().strftime("%a %b %d %Y %H:%M:%S +00:00 (UTC)") |
|
907 | 1 | xr_ds.attrs["author"] = self.author |
|
908 | |||
909 | return xr_ds |
||
910 |