Skip to content
Snippets Groups Projects
Commit 8c16f35e authored by Stefano Serafin's avatar Stefano Serafin
Browse files

fixed generation of random numbers, to really ensure reproducibility; minor fixes to plots

parent 68766142
Branches
Tags
No related merge requests found
...@@ -281,7 +281,7 @@ class cycle: ...@@ -281,7 +281,7 @@ class cycle:
localization_cutoff,\ localization_cutoff,\
inflate_rtps,\ inflate_rtps,\
inflation_rtps_alpha,\ inflation_rtps_alpha,\
RNG): rnseed):
# How many cycles do you need to run? # How many cycles do you need to run?
ncycles = int(trun/assimilation_interval) ncycles = int(trun/assimilation_interval)
...@@ -515,8 +515,13 @@ class experiment: ...@@ -515,8 +515,13 @@ class experiment:
elif self.obs_kinds[j]=='v': elif self.obs_kinds[j]=='v':
variable = nr.history['v'][:,time_index] variable = nr.history['v'][:,time_index]
truths[i,j] = observation_operator(variable,state_coordinates,obs_coordinate) truths[i,j] = observation_operator(variable,state_coordinates,obs_coordinate)
# Change the seed every time you go through this,
# otherwise the perturbations are always the same;
# and you have bias instead of randomness
seed = self.rnseed+j*1000+i*100000
RNG = np.random.default_rng(seed=seed)
observations[i,j] = truths[i,j]+\ observations[i,j] = truths[i,j]+\
self.RNG.normal(0,self.obs_error_sdev_generate[j]) RNG.normal(0,self.obs_error_sdev_generate[j])
# Store truths and observations # Store truths and observations
self.truths = truths self.truths = truths
...@@ -540,7 +545,7 @@ class experiment: ...@@ -540,7 +545,7 @@ class experiment:
self.localization_cutoff, self.localization_cutoff,
self.inflate_rtps, self.inflate_rtps,
self.inflation_rtps_alpha, self.inflation_rtps_alpha,
self.RNG) self.rnseed)
# Compute diagnostics # Compute diagnostics
if not hasattr(self,'dg'): if not hasattr(self,'dg'):
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import numpy as np import numpy as np
from matplotlib import pyplot as p from matplotlib import pyplot as p
import pickle import pickle
import os
from copy import deepcopy from copy import deepcopy
# Own modules # Own modules
...@@ -19,8 +20,8 @@ if __name__ == '__main__': ...@@ -19,8 +20,8 @@ if __name__ == '__main__':
sigma_o_gn = 0.0 # set equal to sigma_o_as in experiments C and F sigma_o_gn = 0.0 # set equal to sigma_o_as in experiments C and F
sigma_o_as = 0.1 # increased by a factor 10 in experiments C and F sigma_o_as = 0.1 # increased by a factor 10 in experiments C and F
# Initiate a random number generator with preset seed, to ensure reproducibility # Define seed for random number generation, to ensure reproducibility
RNG = np.random.default_rng(seed=181612) rnseed = 181612
# Default CBL model settings # Default CBL model settings
default_cbl_settings ={ default_cbl_settings ={
...@@ -47,12 +48,11 @@ if __name__ == '__main__': ...@@ -47,12 +48,11 @@ if __name__ == '__main__':
# Domain parameters (Kmax determines dt) # Domain parameters (Kmax determines dt)
'dz' : 50, 'dz' : 50,
'ztop' : 4000, 'ztop' : 4000,
'maxtime' : 10800,
# Ensemble generation parameters (only effective for ensemble runs) # Ensemble generation parameters (only effective for ensemble runs)
# Part 1: perturbation of initial state # Part 1: perturbation of initial state
# perturbation_type can be "smooth", "random", "uniform" # perturbation_type can be "smooth", "random", "uniform"
# the adjective refers to vertical variability # the adjective refers to vertical variability
'RNG' : RNG, 'rnseed' : rnseed,
'perturb_ensemble_state' : True, 'perturb_ensemble_state' : True,
'perturbations_type' : "smooth", 'perturbations_type' : "smooth",
'perturbations_theta_amplitude' : sigma_b_init, 'perturbations_theta_amplitude' : sigma_b_init,
...@@ -78,7 +78,7 @@ if __name__ == '__main__': ...@@ -78,7 +78,7 @@ if __name__ == '__main__':
# Default assimilation settings # Default assimilation settings
default_da_settings = {'cbl_settings' : default_cbl_settings, default_da_settings = {'cbl_settings' : default_cbl_settings,
'tspinup' : 3600, 'tspinup' : 3600,
'trun' : 10800, 'trun' : 21600,
'assimilation_interval' : 300, 'assimilation_interval' : 300,
'obs_coordinates' : np.linspace(0,2000,nobs), 'obs_coordinates' : np.linspace(0,2000,nobs),
'obs_kinds' : np.array(['theta']*nobs), 'obs_kinds' : np.array(['theta']*nobs),
...@@ -88,7 +88,8 @@ if __name__ == '__main__': ...@@ -88,7 +88,8 @@ if __name__ == '__main__':
'nens' : nens, 'nens' : nens,
'FILTER' : 'EAKF', 'FILTER' : 'EAKF',
'inflation_rtps_alpha' : 0.2, 'inflation_rtps_alpha' : 0.2,
'RNG' : RNG 'rnseed' : rnseed,
'path' : "./runs/seed=%s_enssize=%s_EAKF_6hrs/"%(rnseed,nens)
} }
# Safety check on time steps # Safety check on time steps
...@@ -99,6 +100,10 @@ if __name__ == '__main__': ...@@ -99,6 +100,10 @@ if __name__ == '__main__':
# Applies only to sets B&C; no-PE run is always computed for experiments A&D # Applies only to sets B&C; no-PE run is always computed for experiments A&D
noPE_runs = False noPE_runs = False
# Check if output path exists, if not, create it.
if not os.path.exists(default_da_settings['path']):
os.makedirs(default_da_settings['path'])
############################################################################ ############################################################################
# Experiment A (control) # Experiment A (control)
# Create a copy of the default settings # Create a copy of the default settings
...@@ -107,11 +112,11 @@ if __name__ == '__main__': ...@@ -107,11 +112,11 @@ if __name__ == '__main__':
# Run it # Run it
try: try:
exp_A = pickle.load(open("exp_A.pickle", "rb")) exp_A = pickle.load(open(default_da_settings['path']+"exp_A.pickle", "rb"))
except: except:
exp_A = experiment(da_settings_A) exp_A = experiment(da_settings_A)
setattr(exp_A,'label','A') setattr(exp_A,'label','A')
pickle.dump(exp_A, open('exp_A.pickle', 'wb')) pickle.dump(exp_A, open(default_da_settings['path']+'exp_A.pickle', 'wb'))
# Store the nature run, because it is used also in other experiments/figures # Store the nature run, because it is used also in other experiments/figures
exp_A.nr.has_parameters_in_state = True exp_A.nr.has_parameters_in_state = True
...@@ -127,14 +132,15 @@ if __name__ == '__main__': ...@@ -127,14 +132,15 @@ if __name__ == '__main__':
da_settings_A_noPE['observations'] = observations da_settings_A_noPE['observations'] = observations
da_settings_A_noPE['nr'].do_parameter_estimation = False da_settings_A_noPE['nr'].do_parameter_estimation = False
cbl_settings_A_noPE['do_parameter_estimation'] = False cbl_settings_A_noPE['do_parameter_estimation'] = False
cbl_settings_A_noPE['initial_perturbed_parameters'] = exp_A.da.initial_perturbed_parameters
da_settings_A_noPE['cbl_settings'] = cbl_settings_A_noPE da_settings_A_noPE['cbl_settings'] = cbl_settings_A_noPE
# Run it # Run it
try: try:
exp_A_noPE = pickle.load(open("exp_A_noPE.pickle", "rb")) exp_A_noPE = pickle.load(open(default_da_settings['path']+'exp_A_noPE.pickle', "rb"))
except: except:
exp_A_noPE = experiment(da_settings_A_noPE) exp_A_noPE = experiment(da_settings_A_noPE)
pickle.dump(exp_A_noPE, open('exp_A_noPE.pickle', 'wb')) pickle.dump(exp_A_noPE, open(default_da_settings['path']+'exp_A_noPE.pickle', 'wb'))
######################################################################## ########################################################################
# Experiment B1 # Experiment B1
...@@ -154,11 +160,11 @@ if __name__ == '__main__': ...@@ -154,11 +160,11 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B1 = pickle.load(open("exp_B1.pickle", "rb")) exp_B1 = pickle.load(open(default_da_settings['path']+'exp_B1.pickle', "rb"))
except: except:
exp_B1 = experiment(da_settings_B1) exp_B1 = experiment(da_settings_B1)
setattr(exp_B1,'label','B1') setattr(exp_B1,'label','B1')
pickle.dump(exp_B1, open('exp_B1.pickle', 'wb')) pickle.dump(exp_B1, open(default_da_settings['path']+'exp_B1.pickle', 'wb'))
if noPE_runs: if noPE_runs:
# Corresponding experiment without parameter estimation # Corresponding experiment without parameter estimation
...@@ -171,10 +177,10 @@ if __name__ == '__main__': ...@@ -171,10 +177,10 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B1_noPE = pickle.load(open("exp_B1_noPE.pickle", "rb")) exp_B1_noPE = pickle.load(open(default_da_settings['path']+'exp_B1_noPE.pickle', "rb"))
except: except:
exp_B1_noPE = experiment(da_settings_B1_noPE) exp_B1_noPE = experiment(da_settings_B1_noPE)
pickle.dump(exp_B1_noPE, open('exp_B1_noPE.pickle', 'wb')) pickle.dump(exp_B1_noPE, open(default_da_settings['path']+'exp_B1_noPE.pickle', 'wb'))
######################################################################## ########################################################################
# Experiment B2 # Experiment B2
...@@ -194,11 +200,11 @@ if __name__ == '__main__': ...@@ -194,11 +200,11 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B2 = pickle.load(open("exp_B2.pickle", "rb")) exp_B2 = pickle.load(open(default_da_settings['path']+'exp_B2.pickle', "rb"))
except: except:
exp_B2 = experiment(da_settings_B2) exp_B2 = experiment(da_settings_B2)
setattr(exp_B2,'label','B2') setattr(exp_B2,'label','B2')
pickle.dump(exp_B2, open('exp_B2.pickle', 'wb')) pickle.dump(exp_B2, open(default_da_settings['path']+'exp_B2.pickle', 'wb'))
if noPE_runs: if noPE_runs:
# Corresponding experiment without parameter estimation # Corresponding experiment without parameter estimation
...@@ -211,10 +217,10 @@ if __name__ == '__main__': ...@@ -211,10 +217,10 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B2_noPE = pickle.load(open("exp_B2_noPE.pickle", "rb")) exp_B2_noPE = pickle.load(open(default_da_settings['path']+'exp_B2_noPE.pickle', "rb"))
except: except:
exp_B2_noPE = experiment(da_settings_B2_noPE) exp_B2_noPE = experiment(da_settings_B2_noPE)
pickle.dump(exp_B2_noPE, open('exp_B2_noPE.pickle', 'wb')) pickle.dump(exp_B2_noPE, open(default_da_settings['path']+'exp_B2_noPE.pickle', 'wb'))
######################################################################## ########################################################################
# Experiment B3 # Experiment B3
...@@ -234,11 +240,11 @@ if __name__ == '__main__': ...@@ -234,11 +240,11 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B3 = pickle.load(open("exp_B3.pickle", "rb")) exp_B3 = pickle.load(open(default_da_settings['path']+'exp_B3.pickle', "rb"))
except: except:
exp_B3 = experiment(da_settings_B3) exp_B3 = experiment(da_settings_B3)
setattr(exp_B3,'label','B3') setattr(exp_B3,'label','B3')
pickle.dump(exp_B3, open('exp_B3.pickle', 'wb')) pickle.dump(exp_B3, open(default_da_settings['path']+'exp_B3.pickle', 'wb'))
if noPE_runs: if noPE_runs:
# Corresponding experiment without parameter estimation # Corresponding experiment without parameter estimation
...@@ -251,10 +257,10 @@ if __name__ == '__main__': ...@@ -251,10 +257,10 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B3_noPE = pickle.load(open("exp_B3_noPE.pickle", "rb")) exp_B3_noPE = pickle.load(open(default_da_settings['path']+'exp_B3_noPE.pickle', "rb"))
except: except:
exp_B3_noPE = experiment(da_settings_B3_noPE) exp_B3_noPE = experiment(da_settings_B3_noPE)
pickle.dump(exp_B3_noPE, open('exp_B3_noPE.pickle', 'wb')) pickle.dump(exp_B3_noPE, open(default_da_settings['path']+'exp_B3_noPE.pickle', 'wb'))
######################################################################## ########################################################################
# Experiment B4 # Experiment B4
...@@ -272,11 +278,11 @@ if __name__ == '__main__': ...@@ -272,11 +278,11 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B4 = pickle.load(open("exp_B4.pickle", "rb")) exp_B4 = pickle.load(open(default_da_settings['path']+'exp_B4.pickle', "rb"))
except: except:
exp_B4 = experiment(da_settings_B4) exp_B4 = experiment(da_settings_B4)
setattr(exp_B4,'label','B4') setattr(exp_B4,'label','B4')
pickle.dump(exp_B4, open('exp_B4.pickle', 'wb')) pickle.dump(exp_B4, open(default_da_settings['path']+'exp_B4.pickle', 'wb'))
if noPE_runs: if noPE_runs:
# Corresponding experiment without parameter estimation # Corresponding experiment without parameter estimation
...@@ -287,10 +293,10 @@ if __name__ == '__main__': ...@@ -287,10 +293,10 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_B4_noPE = pickle.load(open("exp_B4_noPE.pickle", "rb")) exp_B4_noPE = pickle.load(open(default_da_settings['path']+'exp_B4_noPE.pickle', "rb"))
except: except:
exp_B4_noPE = experiment(da_settings_B4_noPE) exp_B4_noPE = experiment(da_settings_B4_noPE)
pickle.dump(exp_B4_noPE, open('exp_B4_noPE.pickle', 'wb')) pickle.dump(exp_B4_noPE, open(default_da_settings['path']+'exp_B4_noPE.pickle', 'wb'))
######################################################################## ########################################################################
# Experiment C1 # Experiment C1
...@@ -310,11 +316,11 @@ if __name__ == '__main__': ...@@ -310,11 +316,11 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_C1 = pickle.load(open("exp_C1.pickle", "rb")) exp_C1 = pickle.load(open(default_da_settings['path']+'exp_C1.pickle', "rb"))
except: except:
exp_C1 = experiment(da_settings_C1) exp_C1 = experiment(da_settings_C1)
setattr(exp_C1,'label','C1') setattr(exp_C1,'label','C1')
pickle.dump(exp_C1, open('exp_C1.pickle', 'wb')) pickle.dump(exp_C1, open(default_da_settings['path']+'exp_C1.pickle', 'wb'))
if noPE_runs: if noPE_runs:
# Corresponding experiment without parameter estimation # Corresponding experiment without parameter estimation
...@@ -325,10 +331,10 @@ if __name__ == '__main__': ...@@ -325,10 +331,10 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_C1_noPE = pickle.load(open("exp_C1_noPE.pickle", "rb")) exp_C1_noPE = pickle.load(open(default_da_settings['path']+'exp_C1_noPE.pickle', "rb"))
except: except:
exp_C1_noPE = experiment(da_settings_C1_noPE) exp_C1_noPE = experiment(da_settings_C1_noPE)
pickle.dump(exp_C1_noPE, open('exp_C1_noPE.pickle', 'wb')) pickle.dump(exp_C1_noPE, open(default_da_settings['path']+'exp_C1_noPE.pickle', 'wb'))
######################################################################## ########################################################################
# Experiment C2 # Experiment C2
...@@ -348,11 +354,11 @@ if __name__ == '__main__': ...@@ -348,11 +354,11 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_C2 = pickle.load(open("exp_C2.pickle", "rb")) exp_C2 = pickle.load(open(default_da_settings['path']+'exp_C2.pickle', "rb"))
except: except:
exp_C2 = experiment(da_settings_C2) exp_C2 = experiment(da_settings_C2)
setattr(exp_C2,'label','C2') setattr(exp_C2,'label','C2')
pickle.dump(exp_C2, open('exp_C2.pickle', 'wb')) pickle.dump(exp_C2, open(default_da_settings['path']+'exp_C2.pickle', 'wb'))
if noPE_runs: if noPE_runs:
# Corresponding experiment without parameter estimation # Corresponding experiment without parameter estimation
...@@ -363,10 +369,10 @@ if __name__ == '__main__': ...@@ -363,10 +369,10 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_C2_noPE = pickle.load(open("exp_C2_noPE.pickle", "rb")) exp_C2_noPE = pickle.load(open(default_da_settings['path']+'exp_C2_noPE.pickle', "rb"))
except: except:
exp_C2_noPE = experiment(da_settings_C2_noPE) exp_C2_noPE = experiment(da_settings_C2_noPE)
pickle.dump(exp_C2_noPE, open('exp_C2_noPE.pickle', 'wb')) pickle.dump(exp_C2_noPE, open(default_da_settings['path']+'exp_C2_noPE.pickle', 'wb'))
######################################################################## ########################################################################
# Experiment D # Experiment D
...@@ -389,23 +395,24 @@ if __name__ == '__main__': ...@@ -389,23 +395,24 @@ if __name__ == '__main__':
# Run and save to disk # Run and save to disk
try: try:
exp_D = pickle.load(open("exp_D.pickle", "rb")) exp_D = pickle.load(open(default_da_settings['path']+'exp_D.pickle', "rb"))
except: except:
exp_D = experiment(da_settings_D) exp_D = experiment(da_settings_D)
setattr(exp_D,'label','D') setattr(exp_D,'label','D')
pickle.dump(exp_D, open('exp_D.pickle', 'wb')) pickle.dump(exp_D, open(default_da_settings['path']+'exp_D.pickle', 'wb'))
# Experiment matching D, but without parameter estimation # Experiment matching D, but without parameter estimation
if noPE_runs:
cbl_settings_D_noPE = dict(cbl_settings_D) cbl_settings_D_noPE = dict(cbl_settings_D)
da_settings_D_noPE = dict(da_settings_D) da_settings_D_noPE = dict(da_settings_D)
cbl_settings_D_noPE['do_parameter_estimation'] = False cbl_settings_D_noPE['do_parameter_estimation'] = False
da_settings_D_noPE['cbl_settings'] = cbl_settings_D_noPE da_settings_D_noPE['cbl_settings'] = cbl_settings_D_noPE
try: try:
exp_D_noPE = pickle.load(open("exp_D_noPE.pickle", "rb")) exp_D_noPE = pickle.load(open(default_da_settings['path']+'exp_D_noPE.pickle', "rb"))
except: except:
exp_D_noPE = experiment(da_settings_D_noPE) exp_D_noPE = experiment(da_settings_D_noPE)
pickle.dump(exp_A_noPE, open('exp_D_noPE.pickle', 'wb')) pickle.dump(exp_A_noPE, open(default_da_settings['path']+'exp_D_noPE.pickle', 'wb'))
######################################################################## ########################################################################
...@@ -417,7 +424,8 @@ if __name__ == '__main__': ...@@ -417,7 +424,8 @@ if __name__ == '__main__':
fig05 = False fig05 = False
fig06 = False fig06 = False
fig07 = False fig07 = False
fig08 = True fig08 = False
fig09 = True
# Other possible, optional, plots # Other possible, optional, plots
opt01 = False # assimilation of a single observation opt01 = False # assimilation of a single observation
...@@ -427,6 +435,8 @@ if __name__ == '__main__': ...@@ -427,6 +435,8 @@ if __name__ == '__main__':
# Create a copy of the default settings # Create a copy of the default settings
cbl_settings = dict(default_cbl_settings) cbl_settings = dict(default_cbl_settings)
maxtime = 21600
cbl_settings['maxtime'] = maxtime
# Disable parameter estimation (not used here) # Disable parameter estimation (not used here)
cbl_settings['do_parameter_estimation'] = False cbl_settings['do_parameter_estimation'] = False
...@@ -454,6 +464,7 @@ if __name__ == '__main__': ...@@ -454,6 +464,7 @@ if __name__ == '__main__':
# Panel c) spread induced by p # Panel c) spread induced by p
# Do a free ensemble run (ensemble size set expliclity) # Do a free ensemble run (ensemble size set expliclity)
cbl_settings_free = dict(default_cbl_settings) cbl_settings_free = dict(default_cbl_settings)
cbl_settings_free['maxtime'] = maxtime
cbl_settings_free['perturb_ensemble_state'] = False cbl_settings_free['perturb_ensemble_state'] = False
cbl_free = CBL(cbl_settings_free) cbl_free = CBL(cbl_settings_free)
cbl_free.initialize(nens) cbl_free.initialize(nens)
...@@ -468,7 +479,7 @@ if __name__ == '__main__': ...@@ -468,7 +479,7 @@ if __name__ == '__main__':
ax1.set_ylim([0,zmax]) ax1.set_ylim([0,zmax])
ax1.set_ylabel(r'Height (m)') ax1.set_ylabel(r'Height (m)')
ax1.set_xlabel(r'Time (h)') ax1.set_xlabel(r'Time (h)')
ax1.set_xticks(np.arange(4)) ax1.set_xticks(np.arange((maxtime+1)/3600))
ax1.set_title(r'c) $\overline{\theta}$ (K)') ax1.set_title(r'c) $\overline{\theta}$ (K)')
p.colorbar(c1,orientation='horizontal') p.colorbar(c1,orientation='horizontal')
ax1.contour(cbl_det.history['time']/3600,cbl_det.zt,cbl_det.history['theta'], ax1.contour(cbl_det.history['time']/3600,cbl_det.zt,cbl_det.history['theta'],
...@@ -489,7 +500,7 @@ if __name__ == '__main__': ...@@ -489,7 +500,7 @@ if __name__ == '__main__':
ax3.set_ylabel(r'Height (m)') ax3.set_ylabel(r'Height (m)')
ax3.set_title(r'd) $\sigma_\theta$ (K)') ax3.set_title(r'd) $\sigma_\theta$ (K)')
ax3.set_xlabel('Time (h)') ax3.set_xlabel('Time (h)')
ax3.set_xticks(np.arange(4)) ax3.set_xticks(np.arange((maxtime+1)/3600))
p.colorbar(c3,orientation='horizontal') p.colorbar(c3,orientation='horizontal')
zoverh = np.linspace(0,1,101) zoverh = np.linspace(0,1,101)
...@@ -509,25 +520,34 @@ if __name__ == '__main__': ...@@ -509,25 +520,34 @@ if __name__ == '__main__':
if fig02: if fig02:
exp_A = pickle.load(open("exp_A.pickle", "rb")) exp_A = pickle.load(open(default_da_settings['path']+"exp_A.pickle", "rb"))
fig, [[ax0, ax1], [ax2, ax3]] = p.subplots(2,2,constrained_layout=True) fig, [[ax0, ax1], [ax2, ax3]] = p.subplots(2,2,constrained_layout=True)
fig.set_size_inches(6,6) fig.set_size_inches(6,6)
# #
[ax0,ax1,ax2],c0,c1,c2 = plot_CBL_identifiability(exp_A,da_settings_A['obs_error_sdev_assimilate'][0],ax=[ax0,ax1,ax2]) [ax0,ax1,ax2],c0,c1,c2 = plot_CBL_identifiability(exp_A,da_settings_A['obs_error_sdev_assimilate'][0],ax=[ax0,ax1,ax2])
ax0.set_title(r'a) Exp. A, $\rho(p\prime\prime,y_b}$)') ax0.set_title(r'a) Exp. A$_1$, $\rho(p\prime\prime,y_b}$)')
ax0.set_xlabel('Time (h)') ax0.set_xlabel('Time (h)')
ax0.set_ylabel('Height (m)') ax0.set_ylabel('Height (m)')
ax1.set_title(r'b) Exp. A, $\delta\overline{y}\cdot(\sigma_{p\prime\prime}/\sigma_{y^b})$') ax1.set_title(r'b) Exp. A$_1$, $\delta\overline{y}\cdot(\sigma_{p\prime\prime}/\sigma_{y^b})$')
ax1.set_xlabel('Time (h)') ax1.set_xlabel('Time (h)')
ax1.set_ylabel('Height (m)') ax1.set_ylabel('Height (m)')
ax2.set_title(r'c) Exp. A, $\delta\overline{p}\prime\prime$') ax2.set_title(r'c) Exp. A$_1$, $\delta\overline{p}\prime\prime$')
ax2.set_xlabel('Time (h)') ax2.set_xlabel('Time (h)')
ax2.set_ylabel('Height (m)') ax2.set_ylabel('Height (m)')
ax3 = plot_CBL_PE(exp_A,None,ax=ax3) ax3 = plot_CBL_PE(exp_A,None,ax=ax3)
ax3.set_title(r'd) Exp. A, evolution of $p$') ax3.set_title(r'd) Exp. A$_1$, evolution of $p$')
ax3.set_xlabel('Time (h)') ax3.set_xlabel('Time (h)')
ax3.set_yticks([0,1,2,3,4,5]) ax3.set_yticks([0,1,2,3,4,5])
maxtime = exp_A.trun
ax0.set_xlim([0,maxtime/3600])
ax1.set_xlim([0,maxtime/3600])
ax2.set_xlim([0,maxtime/3600])
ax3.set_xlim([0,maxtime/3600])
ax0.set_xticks(np.arange((maxtime+1)/3600))
ax1.set_xticks(np.arange((maxtime+1)/3600))
ax2.set_xticks(np.arange((maxtime+1)/3600))
ax3.set_xticks(np.arange((maxtime+1)/3600))
p.colorbar(c0,orientation='horizontal') p.colorbar(c0,orientation='horizontal')
p.colorbar(c1,orientation='horizontal') p.colorbar(c1,orientation='horizontal')
p.colorbar(c2,orientation='horizontal') p.colorbar(c2,orientation='horizontal')
...@@ -537,8 +557,8 @@ if __name__ == '__main__': ...@@ -537,8 +557,8 @@ if __name__ == '__main__':
if fig03: if fig03:
exp_A = pickle.load(open("exp_A.pickle", "rb")) exp_A = pickle.load(open(default_da_settings['path']+"exp_A.pickle", "rb"))
exp_A_noPE = pickle.load(open("exp_A_noPE.pickle", "rb")) exp_A_noPE = pickle.load(open(default_da_settings['path']+"exp_A_noPE.pickle", "rb"))
experiments_pe = [exp_A] experiments_pe = [exp_A]
experiments_nope = [exp_A_noPE] experiments_nope = [exp_A_noPE]
...@@ -548,10 +568,10 @@ if __name__ == '__main__': ...@@ -548,10 +568,10 @@ if __name__ == '__main__':
if fig04: if fig04:
exp_B1 = pickle.load(open("exp_B1.pickle", "rb")) exp_B1 = pickle.load(open(default_da_settings['path']+"exp_B1.pickle", "rb"))
exp_B2 = pickle.load(open("exp_B2.pickle", "rb")) exp_B2 = pickle.load(open(default_da_settings['path']+"exp_B2.pickle", "rb"))
exp_B3 = pickle.load(open("exp_B3.pickle", "rb")) exp_B3 = pickle.load(open(default_da_settings['path']+"exp_B3.pickle", "rb"))
exp_B4 = pickle.load(open("exp_B4.pickle", "rb")) exp_B4 = pickle.load(open(default_da_settings['path']+"exp_B4.pickle", "rb"))
fig, [[ax1, ax2], [ax3, ax4]] = p.subplots(2,2,constrained_layout=True) fig, [[ax1, ax2], [ax3, ax4]] = p.subplots(2,2,constrained_layout=True)
fig.set_size_inches(6,4) fig.set_size_inches(6,4)
...@@ -586,8 +606,8 @@ if __name__ == '__main__': ...@@ -586,8 +606,8 @@ if __name__ == '__main__':
if fig05: if fig05:
exp_C1 = pickle.load(open("exp_C1.pickle", "rb")) exp_C1 = pickle.load(open(default_da_settings['path']+"exp_C1.pickle", "rb"))
exp_C2 = pickle.load(open("exp_C2.pickle", "rb")) exp_C2 = pickle.load(open(default_da_settings['path']+"exp_C2.pickle", "rb"))
fig, [ax1, ax2] = p.subplots(1,2,constrained_layout=True) fig, [ax1, ax2] = p.subplots(1,2,constrained_layout=True)
fig.set_size_inches(6,2) fig.set_size_inches(6,2)
...@@ -610,8 +630,8 @@ if __name__ == '__main__': ...@@ -610,8 +630,8 @@ if __name__ == '__main__':
if fig06: if fig06:
exp_C1 = pickle.load(open("exp_C1.pickle", "rb")) exp_C1 = pickle.load(open(default_da_settings['path']+"exp_C1.pickle", "rb"))
exp_C2 = pickle.load(open("exp_C2.pickle", "rb")) exp_C2 = pickle.load(open(default_da_settings['path']+"exp_C2.pickle", "rb"))
npar2 = exp_C1.nr.parameter_number npar2 = exp_C1.nr.parameter_number
npar3 = exp_C2.nr.parameter_number npar3 = exp_C2.nr.parameter_number
...@@ -631,6 +651,11 @@ if __name__ == '__main__': ...@@ -631,6 +651,11 @@ if __name__ == '__main__':
ax2.set_xlabel('Time (h)') ax2.set_xlabel('Time (h)')
ax1.set_ylabel('Height (m)') ax1.set_ylabel('Height (m)')
ax2.sharey(ax1) ax2.sharey(ax1)
maxtime = exp_C1.trun
ax1.set_xlim([0,maxtime/3600])
ax2.set_xlim([0,maxtime/3600])
ax1.set_xticks(np.arange((maxtime+1)/3600))
ax2.set_xticks(np.arange((maxtime+1)/3600))
p.setp(ax2.get_yticklabels(), visible=False) p.setp(ax2.get_yticklabels(), visible=False)
# #
p.colorbar(c1,orientation='horizontal') p.colorbar(c1,orientation='horizontal')
...@@ -641,7 +666,7 @@ if __name__ == '__main__': ...@@ -641,7 +666,7 @@ if __name__ == '__main__':
if fig07: if fig07:
exp_D = pickle.load(open("exp_D.pickle", "rb")) exp_D = pickle.load(open(default_da_settings['path']+"exp_D.pickle", "rb"))
fig, [ax0, ax1] = p.subplots(1,2,constrained_layout=True) fig, [ax0, ax1] = p.subplots(1,2,constrained_layout=True)
fig.set_size_inches(6,3) fig.set_size_inches(6,3)
...@@ -654,6 +679,11 @@ if __name__ == '__main__': ...@@ -654,6 +679,11 @@ if __name__ == '__main__':
ax1.set_title(r'b) Exp. D, evolution of $p$') ax1.set_title(r'b) Exp. D, evolution of $p$')
ax1.set_xlabel('Time (h)') ax1.set_xlabel('Time (h)')
ax1.set_yticks([0,1,2,3,4,5]) ax1.set_yticks([0,1,2,3,4,5])
maxtime = exp_D.trun
ax0.set_xlim([0,maxtime/3600])
ax1.set_xlim([0,maxtime/3600])
ax0.set_xticks(np.arange((maxtime+1)/3600))
ax1.set_xticks(np.arange((maxtime+1)/3600))
p.colorbar(c0,orientation='horizontal') p.colorbar(c0,orientation='horizontal')
# #
fig.savefig('fig07.png',format='png',dpi=300) fig.savefig('fig07.png',format='png',dpi=300)
...@@ -661,19 +691,24 @@ if __name__ == '__main__': ...@@ -661,19 +691,24 @@ if __name__ == '__main__':
if fig08: if fig08:
exp_A = pickle.load(open("exp_A.pickle", "rb")) exp_A = pickle.load(open(default_da_settings['path']+"exp_A.pickle", "rb"))
exp_D = pickle.load(open("exp_D.pickle", "rb")) exp_D = pickle.load(open(default_da_settings['path']+"exp_D.pickle", "rb"))
fig, [[ax0, ax1],[ax2,ax3]] = p.subplots(2,2,constrained_layout=True) fig, [[ax0, ax1],[ax2,ax3]] = p.subplots(2,2,constrained_layout=True)
fig.set_size_inches(6,6) fig.set_size_inches(6,6)
# #
[ax1,ax0],c0,c1 = plot_CBL_identifiability(exp_A,da_settings_A['obs_error_sdev_assimilate'][0],ax=[ax1,ax0]) [ax1,ax0],c0,c1 = plot_CBL_identifiability(exp_A,da_settings_A['obs_error_sdev_assimilate'][0],ax=[ax1,ax0])
ax0.set_title(r'a) Exp. A, $\delta\overline{y}$ (K)') ax0.set_title(r'a) Exp. A$_1$, $\delta\overline{y}$ (K)')
ax0.set_xlabel('Time (h)') ax0.set_xlabel('Time (h)')
ax0.set_ylabel('Height (m)') ax0.set_ylabel('Height (m)')
ax1.set_title(r'b) Exp. A, $\sigma_{p\prime\prime}/\sigma_{y^b}$ (K$^{-1}$)') ax1.set_title(r'b) Exp. A$_1$, $\sigma_{p\prime\prime}/\sigma_{y^b}$ (K$^{-1}$)')
ax1.set_xlabel('Time (h)') ax1.set_xlabel('Time (h)')
ax1.set_ylabel('Height (m)') ax1.set_ylabel('Height (m)')
maxtime = exp_A.trun
ax0.set_xlim([0,maxtime/3600])
ax1.set_xlim([0,maxtime/3600])
ax0.set_xticks(np.arange((maxtime+1)/3600))
ax1.set_xticks(np.arange((maxtime+1)/3600))
[ax3,ax2],c2,c3 = plot_CBL_identifiability(exp_D,da_settings_D['obs_error_sdev_assimilate'][0],ax=[ax3,ax2]) [ax3,ax2],c2,c3 = plot_CBL_identifiability(exp_D,da_settings_D['obs_error_sdev_assimilate'][0],ax=[ax3,ax2])
ax2.set_title(r'c) Exp. D, $\delta\overline{y}$ (K)') ax2.set_title(r'c) Exp. D, $\delta\overline{y}$ (K)')
ax2.set_xlabel('Time (h)') ax2.set_xlabel('Time (h)')
...@@ -681,6 +716,11 @@ if __name__ == '__main__': ...@@ -681,6 +716,11 @@ if __name__ == '__main__':
ax3.set_title(r'd) Exp. D, $\sigma_{p\prime\prime}/\sigma_{y^b}$ (K$^{-1}$)') ax3.set_title(r'd) Exp. D, $\sigma_{p\prime\prime}/\sigma_{y^b}$ (K$^{-1}$)')
ax3.set_xlabel('Time (h)') ax3.set_xlabel('Time (h)')
ax3.set_ylabel('Height (m)') ax3.set_ylabel('Height (m)')
maxtime = exp_D.trun
ax2.set_xlim([0,maxtime/3600])
ax3.set_xlim([0,maxtime/3600])
ax2.set_xticks(np.arange((maxtime+1)/3600))
ax3.set_xticks(np.arange((maxtime+1)/3600))
p.colorbar(c0,orientation='horizontal') p.colorbar(c0,orientation='horizontal')
p.colorbar(c1,orientation='horizontal') p.colorbar(c1,orientation='horizontal')
p.colorbar(c2,orientation='horizontal') p.colorbar(c2,orientation='horizontal')
...@@ -689,6 +729,13 @@ if __name__ == '__main__': ...@@ -689,6 +729,13 @@ if __name__ == '__main__':
fig.savefig('fig08.png',format='png',dpi=300) fig.savefig('fig08.png',format='png',dpi=300)
p.close(fig) p.close(fig)
if fig09:
path_EAKF = "./runs/seed=181612_enssize=200_EAKF_6hrs"
path_LETKF = "./runs/seed=181612_enssize=200_LETKF_6hrs"
if opt01: if opt01:
da_settings = {'cbl_settings' : dict(default_cbl_settings), da_settings = {'cbl_settings' : dict(default_cbl_settings),
...@@ -732,3 +779,22 @@ if __name__ == '__main__': ...@@ -732,3 +779,22 @@ if __name__ == '__main__':
fig.savefig('profiles.png',format='png',dpi=300) fig.savefig('profiles.png',format='png',dpi=300)
p.close(fig) p.close(fig)
check_reproducibility = False
if check_reproducibility:
path = default_da_settings['path']
for i in ["exp_A.pickle",
"exp_A_noPE.pickle",
"exp_B1.pickle",
"exp_B2.pickle",
"exp_B3.pickle",
"exp_B4.pickle",
"exp_C1.pickle",
"exp_C2.pickle",
"exp_D.pickle"]:
experiment = pickle.load(open(path+i, "rb"))
print(i)
print("OBS :",experiment.da.observations[:,0])
print("PARAMETERS:",experiment.da.initial_perturbed_parameters[0,:5])
print("STATE :",experiment.da.initial_state[0,0,:5])
...@@ -421,7 +421,7 @@ def plot_diagnostics(experiments_pe,experiments_nope,labels,filename): ...@@ -421,7 +421,7 @@ def plot_diagnostics(experiments_pe,experiments_nope,labels,filename):
fig.set_size_inches(6,4) fig.set_size_inches(6,4)
z = experiments_pe[0].obs_coordinates z = experiments_pe[0].obs_coordinates
z_pbl = z*1. z_pbl = z*1.
z_pbl[z>1000] = np.nan z_pbl[z>1500] = np.nan
for i in range(len(experiments_pe)): for i in range(len(experiments_pe)):
i1 = experiments_pe[i].dg i1 = experiments_pe[i].dg
i2 = experiments_nope[i].dg i2 = experiments_nope[i].dg
......
...@@ -97,7 +97,8 @@ class CBL: ...@@ -97,7 +97,8 @@ class CBL:
# Overwrite the pre-existing unperturbed values # Overwrite the pre-existing unperturbed values
# This is needed for safety, because parameter transformations may be nonlinear # This is needed for safety, because parameter transformations may be nonlinear
if self.nens>1: if self.nens>1:
if self.do_parameter_estimation and hasattr(self,"initial_perturbed_parameters"): #if self.do_parameter_estimation and hasattr(self,"initial_perturbed_parameters"):
if hasattr(self,"initial_perturbed_parameters"):
x0[-self.parameter_number:,:] = self.initial_perturbed_parameters x0[-self.parameter_number:,:] = self.initial_perturbed_parameters
else: else:
if self.perturb_ensemble_parameters or self.do_parameter_estimation: if self.perturb_ensemble_parameters or self.do_parameter_estimation:
...@@ -158,7 +159,8 @@ class CBL: ...@@ -158,7 +159,8 @@ class CBL:
pp = np.zeros((self.parameter_number,self.nens)) pp = np.zeros((self.parameter_number,self.nens))
for k in range(-self.parameter_number,0): for k in range(-self.parameter_number,0):
dum = self.RNG.uniform(self.parameter_ensemble_min[k], self.parameter_ensemble_max[k], size=self.nens) RNG = np.random.default_rng(seed=self.rnseed)
dum = RNG.uniform(self.parameter_ensemble_min[k], self.parameter_ensemble_max[k], size=self.nens)
pp[k,:] = self.parameter_transform[k](dum , kind='dir') pp[k,:] = self.parameter_transform[k](dum , kind='dir')
return pp return pp
...@@ -172,10 +174,12 @@ class CBL: ...@@ -172,10 +174,12 @@ class CBL:
randomsize = 1 randomsize = 1
if self.perturbations_type == "random" or self.perturbations_type == "uniform": if self.perturbations_type == "random" or self.perturbations_type == "uniform":
ppt = self.RNG.standard_normal((randomsize,self.nens)) RNG = np.random.default_rng(seed=self.rnseed)
ppt = RNG.standard_normal((randomsize,self.nens))
if self.is_bwind: if self.is_bwind:
ppu = self.RNG.standard_normal((self.nens,randomsize)) RNG = np.random.default_rng(seed=self.rnseed)
ppv = self.RNG.standard_normal((self.nens,randomsize)) ppu = RNG.standard_normal((self.nens,randomsize))
ppv = RNG.standard_normal((self.nens,randomsize))
# Smooth perturbations are slightly more complicated # Smooth perturbations are slightly more complicated
if self.perturbations_type == "smooth": if self.perturbations_type == "smooth":
...@@ -188,15 +192,17 @@ class CBL: ...@@ -188,15 +192,17 @@ class CBL:
# Draw random perturbations, then interpolate # Draw random perturbations, then interpolate
randomsize = self.perturbations_smooth_number randomsize = self.perturbations_smooth_number
ppt = np.zeros((self.nz,self.nens))+np.nan ppt = np.zeros((self.nz,self.nens))+np.nan
pert_t = self.RNG.standard_normal((randomsize,self.nens)) RNG = np.random.default_rng(seed=self.rnseed)
pert_t = RNG.standard_normal((randomsize,self.nens))
for n in range(self.nens): for n in range(self.nens):
f = CubicSpline(ipert,pert_t[:,n]) f = CubicSpline(ipert,pert_t[:,n])
ppt[:,n] = f(np.arange(self.nz)) ppt[:,n] = f(np.arange(self.nz))
if self.is_bwind: if self.is_bwind:
ppu = np.zeros((self.nz,self.nens))+np.nan ppu = np.zeros((self.nz,self.nens))+np.nan
ppv = np.zeros((self.nz,self.nens))+np.nan ppv = np.zeros((self.nz,self.nens))+np.nan
pert_u = self.RNG.standard_normal((randomsize,self.nens)) RNG = np.random.default_rng(seed=self.rnseed)
pert_v = self.RNG.standard_normal((randomsize,self.nens)) pert_u = RNG.standard_normal((randomsize,self.nens))
pert_v = RNG.standard_normal((randomsize,self.nens))
for n in range(self.nens): for n in range(self.nens):
f = CubicSpline(ipert,pert_u[:,n]) f = CubicSpline(ipert,pert_u[:,n])
ppu[:,n] = f(np.arange(self.nz)) ppu[:,n] = f(np.arange(self.nz))
...@@ -311,7 +317,11 @@ class CBL: ...@@ -311,7 +317,11 @@ class CBL:
H0 = Hmax H0 = Hmax
# Add random perturbations to the initial value # Add random perturbations to the initial value
H0 += self.RNG.normal(scale=H0_perturbation_ampl_init) # Change the seed every time you go through this,
# otherwise the perturbations are always the same
seed = self.rnseed+j*200000
RNG = np.random.default_rng(seed=seed)
H0 += RNG.normal(scale=H0_perturbation_ampl_init)
# Set the surface momentum flux (ustar) # Set the surface momentum flux (ustar)
ustar = 0 ustar = 0
...@@ -360,8 +370,13 @@ class CBL: ...@@ -360,8 +370,13 @@ class CBL:
rdz = 1./self.dz rdz = 1./self.dz
# Add time-dependent surface perturbations # Add time-dependent surface perturbations
# Change the seed every time you go through this,
# otherwise the perturbations are always the same
seed = self.rnseed+j*200000
RNG = np.random.default_rng(seed=seed)
# Then compute sensible heat flux and integrate T equation # Then compute sensible heat flux and integrate T equation
H[0,j] = H0 + self.RNG.normal(scale=H0_perturbation_ampl_time) H[0,j] = H0 + RNG.normal(scale=H0_perturbation_ampl_time)
H[1:-1,j] = -K[1:-1,j]*( (thetap[1:]-thetap[:-1])*rdz - gammac) H[1:-1,j] = -K[1:-1,j]*( (thetap[1:]-thetap[:-1])*rdz - gammac)
H[nz,j] = 2*H[nz-1,j]-H[nz-2,j] H[nz,j] = 2*H[nz-1,j]-H[nz-2,j]
theta[:,j] = thetap[:]-dt*rdz*(H[1:,j]-H[:-1,j]) theta[:,j] = thetap[:]-dt*rdz*(H[1:,j]-H[:-1,j])
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment