Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download

📚 The CoCalc Library - books, templates and other resources

Views: 96141
License: OTHER
1
2
# coding: utf-8
3
4
# # Analysis of leaf chamber experiments
5
# This worksheet produces figures for:
6
#
7
# **Leaf-scale experiments reveal important omission in the Penman-Monteith equation**
8
#
9
# Schymanski, S.J. and D. Or
10
#
11
# http://www.hydrol-earth-syst-sci-discuss.net/hess-2016-363/
12
#
13
# Author: Stan Schymanski ([email protected])
14
15
# ## Worksheet setup and importing equations and functions from other worksheets
16
17
# In[1]:
18
19
get_ipython().run_cell_magic(u'capture', u'storage', u"# The above redirects all output of the below commands to the variable 'storage' instead of displaying it.\n# It can be viewed by typing: 'storage()'\n\n# Setup of worksheet, incl. importing of packages and defining general custom functions\nload('temp/Worksheet_setup.sage')\nfrom shutil import copyfile # for copying files between directories\nfrom matplotlib.ticker import MaxNLocator\nimport csv\nimport datetime\nimport time\nimport matplotlib.pyplot as plt\nimport matplotlib.dates as mdates")
20
21
22
# In[2]:
23
24
# From leaf_chamber_eqs, Leaf_enbalance2s_eqs and E_PM_eqs
25
load_session('temp/leaf_enbalance_eqs.sobj')
26
dict_vars1 = dict_vars.copy()
27
28
load_session('temp/E_PM_eqs.sobj')
29
dict_vars1.update(dict_vars)
30
31
load_session('temp/leaf_chamber_eqs.sobj')
32
dict_vars1.update(dict_vars)
33
34
dict_vars = dict_vars1.copy()
35
fun_loadvars(vardict=dict_vars) # re-loading variable definitions
36
37
38
# In[3]:
39
40
path_figs = 'figures/'
41
path_data = 'data/'
42
path_data_orig = '/home/sschyman/Documents/STEP/Lab_data/leaf_chamber/'
43
44
45
# ## Functions to compute steady-state leaf energy balance components
46
47
# In[4]:
48
49
def fun_SS(vdict1):
50
'''
51
Steady-state T_l, R_ll, H_l and E_l under forced conditions.
52
Parameters are given in a dictionary (vdict) with the following entries:
53
a_s, a_sh, L_l, P_a, P_wa, R_s, Re_c, T_a, g_sw, v_w
54
'''
55
vdict = vdict1.copy()
56
if not T_w in vdict1.keys():
57
vdict[T_w] = vdict[T_a]
58
59
60
# Nusselt number
61
vdict[nu_a] = eq_nua.rhs().subs(vdict)
62
vdict[Re] = eq_Re.rhs().subs(vdict)
63
vdict[Nu] = eq_Nu_forced_all.rhs().subs(vdict)
64
65
# h_c
66
vdict[k_a] = eq_ka.rhs().subs(vdict)
67
vdict[h_c] = eq_hc.rhs().subs(vdict)
68
69
# gbw
70
vdict[D_va] = eq_Dva.rhs().subs(vdict)
71
vdict[alpha_a] = eq_alphaa.rhs().subs(vdict)
72
vdict[rho_a] = eq_rhoa.rhs().subs(vdict)
73
vdict[Le] = eq_Le.rhs().subs(vdict)
74
vdict[g_bw] = eq_gbw_hc.rhs().subs(vdict)
75
76
# Hl, Rll
77
vdict[R_ll] = eq_Rll.rhs().subs(vdict)
78
vdict[H_l] = eq_Hl.rhs().subs(vdict)
79
80
# El
81
vdict[g_tw] = eq_gtw.rhs().subs(vdict)
82
vdict[C_wa] = eq_Cwl.rhs()(P_wl = P_wa, T_l = T_a).subs(vdict)
83
vdict[P_wl] = eq_Pwl.rhs().subs(vdict)
84
vdict[C_wl] = eq_Cwl.rhs().subs(vdict)
85
vdict[E_lmol] = eq_Elmol.rhs().subs(vdict)
86
vdict[E_l] = eq_El.rhs().subs(eq_Elmol).subs(vdict)
87
88
# Tl
89
try: vdict[T_l] = find_root((eq_Rs_enbal - R_s).rhs().subs(vdict), 273, 373)
90
except: print 'something missing: ' + str((eq_Rs_enbal - R_s).rhs().subs(vdict))
91
92
# Re-inserting T_l
93
Tlss = vdict[T_l]
94
for name1 in [C_wl, P_wl, R_ll, H_l, E_l, E_lmol]:
95
vdict[name1] = vdict[name1].subs(T_l = Tlss)
96
97
# Test for steady state
98
if n((E_l + H_l + R_ll - R_s).subs(vdict))>1.:
99
return 'error in energy balance: El + Hl + Rll - R_s = ' + str(n((E_l + H_l + R_ll - R_s).subs(vdict)))
100
return vdict
101
102
103
# In[5]:
104
105
# Test using data from Fig. 8 in Ball et al. 1988
106
vdict = cdict.copy()
107
vdict[a_s] = 1
108
vdict[L_l] = 0.07
109
vdict[P_a] = 101325
110
vdict[P_wa] = 20/1000*101325
111
vdict[R_s] = 400
112
vdict[Re_c] = 3000
113
vdict[T_a] = 273+30
114
vdict[T_w] = vdict[T_a]
115
vdict[g_sw] = 0.15/40
116
vdict[v_w] = 1.
117
resdict = fun_SS(vdict)
118
119
dict_print(resdict, list_names = [H_l, E_l, T_l])
120
121
122
# ### Model by Ball et al., 1988
123
124
# In[6]:
125
126
# for model by Ball et al. 1988
127
var2('g_svmol', 'Stomatal condutance to vapour in molar units', mole/meter^2/second)
128
var2('c_pmol', 'Molar heat capacity of air', value = 29.2, units = joule/mole/kelvin) # Units in the appendix are wrongly given as J mol/K
129
var2('L_E', 'Latent heat of vaporisation of water', value = 44000, units = joule/mole)
130
var2('r_bstar', 'Boundary layer resistance to heat transfer from unit area of leaf', meter^2*second/mole)
131
var2('r_b', 'Boundary layer resistnace to vapour transfer', meter^2*second/mole)
132
var2('r_s', 'Stomatal resistance to vapour transfer', meter^2*second/mole)
133
134
eq_Hl_Ball = H_l == c_pmol*(T_l - T_a)/r_bstar
135
eq_El_Ball = E_l == L_E*(P_wl - P_wa)/P_a/(r_s + r_b)
136
eq_rbstar = r_bstar == (3.8*L_A^(1/4)*v_w^(-1/2))
137
eq_rb = r_b == (1.78/a_s*r_bstar)
138
print units_check(eq_Hl_Ball).simplify_full()
139
print units_check(eq_El_Ball).simplify_full()
140
141
142
# In[7]:
143
144
def fun_SS_Ball(vdict1):
145
'''
146
Steady-state T_l, h_c, g_bv, g_tv, R_ll, H_l and E_l under forced conditions.
147
h_c and g_bv are calculated using Appendix in Ball et al. (1988).
148
see Ball_1988_Maintenance_of_Leaf2.pdf
149
Parameters are given in a dictionary (vdict) with the following entries:
150
a_s, L_l, P_a, P_wa, R_s, Re_c, T_a, g_svmol, v_w
151
'''
152
vdict = vdict1.copy()
153
if not L_A in vdict.keys():
154
vdict[L_A] = (pi()*L_l^2).subs(vdict)
155
if not T_w in vdict.keys():
156
vdict[T_w] = vdict[T_a]
157
158
vdict[r_s] = (1/(40*g_sw)).subs(vdict)
159
try:
160
vdict[r_bstar] = eq_rbstar.rhs().subs(vdict).n() #two-sided resistance for sensible heat flux
161
except:
162
vdict[r_bstar] = eq_rbstar.rhs().subs(vdict)
163
print 'r_bstar = ' + str(vdict[r_bstar])
164
vdict[r_b] = eq_rb.rhs().subs(vdict) # one-sided resistance to latent heat flux
165
166
167
168
Rll = eq_Rll.rhs().subs(vdict)
169
Hl = eq_Hl_Ball.rhs().subs(vdict)
170
El = eq_El_Ball.rhs().subs(eq_Pwl).subs(vdict)
171
172
enbal = El + Hl + Rll - R_s == 0
173
#print enbal(R_ll = Rll, H_l = Hl, E_l = El).subs(vdict)
174
Tss = find_root(enbal(R_ll = Rll, H_l = Hl, E_l = El).subs(vdict), 273, 373)
175
176
Rll1 = Rll(T_l = Tss)
177
Hl1= Hl(T_l = Tss)
178
El1 = El(T_l = Tss)
179
180
# Test for steady state
181
if (El1 + Hl1 + Rll1 - vdict[R_s])>1.:
182
print (El, Hl, Rll, vdict[R_s])
183
print Tss
184
return 'error in energy balance'
185
Pwl = eq_Pwl.rhs()(T_l = Tss).subs(vdict)
186
187
#dict_print(vdict)
188
return {'Tl_ball':n(Tss), 'Rll_ball':n(Rll1), 'Hl_ball':n(Hl1), 'El_ball':n(El1), 'rs_ball': vdict[r_s], 'rbstar_ball': vdict[r_bstar], 'rb_ball': vdict[r_b]}
189
190
191
# In[8]:
192
193
# Fig. 8 in Ball et al. 1988
194
vdict = cdict.copy()
195
vdict[a_s] = 1
196
vdict[L_l] = 0.07
197
vdict[P_a] = 101325
198
vdict[P_wa] = 20/1000*101325
199
vdict[R_s] = 400
200
vdict[Re_c] = 3000
201
vdict[T_a] = 273+30
202
vdict[T_w] = vdict[T_a]
203
vdict[g_sw] = 0.15/40
204
205
vdict[v_w] = 1.
206
ssdict = fun_SS(vdict)
207
#print ssdict
208
balldict = fun_SS_Ball(vdict)
209
#print balldict
210
print 'h_c(Ball): ' + str((c_pmol/balldict['rbstar_ball']).subs(vdict))
211
print 'g_vmol(Ball): ' + str((1/(r_b + r_s))(r_b = balldict['rb_ball'], r_s = balldict['rs_ball']))
212
print 'g_vmol(SS): ' + str(eq_gtwmol_gtw(T_l = T_a).subs(eq_gtw).subs(ssdict).subs(vdict))
213
print 'T_l(Ball): ' + str(balldict['Tl_ball'])
214
print 'T_l(SS): ' + str(ssdict[T_l])
215
print 'T_a: ' + str(vdict[T_a])
216
217
218
# <p><span style="color: #ff0000;">According to Fig. 8 in Ball et al., 1988, steady-state leaf temperature should be higher by 10 K than air temperature! Here it is only 6. <br /></span></p>
219
220
# ### Analytical models
221
222
# In[9]:
223
224
def fun_SS_PM(vdict1):
225
'''
226
Analytical equations from Worksheet E_PM_eqs, including detailed steady-state.
227
'''
228
vdict = vdict1.copy()
229
if not L_A in vdict1.keys():
230
vdict[L_A] = (pi()*L_l^2).subs(vdict1)
231
if not T_w in vdict1.keys():
232
vdict[T_w] = vdict[T_a]
233
if not P_wa in vdict1.keys():
234
print 'P_wa is missing'
235
ss = fun_SS(vdict)
236
237
vdict[P_was] = eq_Pwl.rhs()(T_l = T_a).subs(vdict)
238
vdict[Delta_eTa] = eq_Deltaeta_T.rhs().subs(vdict)
239
vdict[k_a] = eq_ka.rhs().subs(vdict)
240
vdict[nu_a] = eq_nua.rhs().subs(vdict)
241
vdict[Re] = eq_Re.rhs().subs(vdict)
242
vdict[Nu] = eq_Nu_forced_all.rhs().subs(vdict)
243
vdict[h_c] = eq_hc.rhs().subs(vdict)
244
245
vdict[P_N2] = eq_PN2.rhs().subs(vdict)
246
vdict[P_O2] = eq_PO2.rhs().subs(vdict)
247
vdict[alpha_a] = eq_alphaa.rhs().subs(vdict)
248
vdict[k_a] = eq_ka.rhs().subs(vdict)
249
vdict[D_va] = eq_Dva.rhs().subs(vdict)
250
vdict[Le] = eq_Le.rhs().subs(vdict)
251
vdict[rho_a] = eq_rhoa_Pwa_Ta.rhs().subs(vdict)
252
vdict[g_bw] = eq_gbw_hc.rhs().subs(vdict)
253
vdict[g_tw] = eq_gtw.rhs().subs(vdict)
254
vdict[g_twmol] = eq_gtwmol_gtw_iso.rhs().subs(vdict)
255
256
# Generalized Penman, getting Rll first
257
vdict_GPRll = vdict.copy()
258
vdict_GPRll[R_ll] = 0.
259
vdict_GPRll[T_l] = eq_Tl_Delta.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_GPRll)
260
vdict_GPRll[R_ll] = eq_Rll.rhs().subs(vdict_GPRll)
261
vdict_GPRll[E_l] = eq_El_Delta.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_GPRll)
262
vdict_GPRll[H_l] = eq_Hl_Delta.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_GPRll)
263
264
265
# Using linearised R_ll solution
266
vdict_lin = vdict.copy()
267
namesdict = [E_l, H_l, T_l, R_ll]
268
vdict_lin[E_l] = eq_El_Delta_Rlllin.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_lin)
269
vdict_lin[H_l] = eq_Hl_Delta_Rlllin.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_lin)
270
vdict_lin[T_l] = eq_Tl_Delta_Rlllin.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_lin)
271
vdict_lin[R_ll] = eq_Rll_tang.rhs().subs(vdict_lin)
272
273
274
# 'R_N = R_s:' MU-book, P. 79, under cloudy skies, implying that R_ll = 0
275
vdict2 = vdict.copy()
276
vdict2[R_ll] = 0
277
278
# Generalized Penman
279
vdict_GP = vdict2.copy()
280
vdict_GP[E_l] = eq_El_Delta.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_GP)
281
vdict_GP[H_l] = eq_Hl_Delta.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_GP)
282
vdict_GP[T_l] = eq_Tl_Delta.rhs().subs(eq_ce_conv, eq_ch_hc).subs(vdict_GP)
283
284
285
# Penman-stomata
286
vdict_PS = vdict2.copy()
287
vdict_PS[S] = eq_S_gbw_gsw.rhs().subs(vdict_PS)
288
vdict_PS[f_u] = eq_fu_gbw.rhs().subs(vdict_PS)
289
vdict_PS[gamma_v] = eq_gammav_as.rhs().subs(vdict_PS)
290
vdict_PS[E_l] = eq_El_P52.rhs().subs(vdict_PS)
291
vdict_PS[H_l] = eq_Hl_P52.rhs().subs(vdict_PS)
292
vdict_PS[T_l] = eq_Tl_P52.rhs().subs(vdict_PS)
293
294
# PM equation
295
vdict_PM = vdict2.copy()
296
vdict_PM[r_s] = 1/vdict_PM[g_sw]
297
vdict_PM[r_a] = eq_ra_hc.rhs().subs(vdict_PM)
298
vdict_PM[gamma_v] = eq_gammav_MU.rhs().subs(vdict_PM)
299
vdict_PM[epsilon] = eq_epsilon.rhs().subs(vdict_PM)
300
vdict_PM[E_l] = eq_El_PM2.rhs().subs(vdict_PM)
301
vdict_PM[H_l] = (R_s - R_ll - E_l).subs(vdict_PM)
302
303
# MU equation
304
vdict_MU = vdict2.copy()
305
vdict_MU[n_MU] = (a_sh/a_s).subs(vdict_MU)
306
vdict_MU[r_s] = 1/vdict_MU[g_sw]
307
vdict_MU[r_a] = eq_ra_hc.rhs().subs(vdict_MU)
308
vdict_MU[gamma_v] = eq_gammav_MU.rhs().subs(vdict_MU)
309
vdict_MU[E_l] = eq_El_MU2.rhs().subs(vdict_MU)
310
vdict_MU[H_l] = (R_s - R_ll - E_l).subs(vdict_MU)
311
312
# 'Corrected MU-equation: '
313
vdict_MUc = vdict2.copy()
314
vdict_MUc[r_s] = 1/vdict_MUc[g_sw]
315
vdict_MUc[r_a] = eq_ra_hc.rhs().subs(vdict_MUc)
316
vdict_MUc[gamma_v] = eq_gammav_MU.rhs().subs(vdict_MUc)
317
vdict_MUc[E_l] = eq_El_MU_corr.rhs().subs(vdict_MUc)
318
vdict_MUc[H_l] = (R_s - R_ll - E_l).subs(vdict_MUc)
319
320
resdict = ss.copy()
321
str1 = 'GPRll'
322
namesdict = [E_l, H_l, T_l, R_ll]
323
for name1 in namesdict:
324
resdict[str1+'_'+str(name1)] = eval('vdict_'+str1)[name1]
325
326
str1 = 'lin'
327
namesdict = [E_l, H_l, T_l, R_ll]
328
for name1 in namesdict:
329
resdict[str1+'_'+str(name1)] = eval('vdict_'+str1)[name1]
330
331
str1 = 'GP'
332
namesdict = [E_l, H_l, T_l]
333
for name1 in namesdict:
334
resdict[str1+'_'+str(name1)] = eval('vdict_'+str1)[name1]
335
336
str1 = 'PS'
337
namesdict = [E_l, H_l, T_l]
338
for name1 in namesdict:
339
resdict[str1+'_'+str(name1)] = eval('vdict_'+str1)[name1]
340
341
str1 = 'PM'
342
namesdict = [E_l, H_l]
343
for name1 in namesdict:
344
resdict[str1+'_'+str(name1)] = eval('vdict_'+str1)[name1]
345
346
str1 = 'MU'
347
namesdict = [E_l, H_l]
348
for name1 in namesdict:
349
resdict[str1+'_'+str(name1)] = eval('vdict_'+str1)[name1]
350
351
str1 = 'MUc'
352
namesdict = [E_l, H_l]
353
for name1 in namesdict:
354
resdict[str1+'_'+str(name1)] = eval('vdict_'+str1)[name1]
355
356
return resdict
357
358
359
# # Data reading, computing and display functions
360
361
# ## Functions to read data
362
363
# In[10]:
364
365
def fun_read_csv(fname1, lc_datetime_format = "%Y-%m-%d %H:%M:%S", lc_timepos = [], split1 = ';'):
366
'''
367
Reads file written by leaf_chamber_read_data and saves them as lc_data
368
If csv file fname1 does not exist in path_data, copies the file from path_data_orig to path_data
369
before opening and reading into numpy array. Contents of data file are printed as table before returning numpy array.
370
'''
371
lc_timepos = lc_timepos[:]
372
fname = path_data + fname1
373
try:
374
reader = csv.reader(open(fname, 'r'), delimiter=split1, quotechar='"')
375
except:
376
copyfile(path_data_orig + fname1, fname)
377
reader = csv.reader(open(fname, 'r'), delimiter=split1, quotechar='"')
378
htmldata = []
379
lc_nameslist = reader.next()
380
htmldata.append(lc_nameslist)
381
htmldata[-1][-1] = htmldata[-1][-1]+ '...................................................' # To avoid very thick rows
382
#print htmldata
383
lc_formatslist = ['S200' for i in srange(len(lc_nameslist))]
384
lc_unitslist = reader.next()
385
htmldata.append(lc_unitslist)
386
#print lc_unitslist
387
#print reader.next()
388
ncols = len(lc_nameslist)
389
lc_datetime_format = "%Y-%m-%d %H:%M:%S"
390
csvdata = []
391
with open(fname, 'r') as file_out:
392
rows = file_out.readlines()
393
394
# Determining dtypes
395
for row in rows[2:]:
396
row1 = row.strip('\r\n').split(split1)
397
for i in srange(len(row1)-1):
398
try:
399
blah = float(row1[i])
400
lc_formatslist[i] = 'float'
401
except:
402
try:
403
blah = datetime.datetime.fromtimestamp(time.mktime(time.strptime(row1[i].strip(), lc_datetime_format)))
404
lc_timepos.append(i)
405
lc_formatslist[i] = 'datetime64[us]'
406
except:
407
lc_formatslist[i] = 'S200'
408
409
lc_timepos = list(set(lc_timepos)) # to get unique values, i.e. drop repeated positions
410
411
for row in rows[2:]:
412
row1 = row.strip('\r\n').split(split1)
413
htmldata.append(row1[:])
414
for i in lc_timepos:
415
try:
416
row1[i] = datetime.datetime.fromtimestamp(time.mktime(time.strptime(row1[i].strip(), lc_datetime_format)))
417
except Exception, e:
418
print "failed because: %s" % e
419
print lc_timepos
420
print row1
421
return
422
row2 = tuple(row1)
423
csvdata.append(row2)
424
425
426
try:
427
lc_data = np.array(csvdata,dtype = zip(lc_nameslist,lc_formatslist))
428
except:
429
print 'Error in dtype'
430
return csvdata
431
pretty_print(table(htmldata, header_row=True, align='center'))
432
return lc_data
433
434
435
# In[11]:
436
437
def fun_read_campbell(fname1, nr_datetime_format = "%Y-%m-%d %H:%M:%S.%f", datelen = 21, datelast = '.0'):
438
'''
439
Reads Campbell data logger file and returns numpy array.
440
If file fname1 does not exist in path_data, copies the file from path_data_orig to path_data
441
before opening.
442
'''
443
import sys, traceback
444
fname = path_data + fname1
445
try:
446
reader = csv.reader(open(fname, 'rb'), delimiter=',', quotechar='"')
447
except:
448
copyfile(path_data_orig + fname1, fname)
449
reader = csv.reader(open(fname, 'rb'), delimiter=',', quotechar='"')
450
451
print reader.next()
452
nr_nameslist = reader.next()
453
print nr_nameslist
454
nr_unitslist = reader.next()
455
#print nr_unitslist
456
reader.next()
457
ncols = len(nr_nameslist)
458
459
csvdata = []
460
contd = True
461
while contd:
462
try:
463
row1 = reader.next()
464
date1 = row1[0]
465
# Need to add milliseconds if missing
466
if len(date1) < datelen: date1 = date1+datelast
467
row1[0] = datetime.datetime.fromtimestamp(time.mktime(time.strptime(date1.strip(), nr_datetime_format)))
468
row2 = tuple(row1)
469
csvdata.append(row2)
470
except StopIteration:
471
contd = False
472
except:
473
traceback.print_exc(file=sys.stdout)
474
print row1
475
#contd = False
476
477
#print csvdata
478
nr_formatslist = ['datetime64[us]', 'int']
479
for i in srange(len(nr_nameslist) - 2):
480
nr_formatslist.append('float')
481
nr_data = np.array(csvdata,dtype = zip(nr_nameslist,nr_formatslist))
482
return nr_data
483
484
485
# In[12]:
486
487
def fun_read_li(li_fname, prefix1 = ['1900-01-01_']):
488
'''
489
Reads Licor data file and returns as numpy array. If data contains several days, add a prefix for each day.
490
If file li_fname does not exist in path_data, copies the file from path_data_orig to path_data
491
before opening.
492
'''
493
time_format = "%H:%M:%S"
494
datetime_format = "%Y-%m-%d %H:%M:%S"
495
fname = path_data + li_fname
496
try:
497
reader = csv.reader(open(fname, 'rb'), delimiter='\t')
498
except:
499
copyfile(path_data_orig + li_fname, fname)
500
reader = csv.reader(open(fname, 'rb'), delimiter='\t')
501
502
503
row = ['']
504
csvdata = []
505
outdata = []
506
nameflag = 'n'
507
dataflag = 'n'
508
prefpos = 0
509
timeold = 0
510
for row in reader:
511
#print row
512
if dataflag == 'n':
513
if row[0][0]!='<':
514
print row
515
if row == ['$STARTOFDATA$']:
516
print ' '
517
print 'NEW data set'
518
print 'length previous = '+str(len(csvdata))
519
if len(csvdata)>1: # Converting csvdata to np.array and adding to outdata
520
li_formatslist = ['int','datetime64[us]']
521
for i in srange(len(li_nameslist) - 3):
522
li_formatslist.append('float')
523
li_formatslist.append('str')
524
li_data = np.array(csvdata,dtype = zip(li_nameslist,li_formatslist))
525
outdata.append(li_data)
526
527
# Starting new data series
528
csvdata = []
529
nameflag = 'y'
530
531
532
if len(row)>1:
533
if nameflag == 'y':
534
li_nameslist = row
535
nameflag = 'n'
536
dataflag = 'y'
537
elif dataflag == 'y':
538
row1 = row[:]
539
prefix = prefix1[prefpos]
540
TS = prefix[0:10] + " " + row[1].strip()
541
try:
542
row1[1] = datetime.datetime.fromtimestamp(time.mktime(time.strptime(TS, datetime_format)))
543
if timeold!=0:
544
if row1[1]<timeold: # increment to next date if new time smaller old time
545
prefpos = prefpos + 1
546
TS = prefix[0:10] + " " + row[1].strip()
547
row1[1] = datetime.datetime.fromtimestamp(time.mktime(time.strptime(TS, datetime_format)))
548
timeold = row1[1]
549
row3 = tuple(row1)
550
csvdata.append(row3)
551
except:
552
print 'failed'
553
elif dataflag == 'y':
554
print row
555
556
557
li_formatslist = ['int','datetime64[us]']
558
for i in srange(len(li_nameslist) - 3):
559
li_formatslist.append('float')
560
li_formatslist.append('str')
561
li_data = np.array(csvdata,dtype = zip(li_nameslist,li_formatslist))
562
outdata.append(li_data)
563
print 'number of data sets: '+str(len(outdata))
564
return outdata
565
566
567
# ## Equations to infer conductances from flux measurements
568
569
# In[13]:
570
571
eq_gsw_gtw = solve(eq_gtw, g_sw)[0]
572
units_check(eq_gsw_gtw).simplify_full()
573
574
575
# In[14]:
576
577
eq_gtw_Elmol = solve(eq_Elmol.subs(eq_Cwa, eq_Cwl), g_tw)[0]
578
units_check(eq_gtw_Elmol)
579
580
581
# In[15]:
582
583
eq_hc_Hl = solve(eq_Hl, h_c)[0]
584
units_check(eq_hc_Hl)
585
586
587
# ## Functions to automate computation of derived results and plotting
588
589
# In[16]:
590
591
def fun_results(lc_data, vdict1 = {}, poslist = [], nameRs = '', ndict1 = {}, Pwinoffset = 0, Tdewfac = 1.06, Tdewoffset = -2.45):
592
'''
593
Simulates steady-state conditions for every data set contained in lc_data
594
and returns a numpy array with input data and results. Mapping of fields in lc_data
595
is given in ndict, e.g.
596
ndict = {R_s: '', T_d: 'T_dew', T_l: 'T_leaf_in', Q_in: 'fan_power_avg', S_a: 'Rn_above_leaf', S_b: 'Rn_below_leaf', S_s: 'Rn_beside_leaf', T_in: 'T_in1', F_in_v: 'Air_inflow', v_w: 'Wind', T_a: 'T_chamber', E_lmol: 'water_flow_avg'}
597
If vdict1 is not given or values are missing, predefined values are assumed. Pwinoffset allows accounting for bias in Cellkraft P_w_in by negative 50 to negative 200 Pa, see LI6400_data_repaired2.sws.
598
Usage:
599
sage: fun_results(lc_data, vdict1 = {}, poslist = [1,2,4])
600
'''
601
602
poslist = poslist[:]
603
def fun_subs(expr, vdict):
604
'''
605
Substitutes vdict in equation and returns result.
606
In case of a ValueError, e.g. because an entry is NaN,
607
returns NaN, rather than interrupting because of exception.
608
'''
609
try:
610
return float(expr.subs(vdict))
611
except:
612
#print expr.subs(vdict)
613
return float('NaN')
614
615
616
ndict = {R_s: '', T_d: 'T_dew', T_l: 'T_leaf_in', Q_in: 'fan_power_avg', S_a: 'Rn_above_leaf', S_b: 'Rn_below_leaf', S_s: 'Rn_beside_leaf', T_in: 'T_in1', F_in_v: 'Air_inflow', v_w: 'Wind', T_a: 'T_chamber', E_lmol: 'water_flow_avg'}
617
if len(ndict1)>0:
618
ndict = fun_dict(ndict,ndict1)
619
# Standard values
620
vdict = cdict.copy()
621
vdict[L_l] = 0.03 # 3x3 cm area
622
vdict[a_s] = 1 # one sided stomata
623
vdict[alpha_l] = 0 # assuming 0 albedo
624
vdict[g_sw] = 999 # unlimiting, filter paper only
625
vdict[P_a] = 101325
626
vdict[Re_c] = 3000
627
vdict[R_s] = 0
628
vdict[T_r] = vdict[T0]
629
vdict[P_a] = 101325
630
if len(vdict1)>0:
631
vdict = fun_dict(vdict,vdict1)
632
if L_A not in vdict.keys():
633
vdict[L_A] = vdict[L_l]^2
634
if R_d in vdict.keys():
635
vdict[R_s] = eq_Rs_Rd.rhs().subs(vdict)
636
#print vdict
637
results = []
638
allinput = []
639
640
if len(poslist) == 0:
641
poslist = srange(len(lc_data))
642
643
for i in poslist:
644
rdict1 = {} # For storing results that are not in vdict, e.g. if keys are strings rather than variables.
645
646
# Tdew reported by Cellkraft is biased (see worksheet Cellkraft_tests). Corrections range between y=1.09*x - 2.42 and y=1.06*x - 2.45
647
Tdew = Tdewfac*lc_data[ndict[T_d]][i]+Tdewoffset+vdict[T0]
648
if P_w_in in ndict1:
649
vdict[P_w_in] = lc_data[ndict[P_w_in]][i]
650
else:
651
vdict[P_w_in] = eq_Pwl.rhs().subs(T_l = Tdew).subs(vdict) + Pwinoffset
652
Qin = lc_data[ndict[Q_in]][i]
653
Tlmeas = lc_data[ndict[T_l]][i]+vdict[T0]
654
try:
655
Rn_above = lc_data[ndict[S_a]][i]
656
Rn_below = lc_data[ndict[S_b]][i]
657
#Rn_beside = abs(lc_data[ndict[S_s]][i])
658
Rn_leaf = eq_Rbalance.rhs()(S_a = Rn_above, S_b = Rn_below)
659
rdict1['Rn_leaf'] = Rn_leaf
660
except:
661
pass
662
if len(ndict[R_s])>0:
663
vdict[R_d] = abs(lc_data[ndict[R_s]][i])
664
vdict[R_s] = eq_Rs_Rd.rhs().subs(vdict)
665
#print 'R_s from ' + nameRs
666
667
vdict[T_in] = lc_data[ndict[T_in]][i]+vdict[T0]
668
vdict[F_in_va_n] = lc_data[ndict[F_in_v]][i]/1000/60
669
vdict[F_in_v] = eq_Finv_Finva_ref.rhs().subs(vdict)
670
vdict[F_in_mola] = eq_Finmola_Finva_ref.rhs().subs(vdict)
671
vdict[F_in_molw] = eq_Finmolw_Finmola_Pwa.rhs().subs(vdict)
672
673
#print 'F_in_v = ' + str(vdict[F_in_v])
674
#print vdict[P_v_in]
675
676
vdict[v_w] = lc_data[ndict[v_w]][i]
677
vdict[T_a] = lc_data[ndict[T_a]][i]+ 273.15
678
if T_w not in vdict1.keys():
679
vdict[T_w] = vdict[T_a]
680
681
Elmolmeas = lc_data[ndict[E_lmol]][i]*1e-6/60/vdict[L_A]/vdict[M_w]
682
Elmeas = eq_El_Elmol.rhs()(E_lmol = Elmolmeas).subs(vdict)
683
vdict[P_wa] = eq_Pwout_Elmol.rhs().subs(E_lmol = Elmolmeas).subs(vdict)
684
vdict[F_out_molw] = eq_Foutmolw_Finmolw_Elmol.rhs().subs(E_lmol = Elmolmeas).subs(vdict)
685
#print 'P_w_out = ' + str(vdict[P_wa])
686
#Hlmeas = eq_Hl_Tin_Tout.rhs().subs(E_lmol = Elmolmeas, P_a = 101325, T_out = T_a, Q_in = Qin).subs(vdict)
687
Hlmeas = eq_Hl_Tin_Tout_Fmol.rhs().subs(E_lmol = Elmolmeas, P_a = 101325, T_out = T_a, Q_in = Qin).subs(vdict)
688
689
690
691
Balldict = fun_SS_Ball(vdict)
692
PMdict = fun_SS_PM(vdict)
693
694
# Inferring g_tw and g_sw from Elmolmeas, Tlmeas, P_wa and g_bw
695
vdict1 = vdict.copy()
696
vdict1[E_lmol] = Elmolmeas
697
vdict1[T_l] = Tlmeas
698
vdict1[P_wl] = eq_Pwl.rhs().subs(vdict1)
699
vdict1[g_bw] = PMdict[g_bw]
700
vdict1[g_tw] = fun_subs(eq_gtw_Elmol.rhs(), vdict1)
701
vdict1[g_sw] = fun_subs(eq_gsw_gtw.rhs(),vdict1)
702
703
704
# Inferring h_c from Hlmeas, Tlmeas and Tameas
705
vdict1[H_l] = Hlmeas
706
vdict1[h_c] = fun_subs(eq_hc_Hl.rhs(),vdict1)
707
708
709
#resdict = dict(vdict.items() + SSdict.items() + rdict1.items() + Balldict.items() + PMdict.items())
710
resdict = dict(vdict.items() + rdict1.items() + Balldict.items() + PMdict.items())
711
resdict['Tlmeas'] = Tlmeas
712
resdict['Elmeas'] = Elmeas
713
resdict['Elmolmeas'] = Elmolmeas
714
resdict['Hlmeas'] = Hlmeas
715
resdict['g_twmeas'] = vdict1[g_tw]
716
resdict['g_swmeas'] = vdict1[g_sw]
717
resdict['h_cmeas'] = vdict1[h_c]
718
results.append(tuple(list(lc_data[i]) + resdict.values()))
719
allinput.append(vdict)
720
#print resdict
721
names = [blah[0] for blah in lc_data.dtype.descr] + resdict.keys()
722
nameslist = [str(names[i]) for i in srange(len(names))]
723
formatslist = [blah[1] for blah in lc_data.dtype.descr] + ['f8' for i in srange(len(nameslist))]
724
#print results
725
#print zip(nameslist,formatslist)
726
try:
727
results = np.array(results,dtype = zip(nameslist,formatslist))
728
except:
729
print results
730
results1 = np.nan_to_num(results) # Converts any NaN to something that can be expressed as a float
731
print nameslist
732
print formatslist
733
print vdict
734
print results
735
return results
736
737
return results
738
739
740
# In[17]:
741
742
def fun_plot_diag(results1, varname1 = 'v_w', axeslabel1 = 'Wind speed (m s$^{-1}$)', Emods = [('E_l', '(mod.)', '-')], Hmods = [('H_l', '(mod.)', '-')], Rmods = [('R_ll', '(mod.)', '-')], energy=True, esums = False, esumsmod = False, rll = False, Hobs = True, fsize = 20, lfsize = 20, axfsize = 1.2, psize = 100, figsize1=[8,6], dpi1 = 50, leglength = 2, lwidth = 2, fname = False):
743
'''
744
Sorts results1 for variable varname1 and plots diagnostic plots
745
for energy, esums, leaftemp, alltemps (set either of them to False
746
if not desired).
747
Example:
748
sage: fun_plot_diag(results1, varname1 = 'v_w', axeslabel1 = 'Wind speed (m s$^{-1}$)', Emods = [('E_l', '(mod.)', '-')], Hmods = [('H_l', '(mod.)', '-')], Tmods = [('T_l', '(mod.)', '-')], energy=True, esums = True, leaftemp = True, alltemps = alltemps = [('T_leaf1', 'TC1', 'v'), ('T_leaf2', 'TC2', '^'), ('T_leaf_IR', 'TCIR', '.')], fsize = 10, lfsize = 'large', axfsize = 1.2, psize = 100, figsize1=[7,5], fname = False, fext = '.png')
749
'''
750
751
# Sorting array along v_w
752
results2 = results1.copy()
753
results2 = np.sort(results2, order = varname1)
754
pos_vw = srange(len(results2))
755
xdata = results2[varname1][pos_vw]
756
Talist = results2['T_a'][pos_vw]
757
758
if energy:
759
P = list_plot(zip(xdata,results2['Elmeas'][pos_vw]), frame = True, axes = False, plotjoined=False, marker='o', size=psize, legend_label = '$E_l$ (obs.)')
760
for i in srange(len(Emods)):
761
tup1 = Emods[i]
762
if len(tup1)<4:
763
tup1 = tuple(list(tup1) + ['blue'])
764
P += list_plot(zip(xdata,results2[tup1[0]][pos_vw]), color = tup1[3], plotjoined=True, thickness = lwidth, linestyle=tup1[2], marker=None, legend_label = '$E_l$ ' + tup1[1])
765
if Hobs:
766
P += list_plot(zip(xdata,results2['Hlmeas'][pos_vw]), marker='o', faceted = True, color = 'white', markeredgecolor = 'black', size=psize, plotjoined=False, legend_label = '$H_l$ (obs.)')
767
for i in srange(len(Hmods)):
768
tup1 = Hmods[i]
769
if len(tup1)<4:
770
tup1 = tuple(list(tup1) + ['black'])
771
P += list_plot(zip(xdata,results2[tup1[0]][pos_vw]), color = tup1[3], plotjoined=True, thickness = lwidth, linestyle=tup1[2], marker=None, legend_label = '$H_l$ ' + tup1[1])
772
P.axes_labels([axeslabel1, 'Energy flux from leaf (W m$^{-2}$)'])
773
774
if esums:
775
P += list_plot(zip(xdata,results2['Elmeas'][pos_vw]+results2['Hlmeas'][pos_vw]), frame = True, axes = False, plotjoined=False, marker='s', faceted = True, color = 'red', markeredgecolor = 'black', size=psize, legend_label = '$E_l + H_l$ (obs.)')
776
if esumsmod:
777
for i in srange(len(Hmods)):
778
P += list_plot(zip(xdata,results2[Emods[i][0]][pos_vw]+results2[Hmods[i][0]][pos_vw]), frame = True, axes = False, plotjoined=True, thickness = 2*lwidth, linestyle=Emods[i][2], color = 'red', marker=None, legend_label = '$E_l + H_l$ ' + Emods[i][1])
779
if rll:
780
781
if 'Rn_leaf' in results2.dtype.names:
782
P += list_plot(zip(xdata,results2['Rn_leaf'][pos_vw]), plotjoined=False, marker='o', faceted = True, color = 'red', markeredgecolor = 'black', size=psize, legend_label = '$R_{nleaf}$ (obs.)')
783
for i in srange(len(Rmods)):
784
P += list_plot(zip(xdata,results2['R_s'][pos_vw] - results2[Rmods[i][0]][pos_vw]), frame = True, axes = False, plotjoined=True, color = 'red', thickness = 2*lwidth, linestyle=Rmods[i][2], marker=None, legend_label = '$R_s - R_{ll}$ ' + Rmods[i][1])
785
786
P.axes_labels([axeslabel1, 'Energy flux from leaf (W m$^{-2}$)'])
787
P.show(dpi = dpi1, fontsize = fsize, axes_labels_size = axfsize, fig_tight = True, figsize=figsize1, aspect_ratio = 'automatic', legend_font_size = lfsize, legend_loc=(1.01,0), legend_handlelength=leglength)
788
if fname:
789
P.save(fname, fontsize = fsize, axes_labels_size = axfsize, fig_tight = True, figsize=figsize1, aspect_ratio = 'automatic', legend_font_size = lfsize, legend_loc=(1.01,0), legend_handlelength=leglength)
790
791
792
# # Experiments in the dark
793
794
# ## Black foil, 35.4 holes/mm2, Figures 6b and 7b in http://www.hydrol-earth-syst-sci-discuss.net/hess-2016-363/
795
796
# In[18]:
797
798
fname = 'exp_35_4_Tdew.csv'
799
lc_data_orig = fun_read_csv(fname, lc_timepos = [0, 16, 25, 26, 30, 31])
800
lc_data = lc_data_orig.copy()
801
lc_data['water_flow_avg'] = -lc_data_orig['water_flow_avg'] # Making flow positive
802
lc_data_orig = lc_data.copy()
803
lc_data_35_Pwa = lc_data.copy()
804
805
806
# In[19]:
807
808
# Fig. 6b
809
vdict = cdict.copy()
810
vdict[a_s] = 1
811
vdict[L_l] = 0.03
812
vdict[P_a] = 101325.
813
vdict[R_s] = 0
814
vdict[Re_c] = 3000.
815
vdict[g_sw] = 0.035 # According to perforated_foils_LO: range 0.023-0.051
816
results_orig = fun_results(lc_data, vdict1 = vdict)
817
results1 = results_orig.copy()
818
results_35 = results_orig.copy()
819
list_vars = ['R_s', 'P_wa', 'T_a', 'v_w', 'g_sw']
820
for var1 in list_vars:
821
print var1 + ' = (' + str(min(results1[var1])) + ', ' + str(max(results1[var1])) + ') ' + str(udict[eval(var1)]/eval(var1))
822
fname = path_figs + '35_Pwa.eps'
823
824
fun_plot_diag(results1, varname1 = 'P_wa', axeslabel1 = 'Vapour pressure (Pa)', Emods = [('E_l', '(mod.)', '-')], Hmods = [('H_l', '(mod.)', '-')], Rmods = [('R_ll', '(mod.)', '-')], esums = True, rll = True, dpi1=50, fname=fname)
825
826
827
# In[20]:
828
829
# fig. 7b
830
fname = path_figs + '35_Pwa_anal.eps'
831
fun_plot_diag(results1, varname1 = 'P_wa', axeslabel1 = 'Vapour pressure (Pa)', Emods = [('lin_E_l', '(Rlin)', '-'), ('PS_E_l', '(MUc)', '-.'), ('PM_E_l', '(PM)', '--'), ('MU_E_l', '(MU)', ':')], Hmods = [('lin_H_l', '(Rlin)', '-'), ('PS_H_l', '(MUc)', '-.'), ('PM_H_l', '(PM)', '--'), ('MU_H_l', '(MU)', ':')], fname=fname)
832
833
834
# ## 35.4 holes/mm2, varying wind speed, Figures 6a and 7a in http://www.hydrol-earth-syst-sci-discuss.net/hess-2016-363/
835
#
836
837
# In[21]:
838
839
fname = 'exp_35_4_vw.csv'
840
lc_data_orig = fun_read_csv(fname, lc_timepos = [])
841
lc_data = lc_data_orig.copy()
842
lc_data['water_flow_avg'] = -lc_data_orig['water_flow_avg'] # Making flow positive
843
lc_data_orig = lc_data.copy()
844
845
846
# In[22]:
847
848
# Fig. 6a
849
vdict = cdict.copy()
850
vdict[a_s] = 1
851
vdict[L_l] = 0.03
852
vdict[P_a] = 101325.
853
vdict[R_s] = 0
854
vdict[Re_c] = 3000.
855
#vdict[g_sw] = (0.028+0.051)/2 # According to perforated_foils_LO: range 0.027--0.042
856
vdict[g_sw] = 0.042
857
print vdict[g_sw]
858
results_orig = fun_results(lc_data, vdict)
859
results1 = results_orig.copy()
860
list_vars = ['R_s', 'P_wa', 'T_a', 'v_w', 'g_sw']
861
for var1 in list_vars:
862
print var1 + ' = (' + str(min(results1[var1])) + ', ' + str(max(results1[var1])) + ') ' + str(udict[eval(var1)]/eval(var1))
863
864
fname = path_figs + '35_vw.eps'
865
fun_plot_diag(results1, Emods = [('E_l', '(mod.)', '-')], Hmods = [('H_l', '(mod.)', '-')], Rmods = [('R_ll', '(mod.)', '-')], esums = True, rll = True, dpi1=50, fname=fname)
866
867
868
# In[23]:
869
870
# Fig. 7a
871
fname = path_figs + '35_vw_anal.eps'
872
fun_plot_diag(results1, Emods = [('lin_E_l', '(Rlin)', '-'), ('PS_E_l', '(MUc)', '-.'), ('PM_E_l', '(PM)', '--'), ('MU_E_l', '(MU)', ':')], Hmods = [('lin_H_l', '(Rlin)', '-'), ('PS_H_l', '(MUc)', '-.'), ('PM_H_l', '(PM)', '--'), ('MU_H_l', '(MU)', ':')], fname=fname)
873
874
875
# ## Leaf 7_1, Figures 6c and 7c
876
# (in http://www.hydrol-earth-syst-sci-discuss.net/hess-2016-363/)
877
878
# In[24]:
879
880
fname1 = 'new_tunnel_chamber_2Tin_leaf.csv'
881
fname = path_data + fname1
882
try:
883
reader = csv.reader(open(fname, 'rb'), delimiter=',', quotechar='"')
884
except:
885
copyfile(path_data_orig + fname1, fname)
886
reader = csv.reader(open(fname, 'rb'), delimiter=',', quotechar='"')
887
888
nameslist = reader.next()
889
unitslist = reader.next()
890
ncols = len(nameslist)
891
print ncols
892
print nameslist
893
print unitslist
894
csvdata = []
895
for row in reader :
896
row1 = np.array(row)
897
# replacing empty fields by NaN
898
row1[row1==''] = 'NaN'
899
row = tuple(row1)
900
csvdata.append(row)
901
902
formatslist = []
903
for i in srange(len(unitslist)):
904
if unitslist[i] == '':
905
formatslist.append('S100')
906
else:
907
formatslist.append('float')
908
data = np.array(csvdata,dtype = zip(nameslist,formatslist))
909
data_orig = data.copy()
910
911
tabledata = []
912
tabledata.append(list(nameslist))
913
tabledata.append(list(unitslist))
914
for i in srange(len(data)):
915
line1 = data[i]
916
tabledata.append(list(line1) )
917
#print tabledata
918
table(tabledata)
919
920
921
# In[25]:
922
923
data.dtype
924
925
926
# In[26]:
927
928
# Identifying the data sets with low and high wind speed
929
pos_vlow = [3,4,5,6,7,9]
930
pos_vhigh = [10,11]
931
932
933
# In[27]:
934
935
# Fig. 6c
936
vdict = cdict.copy()
937
vdict[a_s] = 1
938
vdict[L_l] = 0.03
939
vdict[P_a] = 101325.
940
vdict[R_s] = 0
941
vdict[Re_c] = 3000.
942
vdict[g_sw] = 0.0065 # Range: 0.005 to 0.01
943
ndict = {R_s: '', T_d: 'Tdew humidifier', T_l: 'Tlin', Q_in: 'Fan power', S_a: 'Rn_above_leaf', S_b: 'Rn_below_leaf', S_s: 'Rn_beside_leaf', T_in: 'Incoming2 Temp_C(5)', F_in_v: 'Inflow rate', v_w: 'Wind speed', T_a: 'chamber air Temp_C(1) ', E_lmol: 'Sensirion'}
944
945
results_orig = fun_results(data, vdict1=vdict, ndict1=ndict)
946
results1 = results_orig[pos_vlow]
947
list_vars = ['R_s', 'P_wa', 'T_a', 'v_w', 'g_sw']
948
for var1 in list_vars:
949
print var1 + ' = (' + str(min(results1[var1])) + ', ' + str(max(results1[var1])) + ') ' + str(udict[eval(var1)]/eval(var1))
950
fname = path_figs + '7_Pwa.eps'
951
fun_plot_diag(results1, varname1 = 'P_wa', axeslabel1 = 'Vapour pressure (Pa)', Emods = [('E_l', '(mod.)', '-')], Hmods = [('H_l', '(mod.)', '-')], Rmods = [('R_ll', '(mod.)', '-')], esums = True, rll = True, dpi1=50, fname=fname)
952
953
954
# In[28]:
955
956
fname = path_figs + '7_Pwa_anal.eps'
957
fun_plot_diag(results1, varname1 = 'P_wa', axeslabel1 = 'Vapour pressure (Pa)', Emods = [('lin_E_l', '(Rlin)', '-'), ('PS_E_l', '(MUc)', '-.'), ('PM_E_l', '(PM)', '--'), ('MU_E_l', '(MU)', ':')], Hmods = [('lin_H_l', '(Rlin)', '-'), ('PS_H_l', '(MUc)', '-.'), ('PM_H_l', '(PM)', '--'), ('MU_H_l', '(MU)', ':')], fname=fname)
958
959
960
# ### Comparison of 35 and 7 pores/mm2
961
962
# In[29]:
963
964
leglength=2
965
lfsize = 12
966
axfsize = 18
967
figsize1 = [6,5]
968
psize = 24
969
varname1 = 'P_wa'
970
axeslabel1 = 'Vapour pressure (Pa)'
971
Emods = [('E_l', '(mod., 35)', ':')]
972
Hmods = [('H_l', '(mod., 35)', ':')]
973
lwidth = 3
974
975
# 35 holes data
976
results2 = results_35.copy()
977
978
results2 = np.sort(results2, order = varname1)
979
pos_vw = srange(len(results2))
980
xdata = results2[varname1][pos_vw]
981
Talist = results2['T_a'][pos_vw]
982
983
P = list_plot(zip(xdata,results2['Elmeas'][pos_vw]), frame = True, axes = False, plotjoined=False, marker='s', size=psize, legend_label = '$E_l$ (obs., 35)')
984
for i in srange(len(Emods)):
985
tup1 = Emods[i]
986
if len(tup1)<4:
987
tup1 = tuple(list(tup1) + ['blue'])
988
P += list_plot(zip(xdata,results2[tup1[0]][pos_vw]), color = tup1[3], plotjoined=True, thickness = lwidth, linestyle=tup1[2], marker=None, legend_label = '$E_l$ ' + tup1[1])
989
990
P += list_plot(zip(xdata,results2['Hlmeas'][pos_vw]), marker='s', faceted = True, color = 'white', markeredgecolor = 'black', size=psize, plotjoined=False, legend_label = '$H_l$ (obs., 35)')
991
for i in srange(len(Hmods)):
992
tup1 = Hmods[i]
993
if len(tup1)<4:
994
tup1 = tuple(list(tup1) + ['black'])
995
P += list_plot(zip(xdata,results2[tup1[0]][pos_vw]), color = tup1[3], plotjoined=True, thickness = lwidth, linestyle=tup1[2], marker=None, legend_label = '$H_l$ ' + tup1[1])
996
997
998
# Now adding 7 pores / mm2
999
#Emods = [('E_l', '(S-mod.)', '-'), ('El_ball', '(B-mod.)', '--')]
1000
#Hmods = [('H_l', '(S-mod.)', '-'), ('Hl_ball', '(B-mod.)', '--')]
1001
Emods = [('E_l', '(mod., 7)', '--')]
1002
Hmods = [('H_l', '(mod., 7)', '--')]
1003
lwidth = 2
1004
1005
# Sorting array along v_w
1006
results2 = results1.copy()
1007
1008
results2 = np.sort(results2, order = varname1)
1009
pos_vw = srange(len(results2))
1010
xdata = results2[varname1][pos_vw]
1011
Talist = results2['T_a'][pos_vw]
1012
1013
P += list_plot(zip(xdata,results2['Elmeas'][pos_vw]), frame = True, axes = False, plotjoined=False, marker='o', size=psize, legend_label = '$E_l$ (obs., 7)')
1014
for i in srange(len(Emods)):
1015
tup1 = Emods[i]
1016
if len(tup1)<4:
1017
tup1 = tuple(list(tup1) + ['blue'])
1018
P += list_plot(zip(xdata,results2[tup1[0]][pos_vw]), color = tup1[3], plotjoined=True, thickness = lwidth, linestyle=tup1[2], marker=None, legend_label = '$E_l$ ' + tup1[1])
1019
1020
P += list_plot(zip(xdata,results2['Hlmeas'][pos_vw]), marker='o', faceted = True, color = 'white', markeredgecolor = 'black', size=psize, plotjoined=False, legend_label = '$H_l$ (obs., 7)')
1021
for i in srange(len(Hmods)):
1022
tup1 = Hmods[i]
1023
if len(tup1)<4:
1024
tup1 = tuple(list(tup1) + ['black'])
1025
P += list_plot(zip(xdata,results2[tup1[0]][pos_vw]), color = tup1[3], plotjoined=True, thickness = lwidth, linestyle=tup1[2], marker=None, legend_label = '$H_l$ ' + tup1[1])
1026
1027
1028
1029
P.axes_labels([axeslabel1, 'Energy flux from leaf (W m$^{-2}$)'])
1030
P.show(fontsize = lfsize, fig_tight = True, figsize=figsize1, aspect_ratio = 'automatic', legend_font_size = lfsize, legend_handlelength=leglength, legend_loc=(1.01,0.))
1031
1032
1033
# # Simulations for varying radiation and air temperature (Fig. 8)
1034
# (in http://www.hydrol-earth-syst-sci-discuss.net/hess-2016-363/)
1035
1036
# In[30]:
1037
1038
# Fig. 8a
1039
# Conditions similar to experiment with 35.4 holes/mm2
1040
vdict = cdict.copy()
1041
vdict[a_s] = 1.0 # one sided stomata
1042
vdict[g_sw] = 0.045
1043
vdict[T_a] = 295
1044
vdict[T_w] = vdict[T_a] # Wall temperature equal to air temperature
1045
vdict[P_a] = 101325
1046
rha = 0.5
1047
vdict[P_wa] = rha*eq_Pwl.rhs()(T_l = T_a).subs(vdict)
1048
vdict[L_l] = 0.03
1049
#vdict[L_A] = vdict[L_l]^2
1050
vdict[Re_c] = 3000
1051
vdict[R_s] = 0.
1052
#vdict[Q_in] = 0
1053
vdict[v_w] = 1.0
1054
resdict = fun_SS_PM(vdict)
1055
1056
dict_results = {}
1057
1058
for key1 in resdict.keys():
1059
dict_results[key1] = [resdict[key1]]
1060
1061
1062
1063
list_Rs = srange(0, 800, 100)
1064
1065
for Rs in list_Rs:
1066
vdict[R_s] = Rs
1067
resdict = fun_SS_PM(vdict)
1068
1069
for key1 in resdict.keys():
1070
dict_results[key1].append(resdict[key1])
1071
1072
dict_results1 = {}
1073
for key1 in dict_results.keys():
1074
dict_results1[key1] = np.array(dict_results[key1])
1075
1076
results1 = dict_results1.copy()
1077
list_vars = [R_s, P_wa, T_a, v_w, g_sw]
1078
for var1 in list_vars:
1079
print str(var1) + ' = (' + str(min(results1[var1])) + ', ' + str(max(results1[var1])) + ') ' + str(udict[var1]/var1)
1080
1081
xdata = dict_results1[R_s]
1082
vary = [(dict_results1[E_l], 'x', 'blue', '$E_{l}$ (S-mod.)'), (dict_results1[H_l], 'x', 'black', '$H_{l}$ (S-mod.)'), (dict_results1['lin_E_l'], '-', 'blue', '$E_{l}$ (Rlin)'), (dict_results1['lin_H_l'], '-', 'black', '$H_{l}$ (Rlin)'), (dict_results1['PM_E_l'], '--', 'blue', '$E_{l}$ (PM)'), (dict_results1['PM_H_l'], '--', 'black', '$H_{l}$ (PM)')]
1083
1084
fsize = 20
1085
lfsize = 20
1086
axfsize = 1.2
1087
psize = 100
1088
figsize1=[8,6]
1089
xlabel = 'Absorbed shortwave radiation (W m$^{-2}$)'
1090
ylabel = 'Energy flux from leaf (W m$^{-2}$)'
1091
i = 0
1092
P = list_plot(zip(xdata, vary[i][0]), plotjoined=False, marker=vary[i][1], size=psize, faceted = True, color = vary[i][2], legend_label=vary[i][3])
1093
for i in srange(1,2):
1094
P += list_plot(zip(xdata, vary[i][0]), plotjoined=False, marker=vary[i][1], size=psize, color = vary[i][2], legend_label=vary[i][3])
1095
for i in srange(2,len(vary)):
1096
P += list_plot(zip(xdata, vary[i][0]), plotjoined=True, linestyle = vary[i][1], color=vary[i][2], legend_label=vary[i][3])
1097
P.axes_labels([xlabel, ylabel])
1098
P.show(fontsize = fsize, axes_labels_size = axfsize, fig_tight = True, figsize=figsize1, aspect_ratio = 'automatic', legend_font_size = lfsize, legend_loc=(1.01,0))
1099
P.save(path_figs + 'numexp_Rs.png', fontsize = fsize, axes_labels_size = axfsize, fig_tight = True, figsize=figsize1, aspect_ratio = 'automatic', legend_font_size = 14, legend_loc=(1.01,0))
1100
1101
1102
# In[31]:
1103
1104
# Fig. 8b
1105
# Conditions similar to experiment with 35.4 holes/mm2, 350 W/m2 irradiance
1106
Tlow = 282.
1107
Thigh = 300.
1108
vdict = cdict.copy()
1109
vdict[a_s] = 1.0 # one sided stomata
1110
vdict[g_sw] = 0.045
1111
vdict[T_a] = Tlow
1112
vdict[T_w] = vdict[T_a] # Wall temperature equal to air temperature
1113
vdict[P_a] = 101325
1114
rha = 0.5
1115
vdict[P_wa] = rha*eq_Pwl.rhs()(T_l = T_a).subs(vdict)
1116
vdict[L_l] = 0.03
1117
#vdict[L_A] = vdict[L_l]^2
1118
vdict[Re_c] = 3000
1119
vdict[R_s] = 350.
1120
#vdict[Q_in] = 0
1121
vdict[v_w] = 1.0
1122
resdict = fun_SS_PM(vdict)
1123
1124
dict_results = {}
1125
1126
for key1 in resdict.keys():
1127
dict_results[key1] = [resdict[key1]]
1128
1129
1130
1131
list_Ta = srange(Tlow, Thigh, 2)
1132
1133
for Ta in list_Ta:
1134
vdict[T_a] = Ta
1135
vdict[T_w] = vdict[T_a] # Wall temperature equal to air temperature
1136
resdict = fun_SS_PM(vdict)
1137
1138
for key1 in resdict.keys():
1139
dict_results[key1].append(resdict[key1])
1140
1141
dict_results1 = {}
1142
for key1 in dict_results.keys():
1143
dict_results1[key1] = np.array(dict_results[key1])
1144
1145
results1 = dict_results1.copy()
1146
list_vars = [R_s, P_wa, T_a, v_w, g_sw]
1147
for var1 in list_vars:
1148
print str(var1) + ' = (' + str(min(results1[var1])) + ', ' + str(max(results1[var1])) + ') ' + str(udict[var1]/var1)
1149
1150
xdata = dict_results1[T_a]
1151
vary = [(dict_results1[E_l], 'x', 'blue', '$E_{l}$ (S-mod.)'), (dict_results1[H_l], 'x', 'black', '$H_{l}$ (S-mod.)'), (dict_results1['lin_E_l'], '-', 'blue', '$E_{l}$ (Rlin)'), (dict_results1['lin_H_l'], '-', 'black', '$H_{l}$ (Rlin)'), (dict_results1['PM_E_l'], '--', 'blue', '$E_{l}$ (PM)'), (dict_results1['PM_H_l'], '--', 'black', '$H_{l}$ (PM)')]
1152
1153
fsize = 20
1154
lfsize = 20
1155
axfsize = 1.2
1156
psize = 100
1157
figsize1=[8,6]
1158
xlabel = 'Air temperature (K)'
1159
ylabel = 'Energy flux from leaf (W m$^{-2}$)'
1160
i = 0
1161
P = list_plot(zip(xdata, vary[i][0]), plotjoined=False, marker=vary[i][1], size=psize, color = vary[i][2], legend_label=vary[i][3])
1162
for i in srange(1,2):
1163
P += list_plot(zip(xdata, vary[i][0]), plotjoined=False, marker=vary[i][1], size=psize, color = vary[i][2], legend_label=vary[i][3])
1164
for i in srange(2,len(vary)):
1165
P += list_plot(zip(xdata, vary[i][0]), plotjoined=True, linestyle = vary[i][1], color=vary[i][2], legend_label=vary[i][3])
1166
P.axes_labels([xlabel, ylabel])
1167
P.show(fontsize = fsize, axes_labels_size = axfsize, fig_tight = True, figsize=figsize1, aspect_ratio = 'automatic', legend_font_size = lfsize, legend_loc=(1.01,0))
1168
P.save(path_figs + 'numexp_T.png', fontsize = fsize, axes_labels_size = axfsize, fig_tight = True, figsize=figsize1, aspect_ratio = 'automatic', legend_font_size = 14, legend_loc=(1.01,0))
1169
1170
1171
# In[ ]:
1172
1173
1174
1175
1176