Urban-Plumber2: UK-Kin site CLMU5 simulation
[1]:
from pyclmuapp import usp_clmu
import matplotlib.pyplot as plt
import xarray as xr
import numpy as np
[2]:
%%time
# initialize
usp = usp_clmu()
# here we use the default surface data, which is the london uk-kin data
# lat = 51.5116, lon = -0.1167
# this forcing derived from urban-plumber forcing data
usp_london = usp.run(
case_name = "UK_Kin_default",
SURF="surfdata.nc",
FORCING="forcing.nc",
RUN_STARTDATE = "2002-01-01",
STOP_OPTION = "nyears",
STOP_N = "12",
)
usp_london
Copying the file forcing.nc to the /Users/user/Documents/GitHub/pyclmuapp/docs/notebooks/val/workdir/inputfolder/usp
CPU times: user 1.18 s, sys: 493 ms, total: 1.68 s
Wall time: 16min 47s
[2]:
['/Users/user/Documents/GitHub/pyclmuapp/docs/notebooks/val/workdir/outputfolder/lnd/hist/UK_Kin_default_clm0_2024-12-10_13-49-57_clm.nc']
[3]:
london_nc = usp.nc_view(usp_london[0]).sel(time=slice('2012-01-01', '2014-12-31'))
london_nc
[3]:
<xarray.Dataset> Size: 25MB Dimensions: (levgrnd: 25, levlak: 10, levdcmp: 1, time: 35089, hist_interval: 2, lndgrid: 1, column: 6, gridcell: 1, landunit: 2, pft: 6, levsoi: 20) Coordinates: * levgrnd (levgrnd) float32 100B 0.01 0.04 0.09 ... 28.87 42.0 * levlak (levlak) float32 40B 0.05 0.6 2.1 ... 25.6 34.33 44.78 * levdcmp (levdcmp) float32 4B 1.0 * time (time) datetime64[ns] 281kB 2012-01-01 ... 2014-01-01 Dimensions without coordinates: hist_interval, lndgrid, column, gridcell, landunit, pft, levsoi Data variables: (12/129) mcdate (time) int32 140kB ... mcsec (time) int32 140kB ... mdcur (time) int32 140kB ... mscur (time) int32 140kB ... nstep (time) int32 140kB ... time_bounds (time, hist_interval) datetime64[ns] 561kB ... ... ... URBAN_AC (time, gridcell) float32 140kB ... URBAN_HEAT (time, gridcell) float32 140kB ... WASTEHEAT (time, gridcell) float32 140kB ... WBT (time, gridcell) float32 140kB ... Wind (time, gridcell) float32 140kB ... ZWT (time, gridcell) float32 140kB ... Attributes: (12/38) title: CLM History file information comment: NOTE: None of the variables ar... Conventions: CF-1.0 history: created on 12/10/24 13:35:15 source: Community Land Model CLM4.0 hostname: clmu-app ... ... ctype_urban_shadewall: 73 ctype_urban_impervious_road: 74 ctype_urban_pervious_road: 75 cft_c3_crop: 1 cft_c3_irrigated: 2 time_period_freq: minute_30
import the observation data for comparison
[4]:
ds = xr.open_dataset('/Users/user/Documents/GitHub/pyclmuapp/inputfolder/Urban-PLUMBER/datm_files/UK-Kin/CLM1PT_data/UK-KingsCollege_clean_observations_v1.nc')
ds
[4]:
<xarray.Dataset> Size: 2MB Dimensions: (time: 30577) Coordinates: * time (time) datetime64[ns] 245kB 2012-04-04 ... 2014-01-01 Data variables: (12/28) SWdown (time) float32 122kB ... LWdown (time) float32 122kB ... Tair (time) float32 122kB ... Qair (time) float32 122kB ... PSurf (time) float32 122kB ... Rainf (time) float32 122kB ... ... ... Wind_E_qc (time) int8 31kB ... SWup_qc (time) int8 31kB ... LWup_qc (time) int8 31kB ... Qle_qc (time) int8 31kB ... Qh_qc (time) int8 31kB ... Qtau_qc (time) int8 31kB ... Attributes: (12/24) title: Flux tower observations from UK-KingsCollege ... summary: Quality controlled flux tower observations fo... sitename: UK-KingsCollege long_sitename: Kings College, London, United Kingdom version: v1 keywords: urban, flux tower, eddy covariance, observations ... ... observations_contact: Simone Kotthaus (kotthaus@ipsl.polytechnique.... observations_reference: Bjorkegren et al. (2015): https://doi.org/10.... date_created: 2022-09-22 16:27:09 source: https://github.com/matlipson/urban-plumber_pi... comment: Observations from KSSW tower history: v0.9 (2021-09-08): beta issue; v1 (2022-09-15...
[5]:
#round the time to the nearest minute
london_nc['time'] = london_nc['time'].dt.round('min')
# shift the time by 30 minutes to match the observations
london_nc['time'] = london_nc['time'] - np.timedelta64(1800, 's')
df = london_nc[['Qle','Qh','Qtau','SWup','LWup']].to_dataframe()
df_ds = ds[['Qle','Qh','Qtau','SWup','LWup']].to_dataframe()
df['Qtau'] = -df['Qtau']
df = df.merge(df_ds, on='time', suffixes=('_usp', '_obs'))
df.head(1)
[5]:
Qle_usp | Qh_usp | Qtau_usp | SWup_usp | LWup_usp | Qle_obs | Qh_obs | Qtau_obs | SWup_obs | LWup_obs | |
---|---|---|---|---|---|---|---|---|---|---|
time | ||||||||||
2012-04-04 | 31.69558 | 16.175985 | 0.030384 | 0.0 | 353.656372 | NaN | NaN | NaN | NaN | NaN |
[6]:
%%time
# modify the surface
# tree_area_fraction=0.03
# grass_area_fraction=0.04
# bare_soil_area_fraction=0.0
# water_area_fraction=0.14
# impervious_area_fraction=0.79
# roof fraction = 0.4
# raod fraction = 0.39
# topsoil_clay_fraction=0.26
# topsoil_sand_fraction=0.45
# PCT_CLAY = 0.26
# PCT_SAND = 0.45
action = {
#"ALB_ROOF_DIR": 0.109,
#"ALB_ROOF_DIF": 0.109,
"CANYON_HWR": 1.13,
"HT_ROOF": 21.3,
"WTLUNIT_ROOF": 0.4/(0.03+0.04+0.79),
"WTROAD_PERV": 1 - 0.39/(0.03+0.04+0.39),
#"ALB_IMPROAD_DIR": 0.109,
#"ALB_IMPROAD_DIF": 0.109,
#"ALB_PERROAD_DIR": 0.109,
#"ALB_PERROAD_DIF": 0.109,
#"WIND_HGT_CANYON": 50
}
usp.modify_surf(action=action, surfata_name="surface_modfied_UK_Kin.nc", mode="replace", urban_type=2)
CPU times: user 229 ms, sys: 82.7 ms, total: 311 ms
Wall time: 491 ms
[7]:
usp_london_detail = usp.run(
case_name = "UK_Kin_detail",
RUN_STARTDATE = "2002-01-01",
STOP_OPTION = "nyears",
STOP_N = "12",
RUN_TYPE= "coldstart",
)
usp_london_detail
[7]:
['/Users/user/Documents/GitHub/pyclmuapp/docs/notebooks/val/workdir/outputfolder/lnd/hist/UK_Kin_detail_clm0_2024-12-10_14-06-56_clm.nc']
[8]:
ludon_detail_nc = usp.nc_view(usp_london_detail[0]).sel(time=slice('2012-01-01', '2014-12-31'))
ludon_detail_nc['time'] = ludon_detail_nc['time'].dt.round('min')
ludon_detail_nc['time'] = ludon_detail_nc['time'] - np.timedelta64(1800, 's')
df_ds = ds[['Qle','Qh','Qtau','SWup','LWup']].to_dataframe()
df_detail = ludon_detail_nc[['Qle','Qh','Qtau','SWup','LWup']].to_dataframe()
df_detail['Qtau'] = -df_detail['Qtau']
df_detail = df_detail.merge(df_ds, on='time', suffixes=('_usp', '_obs'))
df_detail.head(1)
[8]:
Qle_usp | Qh_usp | Qtau_usp | SWup_usp | LWup_usp | Qle_obs | Qh_obs | Qtau_obs | SWup_obs | LWup_obs | |
---|---|---|---|---|---|---|---|---|---|---|
time | ||||||||||
2012-04-04 | 35.300236 | 16.307856 | 0.029534 | 0.0 | 352.476349 | NaN | NaN | NaN | NaN | NaN |
[9]:
from sklearn.metrics import mean_squared_error, mean_absolute_error
import seaborn as sns
import warnings
from datetime import datetime
from scipy.stats import pearsonr
warnings.filterwarnings('ignore')
def plotting(df, save_path):
var_list = ['SWup','LWup','Qle','Qh','Qtau']
unit = ['W/m$\mathrm{^{2}}$', 'W/m$\mathrm{^{2}}$', 'W/m$\mathrm{^{2}}$', 'W/m$\mathrm{^{2}}$', 'N/m$\mathrm{^{2}}$']
lim = [[-10, 130], [280, 600], [-120, 350], [-150, 500], [-0.1, 1.3]]
for var in var_list:
fig = plt.figure(figsize=(12, 5))
df_plot = df[[f'{var}_usp', f'{var}_obs']].dropna()
df_mean = df_plot[[f'{var}_usp', f'{var}_obs']].groupby(df_plot.index.hour).mean()
df_std = df_plot[[f'{var}_usp', f'{var}_obs']].groupby(df_plot.index.hour).std()
mae = mean_absolute_error(df_plot[f'{var}_obs'],df_plot[f'{var}_usp'])
#mean_absolute_percentage_error(df_plot[f'{var}_usp'], df_plot[f'{var}_obs'])#mean_squared_error(df_plot[f'{var}_usp'], df_plot[f'{var}_obs'])
R, _ = pearsonr(df_plot[f'{var}_usp'], df_plot[f'{var}_obs'])
ax = fig.add_subplot(1, 2, 1)
if var == 'SWup':
for h in range(0,24):
if h not in df_mean.index:
df_mean.loc[h] = [0,0]
df_std.loc[h] = [0,0]
df_mean = df_mean.sort_index()
df_std = df_std.sort_index()
ax.plot(df_mean.index, df_mean[f'{var}_usp'], color="#E02927", label='Simulated')
ax.fill_between(df_mean.index, df_mean[f'{var}_usp']-df_std[f'{var}_usp'], df_mean[f'{var}_usp']+df_std[f'{var}_usp'], color="#E02927", alpha=0.2)
ax.plot(df_mean.index, df_mean[f'{var}_obs'], color="#3964DF", label='Observed')
ax.fill_between(df_mean.index, df_mean[f'{var}_obs']-df_std[f'{var}_obs'], df_mean[f'{var}_obs']+df_std[f'{var}_obs'], color="#3964DF", alpha=0.2)
ax.set_ylabel(f'{var} [{unit[var_list.index(var)]}]', fontsize=14)
ax.set_xlabel('Local hour of day', fontsize=14)
ax.set_title(f'MAE: {mae:.2f}, R: {R:.2f}', fontsize=14, loc='left')
ax.tick_params(axis='both', which='major', labelsize=12)
ax.legend(frameon=False, fontsize=14)
ax = fig.add_subplot(1, 2, 2)
h = sns.histplot(
x=f'{var}_usp',
y=f'{var}_obs',
data=df_plot,
ax=ax,
cmap='rainbow',
bins=120,
#cbar=True,
#cbar_kws={'label': 'Counts'},
)
cbar = h.figure.colorbar(h.collections[0], ax=ax)
cbar.set_label('Counts', fontsize=14)
cbar.ax.tick_params(labelsize=12)
ax.plot(lim[var_list.index(var)], lim[var_list.index(var)], color='black', linestyle='--')
ax.tick_params(axis='both', which='major', labelsize=12)
ax.set_xlabel(f'Simulated {var} [{unit[var_list.index(var)]}]', fontsize=14)
ax.set_ylabel(f'Observed {var} [{unit[var_list.index(var)]}]', fontsize=14)
ax.set_xlim(lim[var_list.index(var)])
ax.set_ylim(lim[var_list.index(var)])
print(f'{var} MAE: {mae:.2f}')
fig.tight_layout()
fig.savefig(save_path + f'_{var}.pdf', dpi=300, bbox_inches='tight')
plt.show()
[10]:
plotting(df, 'figs/CLMU5_UK-Kin_default')
plotting(df_detail, 'figs/CLMU5_UK-Kin_detail')
SWup MAE: 4.69
LWup MAE: 5.50
Qle MAE: 23.39
Qh MAE: 52.93
Qtau MAE: 0.16
SWup MAE: 7.48
LWup MAE: 7.79
Qle MAE: 18.42
Qh MAE: 50.15
Qtau MAE: 0.15