source: trunk/UTIL/PYTHON/mcd/mcd.py @ 821

Last change on this file since 821 was 821, checked in by aslmd, 12 years ago

UTIL PYTHON. MCD online interface. addressed the TODO list of rev 812, plus other small improvements. this version was sent to beta-testers in the euromars list.

  • Property svn:executable set to *
File size: 39.1 KB
Line 
1####################################################
2### A Python Class for the Mars Climate Database ###
3### ---------------------------------------------###
4### Aymeric SPIGA 17-21/04/2012                  ###
5### ---------------------------------------------###
6### (see mcdtest.py for examples of use)         ###
7####################################################
8
9import numpy as np
10import fmcd
11import matplotlib.pyplot as mpl
12import myplot
13
14
15class mcd():
16 
17    def __repr__(self):
18    # print out a help string when help is invoked on the object
19        whatprint = 'MCD object. \"help(mcd)\" for more information\n'
20        return whatprint
21
22########################
23### Default settings ###
24########################
25
26    def __init__(self):
27    # default settings
28        ## 0. general stuff
29        self.name      = "MCD v4.3"
30        self.ack       = "Mars Climate Database (c) LMD/OU/IAA/ESA/CNES"
31        #self.dset      = '/home/aymeric/Science/MCD_v4.3/data/'
32        self.dset      = '/home/marshttp/MCD_v4.3/data/'
33        ## 1. spatio-temporal coordinates
34        self.lat       = 0.
35        self.lats      = None
36        self.late      = None
37        self.lon       = 0.
38        self.lons      = None
39        self.lone      = None
40        self.loct      = 0.
41        self.locts     = None
42        self.locte     = None
43        self.xdate     = 0.  # see datekey
44        self.xdates    = None
45        self.xdatee    = None
46        self.xz        = 10. # see zkey
47        self.xzs       = None
48        self.xze       = None
49        ## 1bis. related settings
50        self.zkey      = 3  # specify that xz is the altitude above surface (m)
51                            # zkey  : <integer>   type of vertical coordinate xz
52                            # 1 = radius from centre of planet (m)
53                            # 2 = height above areoid (m) (MOLA zero datum)
54                            # 3 = height above surface (m)
55                            # 4 = pressure level (Pa)
56                            # 5 = altitude above mean Mars Radius(=3396000m) (m)
57        self.datekey   = 1  # 0 = "Earth time": xdate is given in Julian days (localtime must be set to zero)
58                            # 1 = "Mars date": xdate is the value of Ls
59        ## 2. climatological options
60        self.dust      = 2  #our best guess MY24 scenario, with solar average conditions
61        self.hrkey     = 1  #set high resolution mode on (hrkey=0 to set high resolution off)
62        ## 3. additional settings for advanced use
63        self.extvarkey = 1  #extra output variables (1: yes, 0: no)
64        self.perturkey = 0  #integer perturkey ! perturbation type (0: none)
65        self.seedin    = 1  #random number generator seed (unused if perturkey=0)
66        self.gwlength  = 0. #gravity Wave wavelength (unused if perturkey=0)
67        ## outputs. just to define attributes.
68        ## --> in update
69        self.pres = None ; self.dens = None ; self.temp = None ; self.zonwind = None ; self.merwind = None ; self.meanvar = None ; self.extvar = None
70        self.seedout = None ; self.ierr = None
71        ## --> in prepare
72        self.xcoord = None ; self.ycoord = None
73        self.prestab = None ; self.denstab = None ; self.temptab = None 
74        self.zonwindtab = None ; self.merwindtab = None ; self.meanvartab = None ; self.extvartab = None
75        ## plot stuff
76        self.xlabel = None ; self.ylabel = None ; self.title = ""
77        self.vertplot = False
78        self.fmt = "%.2e" 
79        self.colorm = "jet"
80        self.fixedlt = False
81        self.zonmean = False
82
83    def viking1(self): self.name = "Viking 1 site. MCD v4.3 output" ; self.lat = 22.48 ; self.lon = -49.97 ; self.xdate = 97.
84    def viking2(self): self.name = "Viking 2 site. MCD v4.3 output" ; self.lat = 47.97 ; self.lon = -225.74 ; self.xdate = 117.6
85
86    def getdustlabel(self):
87        if self.dust == 1: self.dustlabel = "MY24 minimum solar scenario"
88        elif self.dust == 2: self.dustlabel = "MY24 average solar scenario"
89        elif self.dust == 3: self.dustlabel = "MY24 maximum solar scenario"
90        elif self.dust == 4: self.dustlabel = "dust storm minimum solar scenario"
91        elif self.dust == 5: self.dustlabel = "dust storm average solar scenario"
92        elif self.dust == 6: self.dustlabel = "dust storm maximum solar scenario"
93        elif self.dust == 7: self.dustlabel = "warm scenario (dusty, maximum solar)"
94        elif self.dust == 8: self.dustlabel = "cold scenario (low dust, minimum solar)"
95
96    def gettitle(self,oneline=False):
97        self.getdustlabel()
98        self.title = self.name + " with " + self.dustlabel + "."
99        if self.datekey == 1:    self.title = self.title + " Ls " + str(self.xdate) + "deg."
100        elif self.datekey == 0:  self.title = self.title + " JD " + str(self.xdate) + "."
101        if not oneline: self.title = self.title + "\n"
102        if self.lats is None:  self.title = self.title + " Latitude " + str(self.lat) + "N"
103        if self.zonmean: self.title = self.title + "Zonal mean over all longitudes."
104        elif self.lons is None: self.title = self.title + " Longitude " + str(self.lon) + "E"
105        if self.xzs is None:   
106            self.vertunits()
107            self.title = self.title + " Altitude " + str(self.xz) + " " + self.vunits
108        if self.locts is None:
109            self.title = self.title + " Local time " + str(self.loct) + "h"
110            if not self.fixedlt:  self.title = self.title + " (at longitude 0) "
111
112    def getextvarlab(self,num):
113        whichfield = { \
114        91: "Pressure (Pa)", \
115        92: "Density (kg/m3)", \
116        93: "Temperature (K)", \
117        94: "W-E wind component (m/s)", \
118        95: "S-N wind component (m/s)", \
119        1: "Radial distance from planet center (m)",\
120        2: "Altitude above areoid (Mars geoid) (m)",\
121        3: "Altitude above local surface (m)",\
122        4: "orographic height (m) (surf alt above areoid)",\
123        5: "Ls, solar longitude of Mars (deg)",\
124        6: "LST local true solar time (hrs)",\
125        7: "Universal solar time (LST at lon=0) (hrs)",\
126        8: "Air heat capacity Cp (J kg-1 K-1)",\
127        9: "gamma=Cp/Cv Ratio of specific heats",\
128        10: "density RMS day to day variations (kg/m^3)",\
129        11: "[not defined]",\
130        12: "[not defined]",\
131        13: "scale height H(p) (m)",\
132        14: "GCM orography (m)",\
133        15: "surface temperature (K)",\
134        16: "daily max mean surface temperature (K)",\
135        17: "daily min mean surface temperature (K)",\
136        18: "surf. temperature RMS day to day variations (K)",\
137        19: "surface pressure (high resolution if hireskey=1)",\
138        20: "GCM surface pressure (Pa)",\
139        21: "atmospheric pressure RMS day to day variations (Pa)",\
140        22: "surface pressure RMS day to day variations (Pa)",\
141        23: "temperature RMS day to day variations (K)",\
142        24: "zonal wind RMS day to day variations (m/s)",\
143        25: "meridional wind RMS day to day variations (m/s)",\
144        26: "vertical wind component (m/s) >0 when downwards!",\
145        27: "vertical wind RMS day to day variations (m/s)",\
146        28: "small scale perturbation (gravity wave) (kg/m^3)",\
147        29: "q2: turbulent kinetic energy (m2/s2)",\
148        30: "[not defined]",\
149        31: "thermal IR flux to surface (W/m2)",\
150        32: "solar flux to surface (W/m2)",\
151        33: "thermal IR flux to space (W/m2)",\
152        34: "solar flux reflected to space (W/m2)",\
153        35: "surface CO2 ice layer (kg/m2)",\
154        36: "DOD: Dust column visible optical depth",\
155        37: "Dust mass mixing ratio (kg/kg)",\
156        38: "DOD RMS day to day variations",\
157        39: "DOD total standard deviation over season",\
158        40: "Water vapor column (kg/m2)",\
159        41: "Water vapor vol. mixing ratio (mol/mol)",\
160        42: "Water ice column (kg/m2)",\
161        43: "Water ice mixing ratio (mol/mol)",\
162        44: "O3 ozone vol. mixing ratio (mol/mol)",\
163        45: "[CO2] vol. mixing ratio (mol/mol)",\
164        46: "[O] vol. mixing ratio (mol/mol)",\
165        47: "[N2] vol. mixing ratio (mol/mol)",\
166        48: "[CO] vol. mixing ratio (mol/mol)",\
167        49: "R: Molecular gas constant (J K-1 kg-1)",\
168        50: "Air viscosity estimation (N s m-2)"
169        }
170        if num not in whichfield: myplot.errormess("Incorrect subscript in extvar.")
171
172        dastuff = whichfield[num]
173 
174        if "(K)" in dastuff:      self.fmt="%.0f"
175        elif "(Pa)" in dastuff:   self.fmt="%.1f"
176        elif "(W/m2)" in dastuff: self.fmt="%.0f"
177        elif "(m/s)" in dastuff:  self.fmt="%.1f"
178        else:                     self.fmt="%.2e"
179
180        return dastuff
181
182    def convertlab(self,num):       
183        ## a conversion from text inquiries to extvar numbers. to be completed.
184        if num == "p": num = 91
185        elif num == "rho": num = 92
186        elif num == "t": num = 93
187        elif num == "u": num = 94
188        elif num == "v": num = 95
189        elif num == "tsurf": num = 15
190        elif num == "topo": num = 4
191        elif num == "h": num = 13
192        elif num == "ps": num = 19
193        elif num == "tau": num = 36
194        elif num == "mtot": num = 40
195        elif num == "icetot": num = 42
196        elif num == "ps_ddv": num = 22
197        elif num == "h2ovap": num = 41
198        elif num == "h2oice": num = 43
199        elif num == "cp": num = 8
200        elif num == "rho_ddv": num = 10
201        elif num == "tsurfmx": num = 16
202        elif num == "tsurfmn": num = 17
203        elif num == "lwdown": num = 31
204        elif num == "swdown": num = 32
205        elif num == "lwup": num = 33
206        elif num == "swup": num = 34
207        elif num == "o3": num = 44
208        elif num == "o": num = 46
209        elif num == "co": num = 48
210        elif num == "visc": num = 50
211        elif num == "co2ice": num = 35
212        elif not isinstance(num, np.int): myplot.errormess("field reference not found.")
213        return num
214
215###################
216### One request ###
217###################
218
219    def update(self):
220    # retrieve fields from MCD (call_mcd). more info in fmcd.call_mcd.__doc__
221        ## sanity first
222        self.loct = abs(self.loct)%24
223        if self.locts is not None and self.locte is not None: 
224            self.locts = abs(self.locts)%24
225            self.locte = abs(self.locte)%24
226            if self.locts == self.locte: self.locte = self.locts + 24
227        if self.lat > 90.: self.lat = 90.
228        if self.lat < -90.: self.lat = -90.
229        if self.lats is not None and self.late is not None:
230            if abs(self.lats) > 90.: self.lats = 90.
231            if abs(self.late) > 90.: self.late = 90.
232            if abs(self.lats) < -90.: self.lats = -90.
233            if abs(self.late) < -90.: self.late = -90.
234        ## now MCD request
235        (self.pres, self.dens, self.temp, self.zonwind, self.merwind, \
236         self.meanvar, self.extvar, self.seedout, self.ierr) \
237         = \
238         fmcd.call_mcd(self.zkey,self.xz,self.lon,self.lat,self.hrkey, \
239             self.datekey,self.xdate,self.loct,self.dset,self.dust, \
240             self.perturkey,self.seedin,self.gwlength,self.extvarkey )
241        ## we use the end of extvar (unused) to store meanvar. this is convenient for getextvar(lab)
242        self.extvar[90] = self.pres ; self.extvar[91] = self.dens
243        self.extvar[92] = self.temp ; self.extvar[93] = self.zonwind ; self.extvar[94] = self.merwind
244        ## treat missing values
245        if self.temp == -999: self.extvar[:] = np.NaN ; self.meanvar[:] = np.NaN
246
247    def printset(self):
248    # print main settings
249        print "zkey",self.zkey,"xz",self.xz,"lon",self.lon,"lat",self.lat,"hrkey",self.hrkey, \
250              "xdate",self.xdate,"loct",self.loct,"dust",self.dust
251
252    def getnameset(self):
253    # set a name referring to settings [convenient for databases]
254        strlat = str(self.lat)+str(self.lats)+str(self.late)
255        strlon = str(self.lon)+str(self.lons)+str(self.lone)
256        strxz = str(self.xz)+str(self.xzs)+str(self.xze)
257        strloct = str(self.loct)+str(self.locts)+str(self.locte)
258        name = str(self.zkey)+strxz+strlon+strlat+str(self.hrkey)+str(self.datekey)+str(self.xdate)+strloct+str(self.dust)
259        return name
260
261    def printcoord(self):
262    # print requested space-time coordinates
263        print "LAT",self.lat,"LON",self.lon,"LOCT",self.loct,"XDATE",self.xdate
264
265    def printmeanvar(self):
266    # print mean MCD variables
267        print "Pressure = %5.3f pascals. " % (self.pres)
268        print "Density = %5.3f kilograms per cubic meter. " % (self.dens)
269        print "Temperature = %3.0f kelvins (%4.0f degrees celsius)." % (self.temp,self.temp-273.15)
270        print "Zonal wind = %5.3f meters per second." % (self.zonwind)
271        print "Meridional wind = %5.3f meters per second." % (self.merwind)
272        print "Total horizontal wind = %5.3f meters per second." % ( np.sqrt(self.zonwind**2 + self.merwind**2) )
273
274    def printextvar(self,num):
275    # print extra MCD variables
276        num = self.convertlab(num)
277        dastr = str(self.extvar[num-1])
278        if dastr == "nan":   print "!!!! There is a problem, probably a value is requested below the surface !!!!"
279        else:                print self.getextvarlab(num) + " ..... " + dastr
280
281    def printallextvar(self):
282    # print all extra MCD variables   
283        for i in range(50): self.printextvar(i+1)
284
285    def htmlprinttabextvar(self,tabtodo):
286        self.fixedlt = True ## local time is real local time
287        self.gettitle()
288        print "<hr>"
289        print self.title
290        print "<hr>"
291        print "<ul>"
292        for i in range(len(tabtodo)): print "<li>" ; self.printextvar(tabtodo[i]) ; print "</li>"
293        print "</ul>"
294        print "<hr>"
295        print self.ack
296        print "<hr>"
297        #print "SETTINGS<br />"
298        #self.printcoord()
299        #self.printset()
300
301    def printmcd(self):
302    # 1. call MCD 2. print settings 3. print mean vars
303        self.update()
304        self.printcoord()
305        print "-------------------------------------------"
306        self.printmeanvar()
307
308########################
309### Several requests ###
310########################
311
312    def prepare(self,ndx=None,ndy=None):
313    ### prepare I/O arrays for 1d slices
314      if ndx is None:  print "No dimension in prepare. Exit. Set at least ndx." ; exit()
315      else:            self.xcoord = np.ones(ndx)
316      if ndy is None:  dashape = (ndx)     ; dashapemean = (ndx,6)     ; dashapeext = (ndx,101)     ; self.ycoord = None
317      else:            dashape = (ndx,ndy) ; dashapemean = (ndx,ndy,6) ; dashapeext = (ndx,ndy,101) ; self.ycoord = np.ones(ndy)
318      self.prestab = np.ones(dashape) ; self.denstab = np.ones(dashape) ; self.temptab = np.ones(dashape)
319      self.zonwindtab = np.ones(dashape) ; self.merwindtab = np.ones(dashape) 
320      self.meanvartab = np.ones(dashapemean) ; self.extvartab = np.ones(dashapeext)
321
322    def getextvar(self,num):
323    ### get a given var in extvartab
324      try: field=self.extvartab[:,:,num] 
325      except: field=self.extvartab[:,num]
326      return field
327
328    def definefield(self,choice):
329    ### for analysis or plot purposes, set field and field label from user-defined choice
330      choice = self.convertlab(choice)
331      field = self.getextvar(choice); fieldlab = self.getextvarlab(choice)
332      ## fix for possibly slightly negative tracers
333      if "(mol/mol)" in fieldlab or "(kg/kg)" in fieldlab or "(kg/m2)" in fieldlab or "(W/m2)" in fieldlab:
334         ind = np.where(field < 1.e-30)
335         if ind != -1: field[ind] = 1.e-30  ## 0 does not work everywhere.
336      return field,fieldlab
337
338    def ininterv(self,dstart,dend,nd,start=None,end=None,yaxis=False,vertcoord=False):
339    ### user-defined start and end are used to create xcoord (or ycoord) vector
340      if start is not None and end is not None:  first, second = self.correctbounds(start,end,vertcoord)
341      else:                                      first, second = self.correctbounds(dstart,dend,vertcoord) 
342      if self.zkey != 4 or not vertcoord:   tabtab = np.linspace(first,second,nd)
343      else:                                 tabtab = np.logspace(first,second,nd)
344      if not yaxis:      self.xcoord = tabtab
345      else:              self.ycoord = tabtab
346
347    def correctbounds(self,start,end,vertcoord):
348      if self.zkey != 4 or not vertcoord:
349        # regular altitudes
350        if start > end: first = end ; second = start
351        else:           first = start ; second = end
352      else:
353        # pressure: reversed avis
354        if start < end: first = np.log10(end) ; second = np.log10(start)
355        else:           first = np.log10(start) ; second = np.log10(end)
356      return first, second
357
358    def vertlabel(self):
359      if self.zkey == 1:   self.xlabel = "radius from centre of planet (m)"
360      elif self.zkey == 2: self.xlabel = "height above areoid (m) (MOLA zero datum)"
361      elif self.zkey == 3: self.xlabel = "height above surface (m)"
362      elif self.zkey == 4: self.xlabel = "pressure level (Pa)"
363      elif self.zkey == 5: self.xlabel = "altitude above mean Mars Radius(=3396000m) (m)"
364
365    def vertunits(self):
366      if self.zkey == 1:   self.vunits = "m CP"
367      elif self.zkey == 2: self.vunits = "m AMR"
368      elif self.zkey == 3: self.vunits = "m ALS"
369      elif self.zkey == 4: self.vunits = "Pa"
370      elif self.zkey == 5: self.vunits = "m AMMRad"
371
372    def vertaxis(self,number,yaxis=False):
373      if self.zkey == 2:   self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
374      elif self.zkey == 3: self.ininterv(0.,120000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
375      elif self.zkey == 5: self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
376      elif self.zkey == 4: self.ininterv(1000.,0.001,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
377      elif self.zkey == 1: self.ininterv(3396000,3596000,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True)
378
379###################
380### 1D analysis ###
381###################
382
383    def put1d(self,i):
384    ## fill in subscript i in output arrays
385    ## (arrays must have been correctly defined through prepare)
386      if self.prestab is None:  myplot.errormess("arrays must be prepared first through self.prepare")
387      self.prestab[i] = self.pres ; self.denstab[i] = self.dens ; self.temptab[i] = self.temp
388      self.zonwindtab[i] = self.zonwind ; self.merwindtab[i] = self.merwind
389      self.meanvartab[i,1:5] = self.meanvar[0:4]  ## note: var numbering according to MCD manual is kept
390      self.extvartab[i,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
391
392    def diurnal(self,nd=13):
393    ### retrieve a local time slice
394      self.fixedlt = True  ## local time is real local time
395      save = self.loct
396      self.xlabel = "Local time (Martian hour)"
397      self.prepare(ndx=nd) ; self.ininterv(0.,24.,nd,start=self.locts,end=self.locte) 
398      for i in range(nd): self.loct = self.xcoord[i] ; self.update() ; self.put1d(i)
399      self.loct = save
400
401    def zonal(self,nd=37):
402    ### retrieve a longitude slice
403      save = self.lon
404      self.xlabel = "East longitude (degrees)"
405      self.prepare(ndx=nd) ; self.ininterv(-180.,180.,nd,start=self.lons,end=self.lone)
406      if not self.fixedlt: umst = self.loct
407      for i in range(nd): 
408          self.lon = self.xcoord[i]
409          if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24
410          self.update() ; self.put1d(i)
411      self.lon = save
412
413    def meridional(self,nd=19):
414    ### retrieve a latitude slice
415      self.fixedlt = True  ## local time is real local time
416      save = self.lat
417      self.xlabel = "North latitude (degrees)"
418      self.prepare(ndx=nd) ; self.ininterv(-90.,90.,nd,start=self.lats,end=self.late)
419      for i in range(nd): self.lat = self.xcoord[i] ; self.update() ; self.put1d(i)
420      self.lat = save
421
422    def profile(self,nd=20,tabperso=None):
423    ### retrieve an altitude slice (profile)
424      self.fixedlt = True  ## local time is real local time
425      save = self.xz
426      self.vertlabel()
427      self.vertplot = True
428      if tabperso is not None: nd = len(tabperso)
429      correct = False
430      self.prepare(ndx=nd) ; self.vertaxis(nd)
431      if tabperso is not None: self.xcoord = tabperso
432      for i in range(nd): self.xz = self.xcoord[i] ; self.update() ; self.put1d(i)
433      self.xz = save
434
435    def seasonal(self,nd=12):
436    ### retrieve a seasonal slice
437      save = self.xdate
438      self.xlabel = "Areocentric longitude (degrees)"
439      self.prepare(ndx=nd) ; self.ininterv(0.,360.,nd,start=self.xdates,end=self.xdatee)
440      for i in range(nd): self.xdate = self.xcoord[i] ; self.update() ; self.put1d(i)
441      self.xdate = save
442
443    def getascii(self,tabtodo,filename="output.txt"):
444    ### print out values in an ascii file
445      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
446      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
447      asciifile = open(filename, "w")
448      for i in range(len(tabtodo)): 
449          (field, fieldlab) = self.definefield(tabtodo[i])
450          self.gettitle(oneline=True)
451          asciifile.write("### " + self.title + "\n")
452          asciifile.write("### " + self.ack + "\n")
453          asciifile.write("### Column 1 is " + self.xlabel + "\n")
454          asciifile.write("### Column 2 is " + fieldlab + "\n")
455          for ix in range(len(self.xcoord)):
456              asciifile.write("%15.5e%15.5e\n" % ( self.xcoord[ix], field[ix] ) )
457      asciifile.close()
458      return 
459
460    def makeplot1d(self,choice):
461    ### one 1D plot is created for the user-defined variable in choice.
462      (field, fieldlab) = self.definefield(choice)
463      if not self.vertplot:  absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel
464      else:                  ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel
465      mpl.plot(absc,ordo,'-bo') ; mpl.ylabel(ordolab) ; mpl.xlabel(absclab) #; mpl.xticks(query.xcoord)
466      if self.zkey == 4: mpl.semilogy() ; ax = mpl.gca() ; ax.set_ylim(ax.get_ylim()[::-1])
467      mpl.figtext(0.5, 0.01, self.ack, ha='center')
468
469    def plot1d(self,tabtodo):
470    ### complete 1D figure with possible multiplots
471      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
472      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
473      fig = mpl.figure() ; subv,subh = myplot.definesubplot( len(tabtodo) , fig ) 
474      for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1).grid(True, linestyle=':', color='grey') ; self.makeplot1d(tabtodo[i])
475
476    def htmlplot1d(self,tabtodo,figname="temp.png",title=""):
477    ### complete 1D figure with possible multiplots
478    ### added in 09/2012 for online MCD
479    ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
480      from matplotlib.figure import Figure
481      from matplotlib.backends.backend_agg import FigureCanvasAgg
482      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
483      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
484
485      howmanyplots = len(tabtodo)
486      if howmanyplots == 1: fig = Figure(figsize=(16,8))
487      elif howmanyplots == 2: fig = Figure(figsize=(8,8))
488      elif howmanyplots == 3: fig = Figure(figsize=(8,16))
489      elif howmanyplots == 4: fig = Figure(figsize=(16,8))
490
491      subv,subh = myplot.definesubplot( len(tabtodo) , fig )
492      for i in range(len(tabtodo)):
493        yeah = fig.add_subplot(subv,subh,i+1) #.grid(True, linestyle=':', color='grey')
494        choice = tabtodo[i]
495        (field, fieldlab) = self.definefield(choice)
496        if not self.vertplot:  absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel
497        else:                  ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel
498        yeah.plot(absc,ordo,'-bo') #; mpl.xticks(query.xcoord)
499        ax = fig.gca() ; ax.set_ylabel(ordolab) ; ax.set_xlabel(absclab)
500
501        if self.xzs is not None and self.zkey == 4: ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1])
502
503        if self.lats is not None:      ax.set_xticks(np.arange(-90,91,15)) ; ax.set_xbound(lower=self.lats, upper=self.late)
504        elif self.lons is not None:    ax.set_xticks(np.arange(-360,361,30)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
505        elif self.locts is not None:   ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte)
506
507        ax.grid(True, linestyle=':', color='grey')
508
509      self.gettitle()
510      fig.text(0.5, 0.95, self.title, ha='center')
511      fig.text(0.5, 0.01, self.ack, ha='center')
512      canvas = FigureCanvasAgg(fig)
513      # The size * the dpi gives the final image size
514      #   a4"x4" image * 80 dpi ==> 320x320 pixel image
515      canvas.print_figure(figname, dpi=80)
516
517###################
518### 2D analysis ###
519###################
520
521    def latlon(self,ndx=37,ndy=19):
522    ### retrieve a latitude/longitude slice
523    ### default is: local time is not fixed. user-defined local time is at longitude 0.
524      save1 = self.lon ; save2 = self.lat ; save3 = self.loct
525      self.xlabel = "East longitude (degrees)" ; self.ylabel = "North latitude (degrees)"
526      self.prepare(ndx=ndx,ndy=ndy)
527      self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone)
528      self.ininterv(-90.,  90.,ndy,start=self.lats,end=self.late,yaxis=True)
529      if not self.fixedlt: umst = self.loct
530      for i in range(ndx):
531       for j in range(ndy):
532         self.lon = self.xcoord[i] ; self.lat = self.ycoord[j]
533         if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24
534         self.update() ; self.put2d(i,j)
535      if not self.fixedlt: self.loct = umst
536      self.lon = save1 ; self.lat = save2 ; self.loct = save3
537
538    def secalt(self,ndx=37,ndy=20,typex="lat"):
539    ### retrieve a coordinate/altitude slice
540      save1 = self.lon ; save2 = self.xz ; save3 = self.loct ; save4 = self.lat
541      self.prepare(ndx=ndx,ndy=ndy)
542      self.vertlabel() ; self.ylabel = self.xlabel
543      self.vertaxis(ndy,yaxis=True)
544      if "lat" in typex:
545          self.xlabel = "North latitude (degrees)"
546          self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late)
547      elif typex == "lon":
548          self.xlabel = "East longitude (degrees)"
549          self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone)
550      if not self.fixedlt: umst = self.loct
551      for i in range(ndx):
552       for j in range(ndy):
553         if typex == "lat":   self.lat = self.xcoord[i]
554         elif typex == "lon": self.lon = self.xcoord[i]
555         self.xz = self.ycoord[j]
556         if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24
557         self.update() ; self.put2d(i,j)
558      if not self.fixedlt: self.loct = umst
559      self.lon = save1 ; self.xz = save2 ; self.loct = save3 ; self.lat = save4
560
561    def zonalmean(self,ndx=37,ndy=20,ndmean=32):
562    ### retrieve a zonalmean lat/altitude slice
563      self.fixedlt = False
564      save1 = self.lon ; save2 = self.xz ; save3 = self.loct ; save4 = self.lat
565      self.prepare(ndx=ndx,ndy=ndy)
566      self.vertlabel() ; self.ylabel = self.xlabel
567      self.vertaxis(ndy,yaxis=True)
568      self.xlabel = "North latitude (degrees)"
569      self.ininterv(-180.,180.,ndmean)
570      coordmean = self.xcoord
571      self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late)
572      umst = self.loct #fixedlt false for this case
573      for i in range(ndx):
574       self.lat = self.xcoord[i]
575       for j in range(ndy):
576        self.xz = self.ycoord[j]
577        meanpres = 0. ; meandens = 0. ; meantemp = 0. ; meanzonwind = 0. ; meanmerwind = 0. ; meanmeanvar = np.zeros(5) ; meanextvar = np.zeros(100)       
578        for m in range(ndmean):
579           self.lon = coordmean[m]
580           self.loct = (umst + self.lon/15.) % 24 #fixedlt false for this case
581           self.update() 
582           meanpres = meanpres + self.pres/float(ndmean) ; meandens = meandens + self.dens/float(ndmean) ; meantemp = meantemp + self.temp/float(ndmean)
583           meanzonwind = meanzonwind + self.zonwind/float(ndmean) ; meanmerwind = meanmerwind + self.merwind/float(ndmean)
584           meanmeanvar = meanmeanvar + self.meanvar/float(ndmean) ; meanextvar = meanextvar + self.extvar/float(ndmean)
585        self.pres=meanpres ; self.dens=meandens ; self.temp=meantemp ; self.zonwind=meanzonwind ; self.merwind=meanmerwind
586        self.meanvar=meanmeanvar ; self.extvar=meanextvar
587        self.put2d(i,j)
588      self.loct = umst #fixedlt false for this case
589      self.lon = save1 ; self.xz = save2 ; self.loct = save3 ; self.lat = save4
590
591    def hovmoller(self,ndtime=25,ndcoord=20,typex="lat"):
592    ### retrieve a time/other coordinate slice
593      save1 = self.lat ; save2 = self.xz ; save3 = self.loct ; save4 = self.lon
594      if typex == "lat": 
595          ndx = ndcoord ; self.xlabel = "North latitude (degrees)" 
596          ndy = ndtime ; self.ylabel = "Local time (Martian hour)"
597          self.prepare(ndx=ndx,ndy=ndy)
598          self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late)
599          self.ininterv(0.,24.,ndy,start=self.locts,end=self.locte,yaxis=True)
600      elif typex == "lon":
601          ndx = ndcoord ; self.xlabel = "East longitude (degrees)"
602          ndy = ndtime ; self.ylabel = "Local time (Martian hour)"
603          self.prepare(ndx=ndx,ndy=ndy)
604          self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone)
605          self.ininterv(0.,24.,ndy,start=self.locts,end=self.locte,yaxis=True)
606      elif typex == "alt":
607          ndy = ndcoord ; self.vertlabel() ; self.ylabel = self.xlabel
608          ndx = ndtime ; self.xlabel = "Local time (Martian hour)"
609          self.prepare(ndx=ndx,ndy=ndy)
610          self.vertaxis(ndy,yaxis=True)
611          self.ininterv(0.,24.,ndx,start=self.locts,end=self.locte)
612      for i in range(ndx):
613       for j in range(ndy):
614         if typex == "lat":   self.lat = self.xcoord[i] ; self.loct = self.ycoord[j]
615         elif typex == "lon": self.lon = self.xcoord[i] ; self.loct = self.ycoord[j]
616         elif typex == "alt": self.xz = self.ycoord[j] ; self.loct = self.xcoord[i]
617         self.update() ; self.put2d(i,j)
618      self.lat = save1 ; self.xz = save2 ; self.loct = save3 ; self.lon = save4
619
620    def put2d(self,i,j):
621    ## fill in subscript i,j in output arrays
622    ## (arrays must have been correctly defined through prepare)
623      if self.prestab is None:  myplot.errormess("arrays must be prepared first through self.prepare")
624      self.prestab[i,j] = self.pres ; self.denstab[i,j] = self.dens ; self.temptab[i,j] = self.temp
625      self.zonwindtab[i,j] = self.zonwind ; self.merwindtab[i,j] = self.merwind
626      self.meanvartab[i,j,1:5] = self.meanvar[0:4]  ## note: var numbering according to MCD manual is kept
627      self.extvartab[i,j,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
628
629    def makemap2d(self,choice,incwind=False,proj="cyl"):
630    ### one 2D map is created for the user-defined variable in choice.
631      self.latlon() ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d)
632      if choice == "wind" or incwind:
633          (windx, fieldlabwx) = self.definefield("u")
634          (windy, fieldlabwy) = self.definefield("v")
635      if choice == "wind":
636          field = np.sqrt(windx*windx + windy*windy)
637          fieldlab = "Horizontal wind speed (m/s)"
638      else:   
639          (field, fieldlab) = self.definefield(choice)
640      if incwind:   myplot.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj,vecx=windx,vecy=windy) #,stride=1)
641      else:         myplot.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj)
642      mpl.figtext(0.5, 0.0, self.ack, ha='center')
643
644    def map2d(self,tabtodo,incwind=False,proj="cyl"):
645    ### complete 2D figure with possible multiplots
646      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
647      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
648      fig = mpl.figure()
649      subv,subh = myplot.definesubplot( len(tabtodo) , fig ) 
650      for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1) ; self.makemap2d(tabtodo[i],incwind=incwind,proj=proj)
651
652    def htmlmap2d(self,tabtodo,incwind=False,figname="temp.png",back="zMOL"):
653    ### complete 2D figure with possible multiplots
654    ### added in 09/2012 for online MCD
655    ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
656      from matplotlib.figure import Figure
657      from matplotlib.backends.backend_agg import FigureCanvasAgg
658      from matplotlib.cm import get_cmap
659      from matplotlib import rcParams
660      #from mpl_toolkits.basemap import Basemap # does not work
661      from Scientific.IO import NetCDF
662
663      filename = "/home/marshttp/surface.nc"
664      zefile = NetCDF.NetCDFFile(filename, 'r') 
665      fieldc = zefile.variables[back]
666      yc = zefile.variables['latitude']
667      xc = zefile.variables['longitude']
668
669      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
670      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
671
672      howmanyplots = len(tabtodo)
673      if howmanyplots == 1: fig = Figure(figsize=(16,8)) 
674      elif howmanyplots == 2: fig = Figure(figsize=(8,8)) 
675      elif howmanyplots == 3: fig = Figure(figsize=(8,16)) 
676      elif howmanyplots == 4: fig = Figure(figsize=(16,8)) 
677
678      subv,subh = myplot.definesubplot( len(tabtodo) , fig )
679
680      for i in range(len(tabtodo)):
681        yeah = fig.add_subplot(subv,subh,i+1)
682        choice = tabtodo[i]
683        self.latlon(ndx=64,ndy=48) 
684        ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d)
685        (field, fieldlab) = self.definefield(choice)
686        if incwind: (windx, fieldlabwx) = self.definefield("u") ; (windy, fieldlabwy) = self.definefield("v")
687
688        proj="moll" ; colorb= self.colorm ; ndiv=20 ; zeback="molabw" ; trans=1.0 #0.6
689        vecx=None ; vecy=None ; stride=2
690        lon = self.xcoord
691        lat = self.ycoord
692       
693        #[lon2d,lat2d] = np.meshgrid(lon,lat)
694        ##### define projection and background. define x and y given the projection
695        ##[wlon,wlat] = myplot.latinterv()
696        ##yeahm = myplot.define_proj(proj,wlon,wlat,back=zeback,blat=None,blon=None)
697        ##x, y = yeahm(lon2d, lat2d)
698        #map = Basemap(projection='ortho',lat_0=45,lon_0=-100)
699        #x, y = map(lon2d, lat2d)
700
701        #### TEMP
702        x = lon ; y = lat
703
704        ## define field. bound field.
705        what_I_plot = np.transpose(field)
706        zevmin, zevmax = myplot.calculate_bounds(what_I_plot)  ## vmin=min(what_I_plot_frame), vmax=max(what_I_plot_frame))
707        what_I_plot = myplot.bounds(what_I_plot,zevmin,zevmax)
708        ## define contour field levels. define color palette
709        ticks = ndiv + 1
710        zelevels = np.linspace(zevmin,zevmax,ticks)
711        palette = get_cmap(name=colorb)
712
713        # You can set negative contours to be solid instead of dashed:
714        rcParams['contour.negative_linestyle'] = 'solid'
715        ## contours topo
716        zelevc = np.linspace(-9.,20.,11)
717        yeah.contour( xc, yc, fieldc, zelevc, colors='black',linewidths = 0.4)
718        yeah.contour( np.array(xc) + 360., yc, fieldc, zelevc, colors='black',linewidths = 0.4)
719        yeah.contour( np.array(xc) - 360., yc, fieldc, zelevc, colors='black',linewidths = 0.4)
720        # contour field
721        c = yeah.contourf( x, y, what_I_plot, zelevels, cmap = palette, alpha = trans )
722        clb = Figure.colorbar(fig,c,orientation='vertical',format=self.fmt,ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])))
723        clb.set_label(fieldlab)
724        if incwind:
725          [x2d,y2d] = np.meshgrid(x,y)
726          yeah.quiver(x2d,y2d,np.transpose(windx),np.transpose(windy))
727        ax = fig.gca() ; ax.set_ylabel("Latitude") ; ax.set_xlabel("Longitude")
728        ax.set_xticks(np.arange(-360,361,45)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
729        ax.set_yticks(np.arange(-90,91,30)) ; ax.set_ybound(lower=self.lats, upper=self.late)
730      self.gettitle()
731      fig.text(0.5, 0.95, self.title, ha='center')
732      fig.text(0.5, 0.01, self.ack, ha='center')
733      canvas = FigureCanvasAgg(fig)
734      # The size * the dpi gives the final image size
735      #   a4"x4" image * 80 dpi ==> 320x320 pixel image
736      canvas.print_figure(figname, dpi=80)
737
738    def htmlplot2d(self,tabtodo,figname="temp.png"):
739    ### complete 2D figure with possible multiplots
740    ### added in 10/2012 for online MCD
741    ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html
742      from matplotlib.figure import Figure
743      from matplotlib.backends.backend_agg import FigureCanvasAgg
744      from matplotlib.cm import get_cmap
745      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
746      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
747
748      howmanyplots = len(tabtodo)
749      if howmanyplots == 1: fig = Figure(figsize=(16,8))
750      elif howmanyplots == 2: fig = Figure(figsize=(8,8))
751      elif howmanyplots == 3: fig = Figure(figsize=(8,16))
752      elif howmanyplots == 4: fig = Figure(figsize=(16,8))
753
754      subv,subh = myplot.definesubplot( len(tabtodo) , fig )
755
756      for i in range(len(tabtodo)):
757        yeah = fig.add_subplot(subv,subh,i+1)
758        choice = tabtodo[i]
759
760        if self.lons is not None:   
761           if self.locts is None:  self.secalt(ndx=64,ndy=35,typex="lon")
762           else:                   self.hovmoller(ndcoord=64,typex="lon")
763        elif self.lats is not None: 
764           if self.locts is None: 
765               if self.zonmean:   self.zonalmean()
766               else:         self.secalt(ndx=48,ndy=35,typex="lat")
767           else:                   self.hovmoller(ndcoord=48,typex="lat")
768        else:
769           self.hovmoller(ndcoord=35,typex="alt")
770
771        (field, fieldlab) = self.definefield(choice)
772
773        colorb=self.colorm ; ndiv=20 
774
775        ## define field. bound field.
776        what_I_plot = np.transpose(field)
777        zevmin, zevmax = myplot.calculate_bounds(what_I_plot)  ## vmin=min(what_I_plot_frame), vmax=max(what_I_plot_frame))
778        what_I_plot = myplot.bounds(what_I_plot,zevmin,zevmax)
779        ## define contour field levels. define color palette
780        ticks = ndiv + 1
781        zelevels = np.linspace(zevmin,zevmax,ticks)
782        palette = get_cmap(name=colorb)
783        # contour field
784        c = yeah.contourf( self.xcoord, self.ycoord, what_I_plot, zelevels, cmap = palette )
785        clb = Figure.colorbar(fig,c,orientation='vertical',format=self.fmt,ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])))
786        clb.set_label(fieldlab)
787        ax = fig.gca() ; ax.set_ylabel(self.ylabel) ; ax.set_xlabel(self.xlabel)
788
789        if self.lons is not None:   ax.set_xticks(np.arange(-360,361,45)) ; ax.set_xbound(lower=self.lons, upper=self.lone)
790        elif self.lats is not None: ax.set_xticks(np.arange(-90,91,30)) ; ax.set_xbound(lower=self.lats, upper=self.late)
791
792        if self.locts is not None: 
793            if self.xzs is not None: ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte)
794            else:                    ax.set_yticks(np.arange(0,26,2)) ; ax.set_ybound(lower=self.locts, upper=self.locte)
795
796        if self.zkey == 4 and self.xzs is not None: 
797            ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1])
798        else:
799            #ax.set_yticks(np.arange(self.xzs,self.xze,10000.)) ;
800            ax.set_ybound(lower=self.xzs, upper=self.xze)
801
802      self.gettitle()
803      fig.text(0.5, 0.95, self.title, ha='center')
804      fig.text(0.5, 0.01, self.ack, ha='center')
805      canvas = FigureCanvasAgg(fig)
806      # The size * the dpi gives the final image size
807      #   a4"x4" image * 80 dpi ==> 320x320 pixel image
808      canvas.print_figure(figname, dpi=80)
809
810
811    ### TODO: makeplot2d, plot2d, passer plot settings
812
Note: See TracBrowser for help on using the repository browser.