AMBHAS
csglm.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003 Created on Thu Dec 29 19:58:19 2011
00004 
00005 @author: Sat Kumar Tomer
00006 @website: www.ambhas.com
00007 @email: satkumartomer@gmail.com
00008 
00009 Copuled Surface-Ground water Lumped hydrological Model
00010 """
00011 
00012 from __future__ import division
00013 # import required modules
00014 import numpy as np
00015 import xlrd, xlwt
00016 import os
00017 import gdal
00018 from gdalconst import *
00019 from scipy.interpolate import Rbf
00020 from Scientific.IO import NetCDF as nc
00021 import datetime
00022 np.seterr(all='raise')
00023 
00024 class CSGLM:
00025     """
00026     This is the main class of the CGLSM.
00027     This will read the input data,
00028     do the processing
00029     and then write the output files
00030     
00031     """
00032     
00033     
00034     def __init__(self, input_file):
00035         """
00036         Input:
00037             input_file: the file which contains all the information
00038             including forcing and parameters.
00039         """        
00040         
00041         self.input_file = input_file
00042         
00043         # read the input data
00044         self._read_input()
00045         
00046         ################ run the model ########################
00047         max_t = int(self.final_time/self.dt)
00048         self.max_t = max_t
00049         # initialize required variables
00050         # the length of state variables (i.e. soil moisture and gw level) is
00051         # one more than the timesteps
00052         self.actual_evap = np.empty(max_t)
00053         self.actual_trans = np.empty(max_t)    
00054         self.E_In = np.empty(max_t)    
00055         self.horton_runoff = np.empty(max_t)    
00056         self.recharge = np.empty(max_t)    
00057         self.runoff = np.empty(max_t)    
00058         self.gw_level = np.empty(max_t+1) 
00059         self.gw_level[0] = self.initial_gwl
00060         self.sm = np.empty((self.no_layer,max_t+1))
00061         self.sm[:,0] = self.initial_sm.flatten()
00062         self.surface_storage = np.zeros(max_t+1)
00063         
00064         for t in range(max_t):
00065             self.t = t
00066               
00067             # get forcing data at current time step        
00068             self._get_forcing()
00069             
00070             # call the interception module
00071             self._interception_fun()
00072             
00073             # call the runoff module
00074             self._runoff_fun()
00075             
00076             # call the soil module
00077             self._soil_fun()
00078             
00079             # call the surface storage module
00080             self._surface_storage_fun()
00081             
00082             # call the goundwater module
00083             self._gw_fun()
00084         
00085         # write the output
00086         self._write_output()
00087 
00088     def _read_input(self):
00089         """
00090         This checks if all the required input sheets are present in the xls file,
00091         read the data from input file, which can be used later in other functions
00092         """
00093     
00094         # list of required files in the input directory
00095         input_sheets = ['ind', 'forcing', 'initial_condition', 'gw_par',
00096                        'runoff_par', 'units', 'root_info', 'temporal_info',
00097                        'spatial_info', 'ET_par', 'soil_hyd_par', 'output_par']
00098         
00099         # check if all the required sheets are present or not
00100         self._check_sheets(input_sheets, self.input_file)
00101         
00102         # read the legend
00103         self._read_ind()
00104         
00105         # read the spatial data
00106         self._read_spatial()
00107         
00108         # read the temporal data
00109         self._read_temporal()
00110 
00111         # read the root distribution data
00112         self._read_root_distribution()
00113         
00114         # read the units 
00115         self._read_units()
00116         
00117         # read the initial condition
00118         self._read_initial_condition()
00119         
00120         # read the soil hydraulic properties data
00121         self._read_shp()
00122         
00123         # read the parameters related to runoff
00124         self._read_runoff_par()
00125         
00126         # read the parameters related to surface storage
00127         self._surface_storage_par()
00128         
00129         # read the groundwaer parameters data
00130         self._read_gw_par()
00131         
00132         # read the ET parameter data
00133         self._read_ET_par()
00134         
00135         # read the forcing infomation
00136         self._read_forcing()
00137         
00138         # read the outfile name
00139         self._read_ofile_name()
00140         
00141         # print the reading status
00142         output_message = 'Input data reading completed sucessfully'
00143         self._colored_output(output_message, 32)
00144        
00145     def _check_sheets(self, check_sheets, check_file):
00146         """
00147         This functions check if all the sheets needed to model are present  
00148         in check_file
00149         
00150         """
00151         # open the xls file and get its sheets
00152         foo = xlrd.open_workbook(check_file)
00153         check_sheet_names = foo.sheet_names()
00154         
00155         for check_sheet_names in check_file:
00156             if check_sheet_names not in check_file:
00157                 output_message = check_sheet_names + ' is missing'
00158                 self._colored_output(output_message,31)
00159 
00160     def _read_ind(self):
00161         """
00162         Read the ind sheet
00163         legend stores the information about the indices of other properties,
00164         which would be used by all other properties reading functions
00165         """
00166         book = xlrd.open_workbook(self.input_file)
00167         sheet = book.sheet_by_name('ind')
00168         # dont read the first line of the xls file
00169         ind = {}
00170         for i in range(sheet.nrows-1):
00171             ind[str(sheet.cell_value(i+1,0))] = int(sheet.cell_value(i+1,1))
00172                 
00173         self.ind = ind
00174 
00175     def _read_spatial(self):
00176         """
00177         Read the spatial info
00178         """
00179         book = xlrd.open_workbook(self.input_file)
00180         sheet = book.sheet_by_name('spatial_info')
00181         # get the row number from the ind
00182         j = self.ind['spatial_info']
00183         no_layer = int(sheet.cell_value(j,1))
00184         z = sheet.row_values(j,2)
00185         if no_layer != len(z):
00186             raise ValueError('The length of the thickness_layers\
00187             should be equal to the No_layer')
00188         
00189         self.no_layer = no_layer
00190         self.z = z
00191         #mid depth of the layers
00192         depth = np.zeros(no_layer+1)
00193         depth[1:] = np.cumsum(z)
00194         self.mid_z = 0.5*(depth[1:]+depth[:-1])
00195         
00196     
00197     def _read_temporal(self):
00198         """
00199         Read the temporal info
00200         """
00201         book = xlrd.open_workbook(self.input_file)
00202         sheet = book.sheet_by_name('temporal_info')
00203         #get the row number from the ind
00204         j = self.ind['temporal_info']
00205         dt = sheet.cell_value(j,1)
00206         final_time = sheet.cell_value(j,2)
00207         
00208         self.dt = dt
00209         self.final_time = final_time
00210     
00211     def _read_root_distribution(self):
00212         """
00213         read the root distribution factors
00214         """
00215         book = xlrd.open_workbook(self.input_file)
00216         sheet = book.sheet_by_name('root_info')
00217         #get the row number from the ind
00218         j = self.ind['root_info']
00219         self.ndvi_max = sheet.cell_value(j,1)
00220         self.ndvi_min = sheet.cell_value(j,2)
00221         self.fapar_max = sheet.cell_value(j,3)
00222         self.lai_max = sheet.cell_value(j,4)
00223         self.Rd_max = sheet.cell_value(j,5)
00224         self.Lrd = sheet.cell_value(j,6)
00225   
00226             
00227     def _read_units(self):
00228         """
00229         read the units of the forcing data
00230         """
00231         book = xlrd.open_workbook(self.input_file)
00232         sheet = book.sheet_by_name('units')
00233         #get the row number from the ind
00234         j = self.ind['units']
00235         forcing_units = {}
00236         for i in range(sheet.ncols-1):
00237             forcing_units[str(sheet.cell_value(0,i+1))] = str(sheet.cell_value(j,i+1))
00238         self.forcing_units = forcing_units
00239     
00240     def _read_initial_condition(self):
00241         """
00242         read initial condition
00243         """
00244         #get the row number from the ind
00245         j = self.ind['initial_condition']
00246         
00247         book = xlrd.open_workbook(self.input_file)
00248         sheet = book.sheet_by_name('initial_condition')
00249         theta_0 = sheet.row_values(j,2)
00250         self.initial_gwl = sheet.cell_value(j,1)
00251         self.initial_sm = np.array(theta_0)
00252         
00253         try:
00254             self.initial_sm.shape = self.no_layer,1
00255         except:
00256             raise ValueError('The length of the theta_0 should be \
00257             equal to the no_layer')
00258     
00259     def _read_shp(self):
00260         """
00261         read the soil hydraulic parameters
00262         """
00263         #get the row number from the ind
00264         j = self.ind['soil_hyd_par']
00265         
00266         book = xlrd.open_workbook(self.input_file)
00267         sheet = book.sheet_by_name('soil_hyd_par')
00268         soil_par = {}
00269         soil_par['qr'] = sheet.cell_value(j,1)
00270         soil_par['f'] = sheet.cell_value(j,2)
00271         soil_par['a'] = sheet.cell_value(j,3)
00272         soil_par['n'] = sheet.cell_value(j,4)
00273         soil_par['Ks'] = sheet.cell_value(j,5)
00274         soil_par['l'] = sheet.cell_value(j,6)
00275         #soil_par['evap_wp'] = sheet.cell_value(j,7)
00276         #soil_par['evap_fc'] = sheet.cell_value(j,8)
00277         soil_par['zl'] = sheet.cell_value(j,9)
00278         soil_par['fl'] = sheet.cell_value(j,10)
00279         
00280         m = 1-1/soil_par['n']
00281         # evaluate wilting point and field capacity
00282         soil_par['evap_fc'] = self.psi2theta(-0.33, soil_par['qr'], soil_par['f'], 
00283                                soil_par['a'], m, soil_par['n'])
00284         
00285         soil_par['evap_wp'] = self.psi2theta(-15, soil_par['qr'], soil_par['f'], 
00286                                soil_par['a'], m, soil_par['n'])
00287                                
00288         self.soil_par = soil_par
00289     
00290     def psi2theta(self,psi, thetar, thetas, alpha, m, n):
00291          """
00292          psi2theta: given the theta calculate the pressure head
00293          """
00294          if (psi>=0):
00295              theta = thetas
00296          elif psi<-1e6:
00297              theta = 1.01*thetar
00298          else:
00299              theta = thetar+(thetas-thetar)*pow(1+pow(abs(alpha*psi),n),-m)
00300          return theta
00301          
00302     def _read_runoff_par(self):
00303         """
00304         read the parameters related to runoff
00305         """
00306         #get the row number from the ind
00307         j = self.ind['runoff_par']
00308         
00309         book = xlrd.open_workbook(self.input_file)
00310         sheet = book.sheet_by_name('runoff_par')
00311         runoff_par = {}
00312         for i in range(sheet.ncols-1):
00313             runoff_par[str(sheet.cell_value(0,i+1))] = float(sheet.cell_value(j,i+1))
00314         self.runoff_par = runoff_par
00315     
00316     def _surface_storage_par(self):
00317         """
00318         read the parameters related to surface storage
00319         """
00320         #get the row number from the ind
00321         j = self.ind['surface_storage_par']
00322         
00323         book = xlrd.open_workbook(self.input_file)
00324         sheet = book.sheet_by_name('surface_storage_par')
00325         surface_storage_par = {}
00326         surface_storage_par['a'] = float(sheet.cell_value(j,1))
00327         surface_storage_par['b'] = float(sheet.cell_value(j,2))
00328         self.surface_storage_par = surface_storage_par
00329     
00330     def _read_gw_par(self):
00331         """
00332         read the parameters related to groundwater
00333         """        
00334         #get the row number from the ind
00335         j = self.ind['gw_par']
00336         
00337         book = xlrd.open_workbook(self.input_file)
00338         sheet = book.sheet_by_name('gw_par')
00339         gw_par = {}
00340         for i in range(sheet.ncols-1):
00341             gw_par[str(sheet.cell_value(0,i+1))] = float(sheet.cell_value(j,i+1))
00342         
00343         self.gw_par = gw_par
00344     
00345     def _read_ET_par(self):
00346         """
00347         read the parameters related to evaporation
00348         """
00349         #get the row number from the ind
00350         #j = self.ind['ET_par']
00351         
00352         #book = xlrd.open_workbook(self.input_file)
00353         #sheet = book.sheet_by_name('ET_par')
00354         ET_par = {}
00355         #ET_par['trans_fc'] = sheet.cell_value(j,1)
00356         #ET_par['trans_wp'] = sheet.cell_value(j,2)
00357         qr = self.soil_par['qr']
00358         f = self.soil_par['f']
00359         a = self.soil_par['a']
00360         n = self.soil_par['n']
00361         m = 1-1/n
00362         fl = self.soil_par['fl']
00363         mid_z = self.mid_z
00364         ET_par['trans_fc'] = self.psi2theta(-0.33, qr, f, a, m, n)*np.exp(-mid_z/fl)
00365         ET_par['trans_wp'] = self.psi2theta(-15, qr, f, a, m, n)*np.exp(-mid_z/fl)
00366         
00367         self.ET_par = ET_par
00368     
00369     def _read_forcing(self):
00370         """
00371         read the forcing data from xls file
00372         """
00373         book = xlrd.open_workbook(self.input_file)
00374         sheet = book.sheet_by_name('forcing')
00375         
00376         data_len = sheet.nrows-1
00377         year = np.zeros(data_len)
00378         doy = np.zeros(data_len)
00379         rain = np.zeros(data_len)
00380         pet = np.zeros(data_len)
00381         ndvi = np.zeros(data_len)
00382         pumping = np.zeros(data_len)
00383     
00384         for i in xrange(data_len):
00385             year[i] = sheet.cell_value(i+1,0)
00386             doy[i] = sheet.cell_value(i+1,1)
00387             rain[i] = sheet.cell_value(i+1,2)
00388             pet[i] = sheet.cell_value(i+1,3)
00389             ndvi[i] = sheet.cell_value(i+1,4)
00390             pumping[i] = sheet.cell_value(i+1,5)
00391         
00392         self.year = year
00393         self.doy = doy
00394         
00395         # if forcing data was in mm units, covert into m
00396         if self.forcing_units['rain'] == 'mm':
00397             self.rain = rain/1000.0
00398         elif self.forcing_units['rain'] == 'm':
00399             self.rain = rain
00400         else:
00401             raise ValueError("The units of rain should be either 'mm' or 'm' ")
00402 
00403         if self.forcing_units['pet'] == 'mm':
00404             self.pet = pet/1000.0
00405         elif self.forcing_units['pet'] == 'm':
00406             self.pet = pet
00407         else:
00408             raise ValueError("The units of PET should be either 'mm' or 'm' ")
00409             
00410         if self.forcing_units['pumping'] == 'mm':
00411             self.pumping = pumping/1000.0
00412         elif self.forcing_units['pumping'] == 'm':
00413             self.pumping = pumping
00414         else:
00415             raise ValueError("The units of pumping should be either 'mm' or 'm' ")
00416         
00417         # compute the fractional vegetation cover, rooting depth and lai
00418         ndvi_max = self.ndvi_max
00419         ndvi_min = self.ndvi_min
00420         ndvi[ndvi>ndvi_max] = ndvi_max
00421         ndvi[ndvi<ndvi_min] = ndvi_min
00422         
00423         fapar = 1.60*ndvi-0.02
00424         fapar_max = self.fapar_max
00425         
00426         lai_max = self.lai_max
00427         lai = lai_max*np.log(1-fapar)/np.log(1-fapar_max)
00428         
00429         Rd_max = self.Rd_max  
00430         Rd = Rd_max*lai/lai_max
00431         fc = ((ndvi-ndvi_max)/(ndvi_max-ndvi_min))**2
00432         
00433         self.kc = 0.8+0.4*(1-np.exp(-0.7*lai))
00434         self.ndvi = ndvi
00435         self.lai = lai        
00436         self.Rd = Rd
00437         self.fc = fc
00438                
00439 
00440     def _read_ofile_name(self):
00441         """
00442         read the forcing data from xls file
00443         """
00444         book = xlrd.open_workbook(self.input_file)
00445         sheet = book.sheet_by_name('output_par')
00446         self.ofile_name = str(sheet.cell_value(0,1))
00447 
00448 
00449     def _colored_output(self, output_message, color):
00450         """
00451         This functions print  the output_message in the color
00452         Input:
00453             output_messgae: the text you want to print
00454             color: the color in which you want to print text, it could be one of:
00455                 30: Gray
00456                 31: Red
00457                 32: Green
00458                 33: Yellow
00459                 34: Blue
00460                 35: Magneta
00461                 66: Cyan
00462                 37: White
00463                 38: Crimson
00464                 41: Highlighted Red
00465                 42: Highlighted Green 
00466                 43: Highlighted Brown 
00467                 44: Highlighted Blue 
00468                 45: Highlighted Magenta 
00469                 46: Highlighted Cyan
00470                 47: Highlighted Gray 
00471                 48: Highlighted Crimson 
00472         Output:
00473             This returns None, but print the output in python shell
00474         """
00475                 
00476         print(("\033[31m" +output_message+ "\033[0m").replace('31',str(color)))
00477 
00478     def _get_forcing(self):
00479         """
00480         this will give the forcing at time t
00481         """
00482         # the PET is multiplied by crop coefficient
00483         self.rain_cur = self.rain[self.t]
00484         self.pet_cur = self.pet[self.t]*self.kc[self.t]
00485         self.lai_cur = self.lai[self.t]
00486         self.pumping_cur = self.pumping[self.t]
00487         
00488         self.cur_year = self.year[self.t]
00489         self.cur_doy = self.doy[self.t]
00490 
00491         
00492     def _interception_fun(self):
00493         """
00494         Input:
00495             lai_cur:    LAI at the current time step
00496             pet_cur:     PET at the current time step
00497             rain_cur:    Rainfall at the current time step
00498             
00499         Output:
00500             E_In:     Evaporation from Interception
00501             T:        Transpiration
00502             E:        Evaporation
00503             net_rain_cur:   Net rainfall (precipitation-interception loss) at 
00504             current time step
00505         """
00506         In = self.lai[self.t]*0.2/1000.0
00507         soil_cover = np.exp(-0.5*self.lai_cur)
00508         veg_cover = 1 - soil_cover
00509         
00510         E_In = np.min([veg_cover*self.rain_cur, veg_cover*self.pet_cur, veg_cover*In])
00511         T = np.min([veg_cover*self.pet_cur - 0.2*E_In, 1.2*self.pet_cur - E_In])
00512         E = np.min([soil_cover*self.pet_cur, 1.2*self.pet_cur-T-E_In])
00513         net_rain_cur = self.rain_cur - E_In
00514         
00515         self.E_In[self.t] = E_In
00516         self.trans = T
00517         self.evap = E
00518         self.net_rain_cur = net_rain_cur
00519     
00520     def _runoff_fun(self):
00521         """
00522         this module will calculate the runoff based on the initial soil moisture 
00523         and net precipitation
00524         
00525         Input:
00526             C:            Average soil moisture
00527             Pn:           Precipitation after interception loss
00528             runoff_par:   runoff parameters ['Cm','B']
00529             
00530         Output:
00531             runoff_cur:     Runoff at current time step
00532         """
00533         #Cm = self.runoff_par['Cm']
00534         #B = self.runoff_par['B']
00535         #F = 1 - (1- self.sm[:,self.t].mean()/Cm)**B 
00536         #self.runoff_cur = self.net_rain_cur*F
00537         #self.runoff[self.t] = self.runoff_cur
00538         
00539         # chen and dudhia
00540         Kdt_ref = 3.0
00541         Kref = 2e-6
00542         theta_s = self.soil_par['f']*np.exp(-self.mid_z/self.soil_par['fl'])
00543         Dx = theta_s - self.sm[:,self.t]
00544         Dx = Dx*self.mid_z
00545         Dx = Dx[:3].sum()
00546         Kdt = Kdt_ref*self.soil_par['Ks']/Kref
00547         
00548         Pn = self.net_rain_cur
00549         Imax = Pn*(Dx*(1-np.exp(-Kdt)))/(Pn+Dx*(1-np.exp(-Kdt)))
00550         
00551         self.runoff_cur = Pn - Imax 
00552         self.runoff[self.t] = self.runoff_cur
00553         
00554         
00555         
00556     def _soil_fun(self):
00557         """
00558         Input:
00559             soil_par     : soil hydraulic parameters
00560             z            : thicknes of layers
00561             R            : runoff
00562             no_layer     : no. of layers
00563             theta_0      : initial soil moisture
00564             root_frac    : root fraction in each layer
00565             T            : transpiration
00566             Pn           : net precipitation (precipitation - interception)
00567             E            : soil evaporation
00568             Pu           : pumping
00569             dt           : time step
00570         Output:
00571             theta_1: soil moisture for next time step
00572             Re: recharge (L)
00573         """
00574         # convert the fluxes from L to L/T
00575         self.runoff_cur /= self.dt
00576         self.evap /= self.dt
00577         self.trans /= self.dt
00578         self.net_rain_cur /= self.dt
00579         self.pumping_cur /= self.dt
00580         
00581         # initialize soil moisture at next time step        
00582         theta_1_mat = np.zeros(self.no_layer)
00583                 
00584         # estimate hydraulic properties
00585         K = np.zeros((self.no_layer,1))
00586         D = np.zeros((self.no_layer,1))
00587         for i in range(self.no_layer):
00588             if i<self.no_layer-1:
00589                 # using the maximum value of theta
00590                 #K[i], D[i] = self._shp(max(self.sm[i,self.t],self.sm[i+1, self.t]),i)
00591                 # using the arithmatic mean of theta
00592                 K[i], D[i] = self._shp(0.5*(self.sm[i, self.t]+self.sm[i+1, self.t]),i)
00593             else:
00594                 K[i], D[i] = self._shp(self.sm[i,self.t],i)
00595         K = K.flatten()*np.exp(-self.mid_z/self.soil_par['zl'])
00596         D = D.flatten()*np.exp(-self.mid_z/self.soil_par['zl'])
00597         
00598         # calculate stress in soil moisture and subsequently the actual 
00599         # evaporation and transpiration
00600         self._smi_fun()
00601         AE = self.evap*self.SSMI
00602         self._transpiration_fun()
00603         AT = self.AT 
00604                 
00605         # set up the A and U matrix
00606         A = np.zeros((self.no_layer, self.no_layer))
00607         U = np.zeros((self.no_layer,1))
00608         z = self.z
00609         for i in range(self.no_layer):
00610             if i == 0:
00611                 A[0,0] = -D[1]/(0.5*z[1]*(z[1]+z[2]))
00612                 A[0,1] = D[1]/(0.5*z[1]*(z[1]+z[2]))
00613                 U[0] = (-AT[0] - K[0] + self.net_rain_cur - AE - self.runoff_cur \
00614                 + self.pumping_cur)/z[0]
00615             elif i == self.no_layer-1:
00616                 A[i,i] = -D[i-1]/(0.5*z[i]*(z[i-1]+z[i]))
00617                 A[i,i-1] = D[i-1]/(0.5*z[i]*(z[i-1]+z[i])) 
00618                 U[i] = (-AT[i] + K[i-1] - K[i])/z[i]
00619             else:
00620                 A[i,i-1] = D[i-1]/(0.5*z[i]*(z[i-1]+z[i]))
00621                 A[i,i+1] = D[i]/(0.5*z[i]*(z[i]+z[i+1]))
00622                 A[i,i] = -A[i,i-1] -A[i,i+1]
00623                 U[i] = (-AT[i] +K[i-1] - K[i])/z[i]
00624                     
00625             # convert from A,U to F,G
00626             F = np.eye(self.no_layer) + A*self.dt
00627             #    if (F>1.4).any() | (F<0.6).any():
00628             #        F = expm(A*dt)
00629             G = np.dot(F,U)*self.dt
00630             
00631             # calculate theta for next time step
00632             theta_1 = np.dot(F, self.sm[:,self.t]) + G.flatten()
00633             
00634             # convert recharge from L/T to L
00635             Re = K[-1]*self.dt
00636             
00637             # remove the water as hortonian runoff, 
00638             # if the soil moisture exceeds saturation
00639             if theta_1[0] >= self.soil_par['f']:
00640                 HR = (theta_1[0]-self.soil_par['f'])*z[0]
00641                 theta_1[0] = self.soil_par['f']
00642             else:
00643                 HR = 0
00644 
00645             #check for the range of the theta
00646             theta_s = self.soil_par['f']*np.exp(-self.mid_z/self.soil_par['fl'])
00647             wp = self.ET_par['trans_wp']*np.exp(-self.mid_z/self.soil_par['fl'])
00648             for j in range(self.no_layer):
00649                 if theta_1[j]>theta_s[j]:
00650                     theta_1[j] = theta_s[j]
00651                 if theta_1[j]<wp[j]:
00652                     theta_1[j] = wp[j]
00653             
00654             # put the result of this pixel into matrix
00655             self.sm[:,self.t+1] = theta_1.flatten()
00656             self.G = G
00657             self.F = F
00658             self.theta_1 = theta_1
00659             self.recharge[self.t] = Re
00660             self.actual_evap[self.t] = AE*self.dt
00661             self.actual_trans[self.t] = AT.sum()*self.dt
00662             self.horton_runoff[self.t] = HR
00663             
00664     def _smi_fun(self):
00665         """
00666         this module computes the surface soil moisture stress index, and root zone soil moisture 
00667         stress index
00668         """
00669         
00670         # calculate surface soil moisture index
00671         SSMI = (self.sm[0,self.t] - self.soil_par['evap_wp'])/(
00672                 self.soil_par['evap_fc'] - self.soil_par['evap_wp'])
00673                 
00674         if SSMI > 1: 
00675             SSMI = 1
00676         elif SSMI<0:
00677             SSMI = 0
00678     
00679         # calculate root zone soil moisture index
00680         RZSMI = np.zeros((self.no_layer,))
00681         
00682         for i in range(self.no_layer):
00683             trans_wp = self.ET_par['trans_wp'][i]
00684             trans_fc = self.ET_par['trans_fc'][i]
00685             if (self.sm[i,self.t] < trans_wp):
00686                 RZSMI[i] = 0
00687             elif self.sm[i,self.t] > trans_fc:
00688                 RZSMI[i] = 1
00689             else:
00690                 
00691                 RZSMI[i] = (self.sm[i,self.t]-trans_wp)/(trans_fc - trans_wp)
00692             
00693         
00694         self.SSMI = SSMI
00695         self.RZSMI = RZSMI
00696     
00697     
00698     def _transpiration_fun(self):
00699         """
00700         this function computes the actual transpiration for all the soil layers
00701         """
00702         # root distribution
00703         Lrd = self.Lrd
00704         Rd = self.Rd[self.t]
00705         r_density = np.empty(self.no_layer)
00706         for i in range(self.no_layer):
00707             if i==0:
00708                 z1 = 0
00709             else:
00710                 z1 = np.sum(self.z[:i])
00711             z2 = np.sum(self.z[:i+1])
00712             if z2>Rd:
00713                 z2 = Rd
00714             if z1>z2:
00715                 z1 = z2
00716             
00717             r_density[i] = np.exp(-z1/Lrd) - np.exp(-z2/Lrd)
00718         r_density = r_density/( 1 - np.exp(-Rd/Lrd) )
00719         
00720         self.r_density = r_density
00721         self.AT = self.RZSMI*r_density*self.trans
00722     
00723 
00724     def _shp(self, theta,i):
00725         """
00726         soil hydraulic properties module
00727         i is the layer
00728         """
00729         
00730         qr = self.soil_par['qr']*np.exp(-self.mid_z[i]/self.soil_par['fl'])
00731         f = self.soil_par['f']*np.exp(-self.mid_z[i]/self.soil_par['fl'])
00732         a = self.soil_par['a']
00733         n = self.soil_par['n']
00734         Ks = self.soil_par['Ks']
00735         l = self.soil_par['l']
00736         
00737         m = 1-1/n
00738         Se = (theta-qr)/(f - qr)
00739         if Se>=0.99:
00740             Se = 0.99
00741         elif Se<=0.01:
00742             Se = 0.01
00743         K = Ks*Se**l*(1-(1-Se**(1/m))**m)**2
00744         D = K/(a*(f-qr)*m*n*(Se**(1/m+1))*(Se**(-1/m)-1)**m)
00745         return K, D
00746     
00747     def _surface_storage_fun(self):
00748         """
00749         this module stores the surface water
00750         and give as recharge to the groundwater model
00751         """
00752         # update the storage based on the surface and hortonian runoff
00753         surface_storage = self.surface_storage[self.t] \
00754                                             + self.runoff_cur \
00755                                             + self.horton_runoff[self.t]
00756         a = self.surface_storage_par['a']
00757         b = self.surface_storage_par['b']
00758         Rep = a*surface_storage**b
00759         
00760         self.surface_storage[self.t+1] = surface_storage - Rep
00761         self.Rep = Rep                
00762         
00763 
00764     def _gw_fun(self):
00765         """
00766         Groundwater module
00767         """
00768         F = self.gw_par['F']
00769         G = self.gw_par['G']
00770         hmin = self.gw_par['hmin']
00771         
00772         self.sy = F/G
00773         self.lam = (1-F)*self.sy
00774         
00775         # net input = recharge - discharge
00776         u = self.recharge[self.t]-self.pumping_cur + self.Rep
00777         self.gw_level[self.t+1] = F*(self.gw_level[self.t]-hmin) + G*u + hmin
00778         
00779         dzn = self.gw_level[self.t+1] - self.gw_level[self.t] 
00780         self.discharge = u - self.sy*(dzn) # simulated discharge
00781         self.z[-1] = self.z[-1] - dzn
00782         #if self.t<30:
00783         #    print self.recharge[self.t]
00784         #    print self.z[-1]
00785                                    
00786         
00787         
00788     def _write_output(self):
00789         """
00790         This will write the data in the xls format
00791         
00792         """
00793         # open the xls workbook
00794         wbk = xlwt.Workbook()
00795         sheet = wbk.add_sheet('variables')
00796         # write the header
00797         sheet.write(0,0,'year')
00798         sheet.write(0,1,'doy')
00799         sheet.write(0,2,'gw level')
00800         for i in range(self.no_layer):
00801             sheet.write(0,3+i,'SM - %i'%(i+1))
00802         # write the data    
00803         for i in range(self.max_t):
00804             sheet.write(i+1,0,self.year[i])
00805             sheet.write(i+1,1,self.doy[i])
00806             sheet.write(i+1,2,self.gw_level[i])
00807             for j in range(self.no_layer):
00808                 sheet.write(i+1,3+j,self.sm[j,i])
00809         
00810         sheet = wbk.add_sheet('flux')
00811         # write the header
00812         sheet.write(0,0,'year')
00813         sheet.write(0,1,'doy')
00814         sheet.write(0,2,'rain')
00815         sheet.write(0,3,'PET')
00816         sheet.write(0,4,'lai')
00817         sheet.write(0,5,'pumping')
00818         sheet.write(0,6,'actual evap')
00819         sheet.write(0,7,'actual trans')
00820         sheet.write(0,8,'E_In')
00821         sheet.write(0,9,'AET')
00822         sheet.write(0,10,'recharge')
00823         sheet.write(0,11,'runoff')
00824         
00825         # write the data    
00826         for i in range(self.max_t):
00827             sheet.write(i+1,0,self.year[i])
00828             sheet.write(i+1,1,self.doy[i])
00829             sheet.write(i+1,2,self.rain[i])
00830             sheet.write(i+1,3,self.pet[i])
00831             sheet.write(i+1,4,self.lai[i])
00832             sheet.write(i+1,5,self.pumping[i])
00833             sheet.write(i+1,6,self.actual_evap[i])
00834             sheet.write(i+1,7,self.actual_trans[i])
00835             sheet.write(i+1,8,self.E_In[i])
00836             sheet.write(i+1,9,self.actual_evap[i]+self.actual_trans[i]+self.E_In[i])
00837             sheet.write(i+1,10,self.recharge[i])
00838             sheet.write(i+1,11,self.runoff[i])
00839             
00840         wbk.save(self.ofile_name)
00841         
00842         output_message = 'Output data writting completed sucessfully'
00843         self._colored_output(output_message, 32)
00844         
00845 
00846 class CSGLM_ENKF(CSGLM):
00847     """
00848     This is the main class of the Ensemble Kalman Filter (EnKF)
00849     coupled with the CSGLM model. The model is given in the class CSGLM.
00850         
00851     This will read the input data,
00852     do the processing
00853     and then write the output files
00854     
00855     """
00856     
00857     def __init__(self,input_file):
00858         """
00859         Input:
00860             input_file: the file which contains all the information
00861             including forcing and parameters.
00862         """      
00863         self.input_file = input_file
00864         self.n_ens = 10
00865         # read the input data
00866         self._read_input()
00867         
00868         # initialize the variables and output file
00869         self.initialize()
00870         
00871         ################ run the model ########################
00872         for t in range(self.max_t):
00873             self.t = t
00874               
00875             # get forcing data at current time step        
00876             self._get_forcing()
00877             
00878             # perturb the soil par ensemble
00879             self._perturb_soil_par_ens()
00880                         
00881             # call the unsat module with ensemble
00882             for ens in range(self.n_ens):
00883                 self.ens = ens
00884                 
00885                 # call the interception module
00886                 self._interception_ens_fun()
00887                 
00888                 # call the runoff module
00889                 self._runoff_ens_fun()
00890                 
00891                 # call the soil module
00892                 self._soil_ens_fun()
00893                 
00894                 # call the surface storage module
00895                 self._surface_storage_ens_fun()
00896                 
00897                 # call the goundwater module
00898                 self._gw_ens_fun()
00899         
00900                 
00901             # ensemble kalmfan filter
00902             self._enkf_par()
00903 
00904             self._enkf_ET()
00905             
00906             self._write_output()                
00907                 
00908                 
00909         self.nc_file.close() # close the output file
00910 
00911 
00912     def initialize(self):
00913         """
00914         this initializes all the required variables
00915         and open the netcdf file for writting
00916         also generates the initial ensemble of the soil hydraulic parameters
00917         """
00918         max_t = int(self.final_time/self.dt)
00919         self.max_t = max_t                       
00920         
00921         #initialize variables
00922         self.surface_storage_ens = np.zeros((self.n_ens, self.max_t+1))   
00923         self.gw_level_ens = np.zeros((self.n_ens, self.max_t+1))
00924         
00925         self.gw_level_ens[:,0] = self.initial_gwl
00926         self.sm_ens = self.initial_sm + 0.02*np.random.normal(size=(self.n_ens,self.no_layer))
00927         
00928         # open file for writing
00929         file = nc.NetCDFFile(self.ofile_name, 'w')
00930         setattr(file, 'title', 'output of the model ambhas.csglm_enkf')
00931         now = datetime.datetime.now()
00932         setattr(file, 'description', 'The model was run at %s'%(now.ctime()))
00933         file.createDimension('depth', self.no_layer)
00934         file.createDimension('time', self.max_t+1)
00935         file.createDimension('ensemble', self.n_ens)
00936         
00937         # depth
00938         varDims = 'depth',
00939         depth = file.createVariable('depth', 'd', varDims)
00940         depth.units = 'm'
00941         depth[:] = self.z
00942         
00943         # time (year and doy)
00944         varDims = 'time',
00945         self.nc_year = file.createVariable('year', 'd', varDims)
00946         self.nc_doy = file.createVariable('doy', 'd', varDims)
00947         
00948         # soil moisture
00949         varDims = 'ensemble', 'depth', 'time'
00950         self.nc_sm = file.createVariable('sm','d', varDims)
00951         self.nc_sm.units = 'v/v'
00952         self.nc_sm[:,:,0] = self.sm_ens
00953         
00954         # recharge, aet 
00955         varDims = 'time',
00956         self.nc_aet = file.createVariable('aet','d',varDims)
00957         self.nc_aet.units = 'mm'
00958         self.nc_recharge = file.createVariable('recharge','d',varDims)
00959         self.nc_recharge.units = 'mm'
00960         
00961         # gw level
00962         varDims = 'ensemble', 'time'
00963         self.nc_gw_level_ens = file.createVariable('gw_level_ens','d',varDims)
00964         self.nc_gw_level_ens.units = 'm'
00965         self.nc_gw_level_ens[:,0] = self.gw_level_ens[:,0]
00966         
00967         # soil hydraulic parameters
00968         varDims = 'ensemble','time'
00969         self.nc_qr = file.createVariable('qr','d',varDims)
00970         self.nc_qr.units = 'v/v'
00971         self.nc_f = file.createVariable('f','d',varDims)
00972         self.nc_f.units = 'v/v'    
00973         self.nc_a = file.createVariable('a','d',varDims)
00974         self.nc_a.units = '1/m'
00975         self.nc_n = file.createVariable('n','d',varDims)
00976         self.nc_n.units = '-' 
00977         self.nc_Ks = file.createVariable('Ks','d',varDims)
00978         self.nc_Ks.units = 'm/s'
00979         self.nc_l = file.createVariable('l','d',varDims)
00980         self.nc_l.units = '-' 
00981         
00982         self.nc_file = file
00983         
00984         # generate soil hydraulic parameters
00985         self._generate_soil_par_ens()
00986         
00987         
00988 
00989     def _generate_soil_par_ens(self):
00990         """
00991         this uses the LHS to generate the ensemble of the parameters
00992         
00993         this also computes the perturbation needed to perturb the parameters
00994         which is done in another function
00995         """
00996                
00997         #gaussian perturbation
00998         v = np.random.normal(size=(self.n_ens,6))
00999         v = v-np.tile(v.mean(axis=0),(self.n_ens,1))
01000         qr = self.shp_ens['qr']  + v[:,0]*self.shp_ens['qr']*0.1
01001         f = self.shp_ens['f']  + v[:,1]*self.shp_ens['f']*0.1
01002         a = self.shp_ens['a']    + v[:,2]*self.shp_ens['a']*0.1
01003         n = self.shp_ens['n']            + v[:,3]*self.shp_ens['n']*0.1
01004         Ks = self.shp_ens['Ks']          + v[:,4]*self.shp_ens['Ks']*0.1
01005         l = self.shp_ens['l']            + v[:,5]*self.shp_ens['l']*0.1
01006 
01007         # check for the range of generated parameters
01008         qr[qr>self.qr_max] = self.qr_max
01009         f[f>self.f_max] = self.f_max
01010         a[a>self.a_max] = self.a_max
01011         n[n>self.n_max] = self.n_max
01012         Ks[Ks>self.Ks_max] = self.Ks_max
01013         l[l>self.l_max] = self.l_max
01014         
01015         qr[qr<self.qr_min]  = self.qr_min
01016         f[f<self.f_min]  = self.f_min
01017         a[a<self.a_min]     = self.a_min
01018         n[n<self.n_min]                 = self.n_min
01019         Ks[Ks<self.Ks_min]              = self.Ks_min
01020         l[l<self.l_min]                 = self.l_min
01021         
01022         soil_par_ens = {}
01023         soil_par_ens['qr'] = qr
01024         soil_par_ens['f'] = f
01025         soil_par_ens['a'] = a
01026         soil_par_ens['n'] = n
01027         soil_par_ens['Ks'] = Ks
01028         soil_par_ens['l'] = l
01029         
01030         self.soil_par_ens = soil_par_ens
01031         
01032         #perturbation parameter
01033         soil_pert = {}
01034         soil_pert['qr'] = (self.qr_max - self.qr_min)*0.1/100.0
01035         soil_pert['f'] = (self.f_max - self.f_min)*0.1/100.0
01036         soil_pert['a'] =  (self.a_max - self.a_min)*0.1/100.0
01037         soil_pert['n'] =      (self.n_max - self.n_min)*0.1/100.0
01038         soil_pert['Ks'] =     (self.Ks_max - self.Ks_min)*0.1/100.0
01039         soil_pert['l'] =      (self.l_max - self.l_min)*0.1/100.0
01040         
01041         self.soil_pert = soil_pert
01042 
01043     def _read_input(self):
01044         """
01045         This checks if all the required input sheets are present in the xls file,
01046         read the data from input file, which can be used later in other functions
01047         """
01048     
01049         # list of required files in the input directory
01050         input_sheets = ['ind', 'forcing', 'initial_condition', 'gw_par',
01051                        'runoff_par', 'units', 'root_info', 'temporal_info',
01052                        'spatial_info', 'ET_par', 'soil_hyd_par', 'output_par']
01053         
01054         # check if all the required sheets are present or not
01055         self._check_sheets(input_sheets, self.input_file)
01056         
01057         # read the legend
01058         self._read_ind()
01059         
01060         # read the spatial data
01061         self._read_spatial()
01062         
01063         # read the temporal data
01064         self._read_temporal()
01065 
01066         # read the root distribution data
01067         self._read_root_distribution()
01068         
01069         # read the units 
01070         self._read_units()
01071         
01072         # read the initial condition
01073         self._read_initial_condition()
01074         
01075         # read the soil hydraulic properties data
01076         self._read_shp_ens()
01077         
01078         # read the parameters related to runoff
01079         self._read_runoff_par()
01080         
01081         # read the parameters related to surface storage
01082         self._surface_storage_par()
01083         
01084         # read the groundwaer parameters data
01085         self._read_gw_par()
01086         
01087         # read the ET parameter data
01088         self._read_ET_par()
01089         
01090         # read the forcing infomation
01091         self._read_forcing()
01092         
01093         # read the outfile name
01094         self._read_ofile_name()
01095         
01096         # print the reading status
01097         output_message = 'Input data reading completed sucessfully'
01098         self._colored_output(output_message, 32)
01099 
01100     def _read_initial_condition(self):
01101         """
01102         read initial condition
01103         """
01104         #get the row number from the ind
01105         j = self.ind['initial_condition']
01106         
01107         book = xlrd.open_workbook(self.input_file)
01108         sheet = book.sheet_by_name('initial_condition')
01109         theta_0 = sheet.row_values(j,2)
01110         self.initial_gwl = sheet.cell_value(j,1)
01111         self.initial_sm = np.array(theta_0)
01112         
01113                
01114 
01115     def _read_shp_ens(self):
01116         """
01117         read the soil hydraulic parameters
01118         """
01119         #get the row number from the ind
01120         j = self.ind['soil_hyd_par']
01121         
01122         book = xlrd.open_workbook(self.input_file)
01123         sheet = book.sheet_by_name('soil_hyd_par')
01124         shp_ens = {}
01125         shp_ens['qr'] = sheet.cell_value(j,1)
01126         shp_ens['f'] = sheet.cell_value(j,2)
01127         shp_ens['a'] = sheet.cell_value(j,3)
01128         shp_ens['n'] = sheet.cell_value(j,4)
01129         shp_ens['Ks'] = sheet.cell_value(j,5)
01130         shp_ens['l'] = sheet.cell_value(j,6)
01131         #soil_par['evap_wp'] = sheet.cell_value(j,7)
01132         #soil_par['evap_fc'] = sheet.cell_value(j,8)
01133         shp_ens['zl'] = sheet.cell_value(j,9)
01134         shp_ens['fl'] = sheet.cell_value(j,10)
01135         
01136         m = 1-1/shp_ens['n']
01137         # evaluate wilting point and field capacity
01138         shp_ens['evap_fc'] = self.psi2theta(-0.33, shp_ens['qr'], shp_ens['f'], 
01139                                shp_ens['a'], m, shp_ens['n'])
01140         
01141         shp_ens['evap_wp'] = self.psi2theta(-15, shp_ens['qr'], shp_ens['f'], 
01142                                shp_ens['a'], m, shp_ens['n'])
01143                                
01144         self.shp_ens = shp_ens
01145         
01146         # maximum and minimum range of the paramters
01147         self.qr_min, self.qr_max = 0.02, 0.12 
01148         self.f_min, self.f_max = 0.25, 0.4 
01149         self.a_min, self.a_max = 2, 5 
01150         self.n_min, self.n_max = 1.4, 2.4 
01151         self.Ks_min, self.Ks_max = 1e-6, 1e-5 
01152         self.l_min, self.l_max = 0.4, 0.6 
01153 
01154 
01155     def _perturb_soil_par_ens(self):
01156         """
01157         this functions perturb the soil hydraulic parameters 
01158         using the gaussian random variables
01159         """
01160         v = np.random.normal(size=(self.n_ens,6))
01161         v = v-np.tile(v.mean(axis=0),(self.n_ens,1))
01162         qr = self.soil_par_ens['qr']+self.soil_pert['qr']*v[:,0]
01163         f = self.soil_par_ens['f']+self.soil_pert['f']*v[:,1]
01164         a = self.soil_par_ens['a']+self.soil_pert['a']*v[:,2]
01165         n = self.soil_par_ens['n']+self.soil_pert['n']*v[:,3]
01166         Ks = self.soil_par_ens['Ks']+self.soil_pert['Ks']*(v[:,4]-v[:,4].mean())
01167         l = self.soil_par_ens['l']+self.soil_pert['l']*v[:,5]
01168         
01169 
01170         # check for the range of generated parameters
01171         qr[qr>self.qr_max] = self.qr_max
01172         f[f>self.f_max] = self.f_max
01173         a[a>self.a_max] = self.a_max
01174         n[n>self.n_max] = self.n_max
01175         Ks[Ks>self.Ks_max] = self.Ks_max
01176         l[l>self.l_max] = self.l_max
01177         
01178         qr[qr<self.qr_min]  = self.qr_min
01179         f[f<self.f_min]  = self.f_min
01180         a[a<self.a_min]     = self.a_min
01181         n[n<self.n_min]                 = self.n_min
01182         Ks[Ks<self.Ks_min]              = self.Ks_min
01183         l[l<self.l_min]                 = self.l_min        
01184 
01185         soil_par_ens = {}
01186         soil_par_ens['qr'] = qr
01187         soil_par_ens['f'] = f
01188         soil_par_ens['a'] = a
01189         soil_par_ens['n'] = n
01190         soil_par_ens['Ks'] = Ks
01191         soil_par_ens['l'] = l        
01192         m = 1-1/n
01193         soil_par_ens['evap_fc'] = self.psi2theta(-0.33, qr, f, a, m, n)
01194         
01195         soil_par_ens['evap_wp'] = self.psi2theta(-15, qr, f, a, m, n)
01196         self.soil_par_ens = soil_par_ens
01197         
01198         fl = self.shp_ens['fl']
01199         mid_z = self.mid_z
01200         ET_par = {}
01201         ET_par['trans_fc'] = self.psi2theta(-0.33, qr, f, a, m, n)
01202         ET_par['trans_wp'] = self.psi2theta(-15, qr, f, a, m, n)
01203         
01204         self.ET_par = ET_par
01205 
01206     def _runoff_ens_fun(self):
01207         """
01208         this module will calculate the runoff based on the initial soil moisture 
01209         and net precipitation
01210         
01211         Input:
01212             C:            Average soil moisture
01213             Pn:           Precipitation after interception loss
01214             runoff_par:   runoff parameters ['Cm','B']
01215             
01216         Output:
01217             runoff_cur:     Runoff at current time step
01218         """
01219         #Cm = self.runoff_par['Cm']
01220         #B = self.runoff_par['B']
01221         #F = 1 - (1- self.sm[:,self.t].mean()/Cm)**B 
01222         #self.runoff_cur = self.net_rain_cur*F
01223         #self.runoff[self.t] = self.runoff_cur
01224         ens = self.ens
01225         # chen and dudhia
01226         Kdt_ref = 3.0
01227         Kref = 2e-6
01228         theta_s = self.soil_par_ens['f'][ens]*np.exp(-self.mid_z/self.shp_ens['fl'])
01229         
01230         Dx = theta_s - self.sm_ens[ens]
01231         Dx = Dx*self.mid_z
01232         Dx = Dx[:3].sum()
01233         Kdt = Kdt_ref*self.soil_par_ens['Ks'][ens]/Kref
01234         
01235         Pn = self.net_rain_cur
01236         Imax = Pn*(Dx*(1-np.exp(-Kdt)))/(Pn+Dx*(1-np.exp(-Kdt)))
01237         
01238         self.runoff_cur = Pn - Imax 
01239         self.runoff = 1.0*self.runoff_cur
01240 
01241     def _interception_ens_fun(self):
01242         """
01243         Input:
01244             lai_cur:    LAI at the current time step
01245             pet_cur:     PET at the current time step
01246             rain_cur:    Rainfall at the current time step
01247             
01248         Output:
01249             E_In:     Evaporation from Interception
01250             T:        Transpiration
01251             E:        Evaporation
01252             net_rain_cur:   Net rainfall (precipitation-interception loss) at 
01253             current time step
01254         """
01255         In = self.lai[self.t]*0.2/1000.0
01256         soil_cover = np.exp(-0.5*self.lai_cur)
01257         veg_cover = 1 - soil_cover
01258         
01259         E_In = np.min([veg_cover*self.rain_cur, veg_cover*self.pet_cur, veg_cover*In])
01260         T = np.min([veg_cover*self.pet_cur - 0.2*E_In, 1.2*self.pet_cur - E_In])
01261         E = np.min([soil_cover*self.pet_cur, 1.2*self.pet_cur-T-E_In])
01262         net_rain_cur = self.rain_cur - E_In
01263         
01264         
01265         self.E_In = E_In
01266         self.trans = T
01267         self.evap = E
01268         self.net_rain_cur = net_rain_cur
01269 
01270     def _soil_ens_fun(self):
01271         """
01272         Input:
01273             soil_par     : soil hydraulic parameters
01274             z            : thicknes of layers
01275             R            : runoff
01276             no_layer     : no. of layers
01277             theta_0      : initial soil moisture
01278             root_frac    : root fraction in each layer
01279             T            : transpiration
01280             Pn           : net precipitation (precipitation - interception)
01281             E            : soil evaporation
01282             Pu           : pumping
01283             dt           : time step
01284         Output:
01285             theta_1: soil moisture for next time step
01286             Re: recharge (L)
01287         """
01288         # convert the fluxes from L to L/T
01289         self.runoff_cur /= self.dt
01290         self.evap /= self.dt
01291         self.trans /= self.dt
01292         self.net_rain_cur /= self.dt
01293         self.pumping_cur /= self.dt
01294         
01295         # initialize soil moisture at next time step        
01296         theta_1_mat = np.zeros(self.no_layer)
01297 
01298         # get the information about current ensemble
01299         ens = self.ens
01300         sm = self.sm_ens[ens]
01301         
01302         # estimate hydraulic properties
01303         K = np.zeros((self.no_layer,1))
01304         D = np.zeros((self.no_layer,1))
01305         for i in range(self.no_layer):
01306             if i<self.no_layer-1:
01307                 # using the maximum value of theta
01308                 #K[i], D[i] = self._shp(max(self.sm[i,self.t],self.sm[i+1, self.t]),i)
01309                 # using the arithmatic mean of theta
01310                 K[i], D[i] = self._shp(0.5*(sm[i]+sm[i+1]),i)
01311             else:
01312                 K[i], D[i] = self._shp(sm[i],i)
01313         K = K.flatten()*np.exp(-self.mid_z/self.shp_ens['zl'])
01314         D = D.flatten()*np.exp(-self.mid_z/self.shp_ens['zl'])
01315         
01316         # calculate stress in soil moisture and subsequently the actual 
01317         # evaporation and transpiration
01318         self._smi_fun()
01319         AE = self.evap*self.SSMI
01320         self._transpiration_fun()
01321         AT = self.AT 
01322                 
01323         # set up the A and U matrix
01324         A = np.zeros((self.no_layer, self.no_layer))
01325         U = np.zeros((self.no_layer,1))
01326         z = self.z
01327         for i in range(self.no_layer):
01328             if i == 0:
01329                 A[0,0] = -D[1]/(0.5*z[1]*(z[1]+z[2]))
01330                 A[0,1] = D[1]/(0.5*z[1]*(z[1]+z[2]))
01331                 U[0] = (-AT[0] - K[0] + self.net_rain_cur - AE - self.runoff_cur \
01332                 + self.pumping_cur)/z[0]
01333             elif i == self.no_layer-1:
01334                 A[i,i] = -D[i-1]/(0.5*z[i]*(z[i-1]+z[i]))
01335                 A[i,i-1] = D[i-1]/(0.5*z[i]*(z[i-1]+z[i])) 
01336                 U[i] = (-AT[i] + K[i-1] - K[i])/z[i]
01337             else:
01338                 A[i,i-1] = D[i-1]/(0.5*z[i]*(z[i-1]+z[i]))
01339                 A[i,i+1] = D[i]/(0.5*z[i]*(z[i]+z[i+1]))
01340                 A[i,i] = -A[i,i-1] -A[i,i+1]
01341                 U[i] = (-AT[i] +K[i-1] - K[i])/z[i]
01342                     
01343             # convert from A,U to F,G
01344             F = np.eye(self.no_layer) + A*self.dt
01345             #    if (F>1.4).any() | (F<0.6).any():
01346             #        F = expm(A*dt)
01347             G = np.dot(F,U)*self.dt
01348             
01349             # calculate theta for next time step
01350             theta_1 = np.dot(F, sm) + G.flatten()
01351             
01352             # convert recharge from L/T to L
01353             Re = K[-1]*self.dt
01354             
01355             # remove the water as hortonian runoff, 
01356             # if the soil moisture exceeds saturation
01357             if theta_1[0] >= self.soil_par_ens['f'][ens]:
01358                 HR = (theta_1[0]-self.soil_par_ens['f'][ens])*z[0]
01359                 theta_1[0] = self.soil_par_ens['f'][ens]
01360             else:
01361                 HR = 0
01362 
01363             #check for the range of the theta
01364             theta_s = self.soil_par_ens['f'][ens]*np.exp(-self.mid_z/self.shp_ens['fl'])
01365             wp = self.ET_par['trans_wp'][ens]*np.exp(-self.mid_z/self.shp_ens['fl'])
01366             for j in range(self.no_layer):
01367                 if theta_1[j]>theta_s[j]:
01368                     theta_1[j] = theta_s[j]
01369                 if theta_1[j]<wp[j]:
01370                     theta_1[j] = wp[j]
01371             
01372             # put the result of this pixel into matrix
01373             self.sm_ens[ens] = theta_1.flatten()
01374             self.G = G
01375             self.F = F
01376             self.theta_1 = theta_1
01377             self.recharge = Re
01378             self.actual_evap = AE*self.dt
01379             self.actual_trans = AT.sum()*self.dt
01380             self.horton_runoff = HR
01381 
01382     def _smi_fun(self):
01383         """
01384         this module computes the surface soil moisture stress index, and root zone soil moisture 
01385         stress index
01386         """
01387         ens = self.ens
01388         sm = self.sm_ens[ens]
01389         # calculate surface soil moisture index
01390         SSMI = (sm[0] - self.soil_par_ens['evap_wp'][ens])/(
01391                 self.soil_par_ens['evap_fc'][ens] - self.soil_par_ens['evap_wp'][ens])
01392                 
01393         if SSMI > 1: 
01394             SSMI = 1
01395         elif SSMI<0:
01396             SSMI = 0
01397     
01398         # calculate root zone soil moisture index
01399         RZSMI = np.zeros((self.no_layer,))
01400         mid_z = self.mid_z
01401         fl = self.shp_ens['fl']
01402         
01403         for i in range(self.no_layer):
01404             trans_wp = self.ET_par['trans_wp'][ens]*np.exp(-mid_z/fl)[i]
01405             trans_fc = self.ET_par['trans_fc'][ens]*np.exp(-mid_z/fl)[i]
01406             if (sm[i] < trans_wp):
01407                 RZSMI[i] = 0
01408             elif sm[i] > trans_fc:
01409                 RZSMI[i] = 1
01410             else:
01411                 
01412                 RZSMI[i] = (sm[i]-trans_wp)/(trans_fc - trans_wp)
01413             
01414         
01415         self.SSMI = SSMI
01416         self.RZSMI = RZSMI
01417 
01418     def _surface_storage_ens_fun(self):
01419         """
01420         this module stores the surface water
01421         and give as recharge to the groundwater model
01422         """
01423         ens = self.ens
01424         # update the storage based on the surface and hortonian runoff
01425         surface_storage = self.surface_storage_ens[ens,self.t] \
01426                                             + self.runoff_cur \
01427                                             + self.horton_runoff
01428         a = 1.0*self.surface_storage_par['a']
01429         b = 1.0*self.surface_storage_par['b']
01430         Rep = a*surface_storage**b
01431         #print type(surface_storage)
01432         
01433         self.surface_storage_ens[ens,self.t+1] = surface_storage - Rep
01434         self.Rep = Rep     
01435 
01436     def _gw_ens_fun(self):
01437         """
01438         Groundwater module
01439         """
01440         ens = self.ens
01441         F = self.gw_par['F']
01442         G = self.gw_par['G']
01443         hmin = self.gw_par['hmin']
01444         
01445         self.sy = F/G
01446         self.lam = (1-F)*self.sy
01447         
01448         # net input = recharge - discharge
01449         u = self.recharge-self.pumping_cur + self.Rep
01450         self.gw_level_ens[ens,self.t+1] = F*(self.gw_level_ens[ens,self.t]-hmin) + G*u + hmin
01451         
01452         dzn = self.gw_level_ens[ens,self.t+1] - self.gw_level_ens[ens,self.t] 
01453         self.discharge = u - self.sy*(dzn) # simulated discharge
01454         self.z_ens[ens,-1] = self.z_ens[ens,-1] - dzn
01455         
01456     def _read_spatial(self):
01457         """
01458         Read the spatial info
01459         """
01460         book = xlrd.open_workbook(self.input_file)
01461         sheet = book.sheet_by_name('spatial_info')
01462         # get the row number from the ind
01463         j = self.ind['spatial_info']
01464         no_layer = int(sheet.cell_value(j,1))
01465         z = sheet.row_values(j,2)
01466         if no_layer != len(z):
01467             raise ValueError('The length of the thickness_layers\
01468             should be equal to the No_layer')
01469         
01470         self.no_layer = no_layer
01471         self.z = z
01472         self.z_ens = np.tile(z,(self.n_ens,1))
01473         
01474         #mid depth of the layers
01475         depth = np.zeros(no_layer+1)
01476         depth[1:] = np.cumsum(z)
01477         self.mid_z = 0.5*(depth[1:]+depth[:-1])
01478     
01479     def _enkf_par(self):
01480         """
01481         ensemble kalman filter
01482         """
01483         # make the state vector which contains the soil moisture at different 
01484         #depths and soil parameters
01485         x = self.sm_ens + 0.005*np.random.normal(size=self.no_layer)
01486         qr = self.soil_par_ens['qr']
01487         f = self.soil_par_ens['f']
01488         a = self.soil_par_ens['a']
01489         n = self.soil_par_ens['n']
01490         Ks = self.soil_par_ens['Ks']
01491         l = self.soil_par_ens['l']
01492         soil_par = (np.vstack([qr, f, a, n, Ks, l])).T
01493         X = np.hstack([x, soil_par])
01494         
01495         # compute the covariance matrix of the state+par
01496         X_bar = np.tile(X.mean(axis=0),(10,1))
01497         X_X_bar = X-X_bar
01498         cov_XX = np.dot(X_X_bar.T,X_X_bar) + 1e-6*np.eye(self.no_layer+6)
01499         cov_XX = 0.5*(cov_XX + cov_XX.T)
01500         
01501         # get the measurement of the ssm at the current time
01502         # and generate its ensemble and compute its covariance matrix
01503         e = np.zeros((self.n_ens, self.no_layer+6))
01504         if np.isnan(self.meas_sm_mean[self.t-1]):
01505             e[:,0] = 0
01506             v = 0.01*np.random.normal(size=(self.n_ens,self.no_layer+6))
01507         else:
01508             e[:,0] = self.meas_sm_mean[self.t-1] - self.sm_ens[:,0].mean()
01509             v = self.meas_sm_std[self.t-1]*np.random.normal(size=(self.n_ens,self.no_layer+6))
01510             
01511         v = v-np.tile(v.mean(axis=0),(self.n_ens,1))
01512         ev = e + v
01513         cov_ee = np.dot(ev.T, ev) + 1e-6*np.eye(self.no_layer+6)
01514         cov_ee = 0.5*(cov_ee + cov_ee.T)
01515         
01516         # compute kalaman gain
01517         K = np.dot(cov_XX, np.linalg.pinv(cov_XX+cov_ee))
01518         
01519         # update the measurment
01520         v = np.random.normal(size=(self.n_ens,))
01521         v = v-v.mean()
01522         e[:,0] = e[:,0]+0.005*v
01523         K = 0.5*(K + K.T)
01524         usm_par = X + np.dot(K,e.T).T      
01525         temp = np.dot(K,e.T).T     
01526         
01527         self.usm_par = usm_par
01528         #if self.t<=5:
01529         #    print self.t, usm_par[:,self.no_layer+4]/soil_par[:,4]
01530         # check for the range of the updated ensemble
01531         # soil moisture
01532         sm_ens = usm_par[:,:self.no_layer]
01533         sm_ens[sm_ens<0] = 0
01534         sm_ens[sm_ens>1] = 1
01535         v = 0.001*np.random.normal(size=(sm_ens.shape))
01536         v = v-np.tile(v.mean(axis=0),(self.n_ens,1))
01537         self.sm_ens = sm_ens + v
01538         # soil parameters
01539         qr = usm_par[:,self.no_layer+0]
01540         f = usm_par[:,self.no_layer+1]
01541         a = usm_par[:,self.no_layer+2]
01542         n = usm_par[:,self.no_layer+3]
01543         Ks = usm_par[:,self.no_layer+4]
01544         l = usm_par[:,self.no_layer+5]
01545         
01546         
01547         qr[qr>self.qr_max] = self.qr_max
01548         f[f>self.f_max] = self.f_max
01549         a[a>self.a_max] = self.a_max
01550         n[n>self.n_max] = self.n_max
01551         Ks[Ks>self.Ks_max] = self.Ks_max
01552         l[l>self.l_max] = self.l_max
01553         
01554         qr[qr<self.qr_min]  = self.qr_min
01555         f[f<self.f_min]  = self.f_min
01556         a[a<self.a_min]     = self.a_min
01557         n[n<self.n_min]                 = self.n_min
01558         Ks[Ks<self.Ks_min]              = self.Ks_min
01559         l[l<self.l_min]                 = self.l_min
01560         
01561         
01562         self.soil_par_ens['qr'] = qr
01563         self.soil_par_ens['f'] = f
01564         self.soil_par_ens['a'] = a
01565         self.soil_par_ens['n'] = n
01566         self.soil_par_ens['Ks'] = Ks
01567         self.soil_par_ens['l'] = l
01568         
01569         self.K = K
01570         self.cov_ee = cov_ee
01571         self.cov_XX = cov_XX
01572     
01573     def _enkf_ET(self):
01574         """
01575         ensemble kalman filter
01576         """
01577         # make the state vector which contains the soil moisture at different 
01578         #depths and soil parameters
01579         x = self.sm_ens + 0.005*np.random.normal(size=self.no_layer)
01580         qr = self.soil_par_ens['qr']
01581         f = self.soil_par_ens['f']
01582         a = self.soil_par_ens['a']
01583         n = self.soil_par_ens['n']
01584         Ks = self.soil_par_ens['Ks']
01585         l = self.soil_par_ens['l']
01586         soil_par = (np.vstack([qr, f, a, n, Ks, l])).T
01587         X = np.hstack([x, soil_par])
01588         
01589         # compute the covariance matrix of the state+par
01590         X_bar = np.tile(X.mean(axis=0),(10,1))
01591         X_X_bar = X-X_bar
01592         cov_XX = np.dot(X_X_bar.T,X_X_bar) + 1e-6*np.eye(self.no_layer+6)
01593         cov_XX = 0.5*(cov_XX + cov_XX.T)
01594         
01595         # get the measurement of the AET at the current time
01596         # and use it to generate ensemble of soil moisture
01597         err_aet = np.zeros(self.n_ens)
01598         for ens in range(self.n_ens):
01599             self.ens = ens
01600             self._smi_fun()
01601             AE = self.evap*self.SSMI
01602             self._transpiration_fun()
01603             AT = self.AT 
01604             
01605             err_aet[ens] = self.meas_aet[self.t] - AE - AT.sum() - self.E_In
01606         err_ae = err_aet.mean()*AE/(AE+AT.sum())
01607         err_at = err_aet.mean()*AT.sum()/(AE+AT.sum())
01608         
01609         e = np.zeros((self.n_ens, self.no_layer+6))
01610         e[:,0] = (err_ae + err_at*self.r_density[0])/self.z[0]
01611         e[:,1] = err_at*self.r_density[1]/self.z[1]
01612         e[:,2] = err_at*self.r_density[2]/self.z[2]
01613         e[:,3] = err_at*self.r_density[3]/self.z[3]
01614         e[:,4] = err_at*self.r_density[4]/self.z[4]
01615         v = 0.03*np.random.normal(size=(self.n_ens,self.no_layer+6))
01616             
01617         v = v-np.tile(v.mean(axis=0),(self.n_ens,1))
01618         ev = e + v
01619         cov_ee = np.dot(ev.T, ev) + 1e-6*np.eye(self.no_layer+6)
01620         cov_ee = 0.5*(cov_ee + cov_ee.T)
01621         
01622         #print cov_ee
01623         print self.t, e.max(), self.z[4]
01624         # compute kalaman gain
01625         K = np.dot(cov_XX, np.linalg.pinv(cov_XX+cov_ee))
01626         
01627         # update the measurment
01628         v = np.random.normal(size=(self.n_ens,))
01629         v = v-v.mean()
01630         e[:,0] = e[:,0]+0.005*v
01631         K = 0.5*(K + K.T)
01632         usm_par = X + np.dot(K,e.T).T      
01633         temp = np.dot(K,e.T).T     
01634         
01635         self.usm_par = usm_par
01636         #if self.t<=5:
01637         #    print self.t, usm_par[:,self.no_layer+4]/soil_par[:,4]
01638         # check for the range of the updated ensemble
01639         # soil moisture
01640         sm_ens = usm_par[:,:self.no_layer]
01641         sm_ens[sm_ens<0] = 0
01642         sm_ens[sm_ens>1] = 1
01643         v = 0.001*np.random.normal(size=(sm_ens.shape))
01644         v = v-np.tile(v.mean(axis=0),(self.n_ens,1))
01645         self.sm_ens = sm_ens + v
01646         # soil parameters
01647         qr = usm_par[:,self.no_layer+0]
01648         f = usm_par[:,self.no_layer+1]
01649         a = usm_par[:,self.no_layer+2]
01650         n = usm_par[:,self.no_layer+3]
01651         Ks = usm_par[:,self.no_layer+4]
01652         l = usm_par[:,self.no_layer+5]
01653         
01654         
01655         qr[qr>self.qr_max] = self.qr_max
01656         f[f>self.f_max] = self.f_max
01657         a[a>self.a_max] = self.a_max
01658         n[n>self.n_max] = self.n_max
01659         Ks[Ks>self.Ks_max] = self.Ks_max
01660         l[l>self.l_max] = self.l_max
01661         
01662         qr[qr<self.qr_min]  = self.qr_min
01663         f[f<self.f_min]  = self.f_min
01664         a[a<self.a_min]     = self.a_min
01665         n[n<self.n_min]                 = self.n_min
01666         Ks[Ks<self.Ks_min]              = self.Ks_min
01667         l[l<self.l_min]                 = self.l_min
01668         
01669         
01670         self.soil_par_ens['qr'] = qr
01671         self.soil_par_ens['f'] = f
01672         self.soil_par_ens['a'] = a
01673         self.soil_par_ens['n'] = n
01674         self.soil_par_ens['Ks'] = Ks
01675         self.soil_par_ens['l'] = l
01676         
01677         self.K = K
01678         self.cov_ee = cov_ee
01679         self.cov_XX = cov_XX
01680 
01681     def _read_forcing(self):
01682         """
01683         read the forcing data from xls file
01684         """
01685         book = xlrd.open_workbook(self.input_file)
01686         sheet = book.sheet_by_name('forcing')
01687         
01688         data_len = sheet.nrows-1
01689         year = np.zeros(data_len)
01690         doy = np.zeros(data_len)
01691         rain = np.zeros(data_len)
01692         pet = np.zeros(data_len)
01693         ndvi = np.zeros(data_len)
01694         pumping = np.zeros(data_len)
01695         meas_sm_mean = np.zeros(data_len)
01696         meas_sm_std = np.zeros(data_len)
01697         meas_aet = np.zeros(data_len)
01698     
01699         for i in xrange(data_len):
01700             year[i] = sheet.cell_value(i+1,0)
01701             doy[i] = sheet.cell_value(i+1,1)
01702             rain[i] = sheet.cell_value(i+1,2)
01703             pet[i] = sheet.cell_value(i+1,3)
01704             ndvi[i] = sheet.cell_value(i+1,4)
01705             pumping[i] = sheet.cell_value(i+1,5)
01706             meas_sm_mean[i] = sheet.cell_value(i+1,6)
01707             meas_sm_std[i] = sheet.cell_value(i+1,7)
01708             meas_aet[i] = sheet.cell_value(i+1,8)/1000.0
01709         
01710         self.year = year
01711         self.doy = doy
01712         self.meas_sm_mean = meas_sm_mean
01713         self.meas_sm_std = meas_sm_std
01714         self.meas_aet = meas_aet
01715         
01716         # if forcing data was in mm units, covert into m
01717         if self.forcing_units['rain'] == 'mm':
01718             self.rain = rain/1000.0
01719         elif self.forcing_units['rain'] == 'm':
01720             self.rain = rain
01721         else:
01722             raise ValueError("The units of rain should be either 'mm' or 'm' ")
01723 
01724         if self.forcing_units['pet'] == 'mm':
01725             self.pet = pet/1000.0
01726         elif self.forcing_units['pet'] == 'm':
01727             self.pet = pet
01728         else:
01729             raise ValueError("The units of PET should be either 'mm' or 'm' ")
01730             
01731         if self.forcing_units['pumping'] == 'mm':
01732             self.pumping = pumping/1000.0
01733         elif self.forcing_units['pumping'] == 'm':
01734             self.pumping = pumping
01735         else:
01736             raise ValueError("The units of pumping should be either 'mm' or 'm' ")
01737         
01738         # compute the fractional vegetation cover, rooting depth and lai
01739         ndvi_max = self.ndvi_max
01740         ndvi_min = self.ndvi_min
01741         ndvi[ndvi>ndvi_max] = ndvi_max
01742         ndvi[ndvi<ndvi_min] = ndvi_min
01743         
01744         fapar = 1.60*ndvi-0.02
01745         fapar_max = self.fapar_max
01746         
01747         lai_max = self.lai_max
01748         lai = lai_max*np.log(1-fapar)/np.log(1-fapar_max)
01749         
01750         Rd_max = self.Rd_max  
01751         Rd = Rd_max*lai/lai_max
01752         fc = ((ndvi-ndvi_max)/(ndvi_max-ndvi_min))**2
01753         
01754         self.kc = 0.8+0.4*(1-np.exp(-0.7*lai))
01755         self.ndvi = ndvi
01756         self.lai = lai        
01757         self.Rd = Rd
01758         self.fc = fc
01759 
01760     def _write_output(self):
01761         """
01762         this functions writes the output at each time step
01763         """
01764         # write the output
01765         self.nc_year[self.t] = (self.cur_year)
01766         self.nc_doy[self.t] = (self.cur_doy)
01767         self.nc_sm[:,:,self.t+1] = self.sm_ens
01768         self.nc_gw_level_ens[:,self.t+1] = self.gw_level_ens[:,self.t+1]
01769         #self.nc_recharge[self.t] = recharge_day
01770         #self.nc_aet[self.t] = aet_day
01771         self.nc_qr[:,self.t] = self.soil_par_ens['qr']
01772         self.nc_f[:,self.t] = self.soil_par_ens['f']
01773         self.nc_a[:,self.t] = self.soil_par_ens['a']
01774         self.nc_n[:,self.t] = self.soil_par_ens['n']
01775         self.nc_Ks[:,self.t] = self.soil_par_ens['Ks']
01776         self.nc_l[:,self.t] = self.soil_par_ens['l']
01777         #self.nc_recharge[:,self.t] = self.recharge
01778     
01779     def _shp(self, theta,i):
01780         """
01781         soil hydraulic properties module
01782         i is the layer
01783         """
01784         ens = self.ens
01785         qr = self.soil_par_ens['qr'][ens]*np.exp(-self.mid_z[i]/self.shp_ens['fl'])
01786         f = self.soil_par_ens['f'][ens]*np.exp(-self.mid_z[i]/self.shp_ens['fl'])
01787         a = self.soil_par_ens['a'][ens]
01788         n = self.soil_par_ens['n'][ens]
01789         Ks = self.soil_par_ens['Ks'][ens]
01790         l = self.soil_par_ens['l'][ens]
01791         
01792         m = 1-1/n
01793         Se = (theta-qr)/(f - qr)
01794         if Se>=0.99:
01795             Se = 0.99
01796         elif Se<=0.01:
01797             Se = 0.01
01798         K = Ks*Se**l*(1-(1-Se**(1/m))**m)**2
01799         D = K/(a*(f-qr)*m*n*(Se**(1/m+1))*(Se**(-1/m)-1)**m)
01800         return K, D
01801 
01802     def _read_ET_par(self):
01803         """
01804         read the parameters related to evaporation
01805         """
01806         #get the row number from the ind
01807         #j = self.ind['ET_par']
01808         
01809         #book = xlrd.open_workbook(self.input_file)
01810         #sheet = book.sheet_by_name('ET_par')
01811         ET_par = {}
01812         #ET_par['trans_fc'] = sheet.cell_value(j,1)
01813         #ET_par['trans_wp'] = sheet.cell_value(j,2)
01814         qr = self.shp_ens['qr']
01815         f = self.shp_ens['f']
01816         a = self.shp_ens['a']
01817         n = self.shp_ens['n']
01818         m = 1-1/n
01819         fl = self.shp_ens['fl']
01820         mid_z = self.mid_z
01821         ET_par['trans_fc'] = self.psi2theta(-0.33, qr, f, a, m, n)*np.exp(-mid_z/fl)
01822         ET_par['trans_wp'] = self.psi2theta(-15, qr, f, a, m, n)*np.exp(-mid_z/fl)
01823         
01824         self.ET_par = ET_par
01825 
01826 if __name__=='__main__':
01827     #berambadi = CSGLM('/home/tomer/csglm/input/berambadi.xls')
01828     
01829     berambadi_enkf = CSGLM_ENKF('/home/tomer/csglm/input/berambadi_enkf.xls')
01830     
01831 #    plt.plot(berambadi.gw_level)
01832 #    plt.show()
01833 
01834 
01835        
01836         
01837 
01838         
01839 
01840         
 All Classes Namespaces Files Functions Variables