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

Last change on this file since 639 was 639, checked in by aslmd, 13 years ago

UTIL PYTHON : Interfacing MCD with python. (Also a toy web server in proto; for the moment, do not use nor modify).

  • Property svn:executable set to *
File size: 14.5 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
14class mcd:
15
16    def __repr__(self):
17    # print out a help string when help is invoked on the object
18        whatprint = 'MCD object. \"help(mcd)\" for more information\n'
19        return whatprint
20
21########################
22### Default settings ###
23########################
24
25    def __init__(self):
26    # default settings
27        ## 0. general stuff
28        self.name      = "MCD v4.3 output"
29        self.dset      = '/home/aymeric/Science/MCD_v4.3/data/'
30        ## 1. spatio-temporal coordinates
31        self.lat       = 0.
32        self.lon       = 0.
33        self.loct      = 0.
34        self.xdate     = 0.  # see datekey
35        self.xz        = 10. # see zkey
36        ## 1bis. related settings
37        self.zkey      = 3  # specify that xz is the altitude above surface (m)
38        self.datekey   = 1  # 0 = "Earth time": xdate is given in Julian days (localtime must be set to zero)
39                            # 1 = "Mars date": xdate is the value of Ls
40        ## 2. climatological options
41        self.dust      = 2  #our best guess MY24 scenario, with solar average conditions
42        self.hrkey     = 1  #set high resolution mode on (hrkey=0 to set high resolution off)
43        ## 3. additional settings for advanced use
44        self.extvarkey = 1  #extra output variables (1: yes, 0: no)
45        self.perturkey = 0  #integer perturkey ! perturbation type (0: none)
46        self.seedin    = 1  #random number generator seed (unused if perturkey=0)
47        self.gwlength  = 0. #gravity Wave wavelength (unused if perturkey=0)
48        ## outputs. just to define attributes.
49        ## --> in update
50        self.pres = None ; self.dens = None ; self.temp = None ; self.zonwind = None ; self.merwind = None ; self.meanvar = None ; self.extvar = None
51        self.seedout = None ; self.ierr = None
52        ## --> in prepare
53        self.xcoord = None ; self.ycoord = None
54        self.prestab = None ; self.denstab = None ; self.temptab = None 
55        self.zonwindtab = None ; self.merwindtab = None ; self.meanvartab = None ; self.extvartab = None
56
57    def viking1(self): self.name = "Viking 1 site. MCD v4.3 output" ; self.lat = 22.48 ; self.lon = -49.97 ; self.xdate = 97.
58    def viking2(self): self.name = "Viking 2 site. MCD v4.3 output" ; self.lat = 47.97 ; self.lon = -225.74 ; self.xdate = 117.6
59
60    def getextvarlab(self,num):
61        whichfield = { \
62        1: "Radial distance from planet center (m)",\
63        2: "Altitude above areoid (Mars geoid) (m)",\
64        3: "Altitude above local surface (m)",\
65        4: "orographic height (m) (surface altitude above areoid)",\
66        5: "Ls, solar longitude of Mars (deg)",\
67        6: "LST local true solar time (hrs)",\
68        7: "Universal solar time (LST at lon=0) (hrs)",\
69        8: "Air heat capacity Cp (J kg-1 K-1)",\
70        9: "gamma=Cp/Cv Ratio of specific heats",\
71        10: "density RMS day to day variations (kg/m^3)",\
72        11: "[not defined]",\
73        12: "[not defined]",\
74        13: "scale height H(p) (m)",\
75        14: "GCM orography (m)",\
76        15: "surface temperature (K)",\
77        16: "daily maximum mean surface temperature (K)",\
78        17: "daily minimum mean surface temperature (K)",\
79        18: "surf. temperature RMS day to day variations (K)",\
80        19: "surface pressure (high resolution if hireskey=1)",\
81        20: "GCM surface pressure (Pa)",\
82        21: "atmospheric pressure RMS day to day variations (Pa)",\
83        22: "surface pressure RMS day to day variations (Pa)",\
84        23: "temperature RMS day to day variations (K)",\
85        24: "zonal wind RMS day to day variations (m/s)",\
86        25: "meridional wind RMS day to day variations (m/s)",\
87        26: "vertical wind component (m/s) >0 when downwards!",\
88        27: "vertical wind RMS day to day variations (m/s)",\
89        28: "small scale perturbation (gravity wave) (kg/m^3)",\
90        29: "q2: turbulent kinetic energy (m2/s2)",\
91        30: "[not defined]",\
92        31: "thermal IR flux to surface (W/m2)",\
93        32: "solar flux to surface (W/m2)",\
94        33: "thermal IR flux to space (W/m2)",\
95        34: "solar flux reflected to space (W/m2)",\
96        35: "surface CO2 ice layer (kg/m2)",\
97        36: "DOD: Dust column visible optical depth",\
98        37: "Dust mass mixing ratio (kg/kg)",\
99        38: "DOD RMS day to day variations",\
100        39: "DOD total standard deviation over season",\
101        40: "Water vapor column (kg/m2)",\
102        41: "Water vapor vol. mixing ratio (mol/mol)",\
103        42: "Water ice column (kg/m2)",\
104        43: "Water ice mixing ratio (mol/mol)",\
105        44: "O3 ozone vol. mixing ratio (mol/mol)",\
106        45: "[CO2] vol. mixing ratio (mol/mol)",\
107        46: "[O] vol. mixing ratio (mol/mol)",\
108        47: "[N2] vol. mixing ratio (mol/mol)",\
109        48: "[CO] vol. mixing ratio (mol/mol)",\
110        49: "R: Molecular gas constant (J K-1 kg-1)",\
111        50: "Air viscosity estimation (N s m-2)"
112        }
113        if num not in whichfield: errormess("Incorrect subscript in extvar.")
114        return whichfield[num]
115
116###################
117### One request ###
118###################
119
120    def update(self):
121    # retrieve fields from MCD (call_mcd). more info in fmcd.call_mcd.__doc__
122        (self.pres, self.dens, self.temp, self.zonwind, self.merwind, \
123         self.meanvar, self.extvar, self.seedout, self.ierr) \
124         = \
125         fmcd.call_mcd(self.zkey,self.xz,self.lon,self.lat,self.hrkey, \
126             self.datekey,self.xdate,self.loct,self.dset,self.dust, \
127             self.perturkey,self.seedin,self.gwlength,self.extvarkey )
128
129    def printset(self):
130    # print main settings
131        print "zkey",self.zkey,"xz",self.xz,"lon",self.lon,"lat",self.lat,"hrkey",self.hrkey, \
132              "xdate",self.xdate,"loct",self.loct,"dust",self.dust
133
134    def getnameset(self):
135    # set a name referring to settings [convenient for databases]
136        name = str(self.zkey)+str(self.xz)+str(self.lon)+str(self.lat)+str(self.hrkey)+str(self.datekey)+str(self.xdate)+str(self.loct)+str(self.dust)
137        return name
138
139    def printcoord(self):
140    # print requested space-time coordinates
141        print "----------------------------------------------------------------"
142        print "LAT",self.lat,"LON",self.lon,"LOCT",self.loct,"XDATE",self.xdate
143        print "----------------------------------------------------------------"
144
145    def printmeanvar(self):
146    # print mean MCD variables
147        print "Pressure = %5.3f pascals. " % (self.pres)
148        print "Density = %5.3f kilograms per cubic meter. " % (self.dens)
149        print "Temperature = %3.0f kelvins (%4.0f degrees celsius)." % (self.temp,self.temp-273.15)
150        print "Zonal wind = %5.3f meters per second." % (self.zonwind)
151        print "Meridional wind = %5.3f meters per second." % (self.merwind)
152
153    def printextvar(self,num):
154    # print extra MCD variables
155        print self.getextvarlab(num) + " ---> " + str(self.extvar[num-1])
156
157    def printallextvar(self):
158    # print all extra MCD variables   
159        for i in range(50): self.printextvar(i+1)
160
161    def printmcd(self):
162    # 1. call MCD 2. print settings 3. print mean vars
163        self.update()
164        self.printcoord()
165        self.printmeanvar()
166
167########################
168### Several requests ###
169########################
170
171    def prepare(self,ndx=None,ndy=None):
172    ### prepare I/O arrays for 1d slices
173      if ndx is None:  print "No dimension in prepare. Exit. Set at least ndx." ; exit()
174      else:            self.xcoord = np.ones(ndx)
175      if ndy is None:  dashape = (ndx)     ; dashapemean = (ndx,6)     ; dashapeext = (ndx,101)     ; self.ycoord = None
176      else:            dashape = (ndx,ndy) ; dashapemean = (ndx,ndy,6) ; dashapeext = (ndx,ndy,101) ; self.ycoord = np.ones(ndy)
177      self.prestab = np.ones(dashape) ; self.denstab = np.ones(dashape) ; self.temptab = np.ones(dashape)
178      self.zonwindtab = np.ones(dashape) ; self.merwindtab = np.ones(dashape) 
179      self.meanvartab = np.ones(dashapemean) ; self.extvartab = np.ones(dashapeext)
180
181    def getextvar(self,num):
182    ### get a given var in extvartab
183      try: field=self.extvartab[:,:,num] 
184      except: field=self.extvartab[:,num]
185      return field
186
187    def definefield(self,choice):
188    ### for analysis or plot purposes, set field and field label from user-defined choice
189    ### --- choice can be a MCD number for extvar
190      if isinstance(choice, np.int):    field = self.getextvar(choice); fieldlab = self.getextvarlab(choice)
191      else:
192       if choice == "t":        field = self.temptab ; fieldlab="Temperature (K)"
193       elif choice == "p":      field = self.prestab ; fieldlab="Pressure (Pa)"
194       elif choice == "rho":    field = self.denstab ; fieldlab="Density (kg/m3)"
195       elif choice == "u":      field = self.zonwindtab ; fieldlab="W-E wind component (m/s)"
196       elif choice == "v":      field = self.merwindtab ; fieldlab="S-N wind component (m/s)"
197       elif choice == "tsurf":  field = self.getextvar(15); fieldlab="Surface temperature (K)"
198       elif choice == "topo":   field = self.getextvar(4) ; fieldlab="Topography (m)"
199       elif choice == "h":      field = self.getextvar(13); fieldlab = "Scale height (m)"
200       elif choice == "ps":     field = self.getextvar(19); fieldlab = "Surface pressure (Pa)"
201       elif choice == "olr":    field = self.getextvar(33); fieldlab = "Outgoing longwave radiation (W/m2)"
202       elif choice == "tau":    field = self.getextvar(36); fieldlab = "Dust optical depth"
203       elif choice == "mtot":   field = self.getextvar(40); fieldlab = "Water vapor column (kg/m2)"
204       elif choice == "icetot": field = self.getextvar(42); fieldlab = "Water ice column (kg/m2)"
205       elif choice == "ps_ddv": field = self.getextvar(22); fieldlab = "Surface pressure RMS day to day variations (Pa)"
206       else:                    errormess("field reference not found.")
207      return field,fieldlab
208
209###################
210### 1D analysis ###
211###################
212
213    def put1d(self,i):
214    ## fill in subscript i in output arrays
215    ## (arrays must have been correctly defined through prepare)
216      if self.prestab is None:  errormess("arrays must be prepared first through self.prepare")
217      self.prestab[i] = self.pres ; self.denstab[i] = self.dens ; self.temptab[i] = self.temp
218      self.zonwindtab[i] = self.zonwind ; self.merwindtab[i] = self.merwind
219      self.meanvartab[i,1:5] = self.meanvar[0:4]  ## note: var numbering according to MCD manual is kept
220      self.extvartab[i,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
221
222    def diurnal(self,nd=13,start=0.,end=24.):
223    ### retrieve a local time slice
224      self.xlabel = "Local time (Martian hour)"
225      self.prepare(ndx=nd) ; self.xcoord = np.linspace(start,end,nd)
226      for i in range(nd): self.loct = self.xcoord[i] ; self.update() ; self.put1d(i)
227
228    def zonal(self,nd=37,start=-180.,end=180.):
229    ### retrieve a longitude slice
230      self.xlabel = "East longitude (degrees)"
231      self.prepare(ndx=nd) ; self.xcoord = np.linspace(start,end,nd)
232      for i in range(nd): self.lon = self.xcoord[i] ; self.update() ; self.put1d(i)
233
234    def meridional(self,nd=19,start=-90.,end=90.):
235    ### retrieve a latitude slice
236      self.xlabel = "North latitude (degrees)"
237      self.prepare(ndx=nd) ; self.xcoord = np.linspace(start,end,nd)
238      for i in range(nd): self.lat = self.xcoord[i] ; self.update() ; self.put1d(i)
239
240    def profile(self,nd=20,start=0.,end=100000.):
241    ### retrieve an altitude slice (profile)
242      self.xlabel = "Altitude (m)"
243      self.prepare(ndx=nd) ; self.xcoord = np.linspace(start,end,nd)
244      for i in range(nd): self.xz = self.xcoord[i] ; self.update() ; self.put1d(i)
245
246    def latlon(self,ndx=37,startx=-180.,endx=180.,ndy=19,starty=-90.,endy=90.):
247    ### retrieve a latitude/longitude slice
248      self.xlabel = "East longitude (degrees)" ; self.ylabel = "North latitude (degrees)"
249      self.prepare(ndx=ndx,ndy=ndy)
250      self.xcoord = np.linspace(startx,endx,ndx) ; self.ycoord = np.linspace(starty,endy,ndy)
251      for i in range(ndx): 
252       for j in range(ndy):
253         self.lon = self.xcoord[i] ; self.lat = self.ycoord[j] ; self.update() ; self.put2d(i,j)
254
255    def makeplot1d(self,choice,vertplot=0):
256    ### one 1D plot is created for the user-defined variable in choice.
257      (field, fieldlab) = self.definefield(choice)
258      if vertplot != 1:  absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel
259      else:              ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel
260      mpl.plot(absc,ordo,'-bo') ; mpl.ylabel(ordolab) ; mpl.xlabel(absclab) #; mpl.xticks(query.xcoord)
261
262    def plot1d(self,tabtodo,vertplot=0):
263    ### complete 1D figure with possible multiplots
264      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
265      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
266      fig = mpl.figure() ; subv,subh = myplot.definesubplot( len(tabtodo) , fig ) 
267      for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1).grid(True, linestyle=':', color='grey') ; self.makeplot1d(tabtodo[i],vertplot)
268
269###################
270### 2D analysis ###
271###################
272
273    def put2d(self,i,j):
274    ## fill in subscript i,j in output arrays
275    ## (arrays must have been correctly defined through prepare)
276      if self.prestab is None:  errormess("arrays must be prepared first through self.prepare")
277      self.prestab[i,j] = self.pres ; self.denstab[i,j] = self.dens ; self.temptab[i,j] = self.temp
278      self.zonwindtab[i,j] = self.zonwind ; self.merwindtab[i,j] = self.merwind
279      self.meanvartab[i,j,1:5] = self.meanvar[0:4]  ## note: var numbering according to MCD manual is kept
280      self.extvartab[i,j,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept
281
282    def makemap2d(self,choice):
283    ### one 2D map is created for the user-defined variable in choice.
284      (field, fieldlab) = self.definefield(choice)
285      myplot.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj="moll")
286
287    def map2d(self,tabtodo):
288    ### complete 2D figure with possible multiplots
289      if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
290      if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible.
291      fig = mpl.figure() ; subv,subh = myplot.definesubplot( len(tabtodo) , fig ) 
292      for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1) ; self.makemap2d(tabtodo[i])
293
294    ### TODO: makeplot2d, plot2d, passer plot settings, vecteurs, plot loct pas fixe
Note: See TracBrowser for help on using the repository browser.