def evolvemembers(xold, tstep_truth, o2t, parout=None): """Evolving the members. Inputs: - xold, a [N,M] array of initial conditions for the M members and N variables - tstep_truth, the time step used in the nature run - o2t, frequency of observations in time steps Outputs: - xnew, a [o2t+1,N,M] array with the evolved members""" t_anal = o2t * tstep_truth N, M = np.shape(xold) xnew = np.empty((o2t + 1, N, M)) xnew.fill(np.nan) for j in range(M): if parout is None: taux, xaux = lorenz63(xold[:, j], t_anal) # [o2t+1,N] else: taux, xaux = lorenz63(xold[:, j], t_anal, parout[:, j]) # [o2t+1,N] xnew[:, :, j] = xaux del j return xnew
def costfun(xa): xavec = np.mat(xa).T Jback = (xavec - x0bvec).T * invB * (xavec - x0bvec) if model == 'lor63': taux, xaaux = lorenz63(xa, o2t * anawin * tstep_truth) #elif model=='lor96': # taux,xaaux = lorenz96(o2t*anawin*tstep_truth,xa,N) indobs = range(o2t, anawin * o2t + 1, o2t) xobs = xaaux[indobs, :] xobs = np.mat(xobs).T Jobs = np.empty(len(indobs)) Jobs.fill(np.nan) for iJobs in range(len(indobs)): Jobs[iJobs] = (y[:,iJobs]-H*(xobs[:,iJobs])).T*invR \ *(y[:,iJobs]-H*(xobs[:,iJobs])) J = Jback + np.sum(Jobs) return J
def getBsimple(model,N): """A very simple method to obtain the background error covariance. Obtained from a long run of a model. Inputs: - model, the name of the model 'lor63' or 'lor96' - N, the number of variables Outputs: - B, the covariance matrix - Bcorr, the correlation matrix""" if model=='lor63': total_steps = 10000 tstep = 0.01 tmax = tstep*total_steps x0 = np.array([-10,-10,25]) t,xt = lorenz63(x0,tmax) samfreq = 16 err2 = 2 # elif model=='lor96': # total_steps = 5000 # tstep = 0.025 # tmax = tstep*total_steps # x0 = None # t,xt = lorenz96(tmax,x0,N) # samfreq = 2 # err2 = 2 # Precreate the matrix ind_sample = range(0,total_steps,samfreq) x_sample = xt[ind_sample,:] Bcorr = np.mat(np.corrcoef(x_sample,rowvar=0)) B = np.mat(np.cov(x_sample,rowvar=0)) alpha = err2/np.amax(np.diag(B)) B = alpha*B return B,Bcorr
def var3d(x0, t, tobs, y, H, B, R, model, N): """Data assimilation routine for both Lorenz 1963 & 1996 using 3DVar. Inputs: - x0, the real initial conditions - t, time array of the model (should be evenly spaced) - tobs, time array of the observations (should be evenly spaced with a timestep that is a multiple of the model timestep) - y, the observations - H, observation matrix - B, the background error covariance matrix - R, the observational error covariance matrix - model, a string indicating the name of the model: 'lor63' or 'lor96' - N, the number of variables Outputs: - x_b, the background - x_a, the analysis""" # General settings # For the true time tstep_truth = t[1] - t[0] # For the analysis tstep_obs = tobs[1] - tobs[0] # The ratio o2t = int(tstep_obs / tstep_truth + 0.5) # Precreate the arrays for background and analysis x_b = np.empty((len(t), N)) x_b.fill(np.nan) x_a = np.empty((len(t), N)) x_a.fill(np.nan) # For the original background ensemble let's start close from the truth orig_bgd = 'fixed' #orig_bgd = 'random' if orig_bgd == 'fixed': indaux = np.arange(N) x0_aux = x0 + (-1)**indaux elif orig_bgd == 'random': x0_aux = x0 + np.random.randn(N) # For the first instant b and a are equal x_b[0, :] = x0_aux x_a[0, :] = x0_aux # The following cycle contains evolution and assimilation for j in range(len(tobs) - 1): yaux = y[j + 1, :] # First compute background; our initial condition is the # forecast from the analysis at the previous observational # time xb0 = x_a[j * o2t, :] if model == 'lor63': taux, xbaux = lorenz63(xb0, o2t * tstep_truth) #elif model=='lor96': # taux,xbaux = lorenz96(o2t*tstep_truth,xb0,N) x_b[j * o2t + 1:(j + 1) * o2t + 1, :] = xbaux[1:, :] x_a[j * o2t + 1:(j + 1) * o2t + 1, :] = xbaux[1:, :] xa_aux = one3dvar(xbaux[o2t, :], yaux, H, B, R) x_a[(j + 1) * o2t, :] = xa_aux print 't =', t[o2t * (j + 1)] return x_b, x_a
def var4d(x0, t, tobs, anawin, y, H, B, R, model, N): """Data assimilation routine for both Lorenz 1963 & 1996 using 4DVar. Inputs: - x0, the real initial conditions - t, time array of the model (should be evenly spaced) - tobs, time array of the observations (should be evenly spaced with a timestep that is a multiple of the model timestep) - anawin, length of the 4D assim window, expressed as number of future obs included - y, the observations - H, observation matrix - B, the background error covariance matrix - R, the observational error covariance matrix - model, a string indicating the name of the model: 'lor63' or 'lor96' - N, the number of variables Outputs: - x_b, the background - x_a, the analysis""" # General settings # For the true time tstep_truth = t[1] - t[0] # For the analysis tstep_obs = tobs[1] - tobs[0] # The ratio o2t = int(tstep_obs / tstep_truth + 0.5) totana = (len(tobs) - 1) / anawin # Precreate the arrays for background and analysis x_b = np.empty((len(t), N)) x_b.fill(np.nan) x_a = np.empty((len(t), N)) x_a.fill(np.nan) # For the original background ensemble let's start close from the truth orig_bgd = 'fixed' #orig_bgd = 'random' if orig_bgd == 'fixed': indaux = np.arange(N) x0_aux = x0 + (-1)**indaux elif orig_bgd == 'random': x0_aux = x0 + np.random.randn(N) # For the first instant b and a are equal x_b[0, :] = x0_aux x_a[0, :] = x0_aux # The following cycle contains evolution and assimilation for j in range(totana): # Get the observations; these are distributed all over the # assimilation window yaux = y[anawin * j + 1:anawin * (j + 1) + 1, :] # [anawin,L] # First compute background; our background is the forecast # from the analysis xb0 = x_a[j * anawin * o2t, :] if model == 'lor63': taux, xbaux = lorenz63(xb0, o2t * anawin * tstep_truth) #elif model=='lor96': # taux,xbaux = lorenz96(o2t*anawin*tstep_truth,xb0,N) x_b[j * o2t * anawin:(j + 1) * o2t * anawin + 1, :] = xbaux xa0 = one4dvar(tstep_truth, o2t, anawin, xb0, yaux, H, B, R, model, N) if model == 'lor63': taux, xaaux = lorenz63(xa0, o2t * anawin * tstep_truth) #elif model=='lor96': # taux,xaaux = lorenz96(o2t*anawin*tstep_truth,xa0,N) x_a[j * o2t * anawin:(j + 1) * o2t * anawin + 1, :] = xaaux print 't =', tobs[anawin * (j + 1)] return x_b, x_a
from L63_model import lorenz63 from L63_misc import gen_obs, rmse_spread, createH, getBsimple from L63_var import var3d, var4d from L63_plots import plotL63, plotL63obs, plotL63DA_var, plotRMSP, tileplotB ############################################################################### ### 1.The Nature Run # Let us perform a 'free' run of the model, which we will consider the truth # The initial conditions x0 = [-10, -10, 20] Nx = np.size(x0) # The final time tmax = 10 # Computing the nature run paramtrue = [10.0, 8 / 3.0, 28.0] t, xt = lorenz63(x0, tmax, paramtrue) plotL63(t, xt) # A guess to start from in our assimilation experiments x0guess = [-11, -12, 10] ############################################################################### ### 2. The observations # Decide what variables to observe obsgrid = 'xyz' H, observed_vars = createH(obsgrid) period_obs = 10 var_obs = 1 # Generating the observations tobs, y, R = gen_obs(t, xt, period_obs, H, var_obs) plotL63obs(t, xt, tobs, y, observed_vars)