diff --git a/observations.py b/observations.py
deleted file mode 100644
index a2de25bf320231ae941fcae602c2f7dc6d644a94..0000000000000000000000000000000000000000
--- a/observations.py
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-import numpy as np
-from matplotlib import pyplot as p
-import glob
-import pandas as pd
-
-is_sorted = lambda a: np.all(a[:-1] <= a[1:])
-
-def decode_observations(observation_files):
-
-    # Read set of CSV files into a pandas dataframe.
-    # Based on:
-    # https://stackoverflow.com/questions/20906474/import-multiple-csv-files-into-pandas-and-concatenate-into-one-dataframe    
-
-    # Create a list of dataframes, one per file
-    all_files = sorted(glob.glob(observation_files))
-    li = []
-    for filename in all_files:
-        df = pd.read_csv(filename, index_col=None, header=0)
-        li.append(df)
-    nassim = len(li)
-
-    # Browse through all dataframes and get the maximum
-    # number of observation records
-    nobs = 0
-    for i in li:
-        nobs = max(i.shape[0],nobs)
-
-    # Create observation and coordinate arrays
-    observations = np.zeros((nassim,nobs))+np.nan
-    ocoords = np.zeros((nassim,nobs))+np.nan
-
-    # Reading from the dataframes and
-    # populate observation and coordinate arrays
-    for i in range(nassim):
-        ocoords[i,:] = li[i].get("z (m)")
-        observations[i,:] = li[i].get("theta (K)")
-
-    return observations,ocoords
-
-def random_sort_observations(observations,ocoords,truths=None):
-
-    # Check that input arrays have consistent dimensions
-    assert (observations.shape == ocoords.shape),\
-        f'observation and coordinate arrays must have the same size'
-
-    # Preallocate arrays
-    nassim,nobs = observations.shape
-    shuffled_obs = np.zeros(observations.shape)+np.nan
-    shuffled_coords = np.zeros(observations.shape)+np.nan
-
-    # Randomize arrays, differently at each time
-    if truths is None:
-        indices = np.arange(nobs)
-        for i in range(nassim):
-            np.random.shuffle(indices)
-            shuffled_obs[i,:] = observations[i,indices]
-            shuffled_coords[i,:] = ocoords[i,indices]
-            
-        return shuffled_obs,shuffled_coords
-
-    else:
-        # Check that truths array has consistent dimensions
-        assert (truths.shape == ocoords.shape),\
-            f'observation and coordinate arrays must have the same size'
-
-        # Preallocate truths array
-        shuffled_truths = np.zeros(ocoords.shape)+np.nan
-
-        # Randomize arrays, differently at each time
-        indices = np.arange(nobs)
-        for i in range(nassim):
-            np.random.shuffle(indices)
-            shuffled_obs[i,:] = observations[i,indices]
-            shuffled_coords[i,:] = ocoords[i,indices]
-            shuffled_truths[i,:] = truths[i,indices]
-        return shuffled_obs,shuffled_coords,shuffled_truths
-
-if __name__ == '__main__':
-
-    printout = False
-
-    # Read the observations
-    observations,ocoords = decode_observations('./LES_data/Theta/*csv')
-
-    if printout:
-        ntim = 0
-        for i in range(observations.shape[1]):
-            print(ocoords[ntim,i],observations[ntim,i])
-
-    # Sort the observations randomly
-    observations,ocoords = random_sort_observations(observations,ocoords)
-    if printout:
-        for i in range(observations.shape[1]):
-            print(ocoords[ntim,i],observations[ntim,i])
-
-    makeplots = True
-    # Make plots
-    if makeplots:
-
-        # If observations are shuffled, sort them again
-        ntimes = ocoords.shape[0]
-        for k in range(ntimes):
-            if is_sorted(ocoords[k,:]):
-                pass
-            else:
-                indices = np.argsort(ocoords[k,:])
-                ocoords[k,:] = ocoords[k,indices]
-                observations[k,:] = observations[k,indices]
-
-        fig, ax1 = p.subplots(1,1,constrained_layout=True)
-        fig.set_size_inches(4,3)
-
-        tint = 300
-        t = np.linspace(0,tint*(ocoords.shape[0]-1),ocoords.shape[0])[:,None]+np.zeros(ocoords.shape)
-        t = t/3600.
-        c = ax1.scatter(t,ocoords,s=5,c=observations,vmin=290,vmax=296)
-        ax1.contour(t,ocoords,observations,
-                np.linspace(290,290+0.003*2000,13),
-                colors='black',
-                linestyles='--',
-                linewidths=0.75)
-        ax1.set_ylim([0,2000])
-        ax1.set_ylabel(r'Height (m)')
-        ax1.set_xlabel(r'Time (s)')
-        ax1.set_title(r'$\overline{\theta}$ (K) obs in t=(%u-%u) h'%(t.min(),t.max()))
-        ax1.legend(frameon=False)
-        p.colorbar(c,orientation='horizontal')
-        fig.savefig('LES_obs.png',format='png',dpi=300)
-        p.close(fig)
diff --git a/replace_text.py b/replace_text.py
deleted file mode 100644
index 23218028979fde3c06e98d89ddd94fef4daff0d3..0000000000000000000000000000000000000000
--- a/replace_text.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-# Useful in order to edit
-# a set of config files all at once
-
-# https://stackoverflow.com/questions/74191831/how-to-replace-a-text-with-another-text-in-several-txt-files-at-the-same-time
-
-import glob
-import os
-
-# Input and output text files
-pathSource = "./runs/seed=181612_enssize=20_EAKF_6hrs/"
-pathDest = "./runs/seed=181612_enssize=20_EAKF_6hrs/"
-#pathDest = "./backup/config_files_new/"
-textFiles_Source = glob.glob(pathSource+"*.json") 
-textFiles_Dest = [i.replace(pathSource,pathDest) for i in textFiles_Source]
-
-if not os.path.exists(pathDest):
-    os.makedirs(pathDest)
-
-# searched text and replacement text
-search_text = '"cbl_settings_file": "./config_files/'
-replace_text = '"cbl_settings_file": "'
-#search_text = '"nature_run_from_file": "./runs/seed=181612_enssize=200_EAKF_6hrs/'
-#replace_text = '"nature_run_from_file": "./runs/seed=181612_enssize=200_LETKF_6hrs/'
-#search_text = '"nens": 20,'
-#replace_text = '"nens": 200,'
-
-# Loop over each text file in our list from above
-for source,dest in zip(textFiles_Source,textFiles_Dest):
-    # Opening our text file in read only
-    # mode using the open() function
-    with open(source, 'r') as file:
-    
-        # Reading the content of the file
-        # using the read() function and storing
-        # them in a new variable
-        data = file.read()
-    
-        # Searching and replacing the text
-        # using the replace() function
-        data = data.replace(search_text, replace_text)
-    
-    # Opening our text file in write only
-    # mode to write the replaced content
-    with open(dest, 'w') as file:
-    
-        # Writing the replaced data in our
-        # text file
-        file.write(data)
\ No newline at end of file
diff --git a/verification.py b/verification.py
deleted file mode 100644
index 5a8f2f385782c26c0c792bce58ab82612c3c3d25..0000000000000000000000000000000000000000
--- a/verification.py
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-import numpy as np
-from matplotlib import pyplot as p
-
-from PE_CBL_models import CBL
-from observations import decode_observations
-
-# Default CBL model settings
-default_cbl_settings ={
-    # Physical parameters
-    'g' : 9.806,
-    'f' : 1e-4,
-    'kvonk' : 0.4,
-    'z0' : 0.1,
-    'ug' : 0,
-    'vg' : 10,
-    'theta_0' : 290,
-    'gamma' : 3e-3,
-    'Hmax' : 0.12,
-    'H0_perturbation_ampl_init' : 0.0,
-    'H0_perturbation_ampl_time' : 0.0,
-    'exct' : 0.3,
-    'pfac' : 1.5,
-    'Kmin' : 0.1,
-    'Kmax' : 200,
-    # Model formulation
-    'is_bwind' : False,
-    'is_cgrad' : True,
-    'is_cycle' : False,
-    # Domain parameters (Kmax determines dt)
-    'dz' : 50,
-    'ztop' : 4000,
-    # Ensemble generation parameters (only effective for ensemble runs)
-    # Part 1: perturbation of initial state
-    # perturbation_type can be "smooth", "random", "uniform"
-    # the adjective refers to vertical variability
-    'rnseed' : 181612,
-    'perturb_ensemble_state' : True,
-    'perturbations_type' : "smooth",
-    'perturbations_theta_amplitude' : 0.1,
-    'perturbations_uv_amplitude' : 0.1,
-    'perturbations_smooth_number' : 11,
-    'perturbations_symmetric' : True,
-    'simulate_error_growth' : False,
-    'error_growth_perturbations_amplitude' : 0.0,
-    # Part 2: perturbation of parameters
-    'perturb_ensemble_parameters' : True,
-    'parameter_number' : 1,
-    'parameter_transform' : None,
-    'parameter_ensemble_min' : np.array([0.5]),
-    'parameter_ensemble_max' : np.array([4.5]),
-    'parameter_true' : np.array([1.5]),
-    # In case of parameter estimation
-    'do_parameter_estimation' : False,
-    'parameter_inflation_rtps_alpha' : np.array([0.8]),
-    'return_covariances_increments_and_innovations' : True
-    }
-
-def observation_operator(fp,xp,x):
-    f = np.interp(x, xp, fp)
-    return f
-
-if __name__ == '__main__':
-
-    # Settings
-    energy_diagnostics = False
-    sensitivity_to_p = True
-
-    # Read the observations
-    theta,z = decode_observations('./LES_data/Theta/*csv')
-    nassim,nobs = theta.shape
-    thicknesses = np.zeros(z.shape)+np.nan
-    for k in range(nassim):
-        thicknesses[k,:]=np.hstack((z[k,0],np.diff(z[k,:])))
-    tint = 300
-    t = np.linspace(0,tint*(z.shape[0]-1),z.shape[0])[:,None]+np.zeros(z.shape)
-
-    if energy_diagnostics:
-
-        # Compute delta theta wrt IC
-        theta_init = 290+z*0.003
-        delta_theta = theta-theta_init
-
-        # Set the sensible heat flux (kinematic units)
-        hfx = 0.12
-
-        # Run model
-        run_settings = dict(default_cbl_settings)
-        run = CBL(run_settings)
-        run.maxtime = 25200
-        run.initialize(1) 
-        run.run(output_full_history=True)
-        zt = run.zt
-
-        # Model state
-        model_theta = run.history['theta']
-        model_delta_theta = model_theta-model_theta[:,0][:,None]
-        model_thicknesses = run.dz*(np.ones(zt.size))[:,None]+np.zeros(model_theta.shape)
-        model_delta_theta = model_delta_theta.T
-        model_thicknesses = model_thicknesses.T
-        model_times = run.history['time']
-
-        # Model equivalents
-        model_equivalents = np.zeros(theta.shape)+np.nan
-        for i in range(int(nassim)):
-            valid_time = i*tint
-            time_index = np.argwhere(run.history['time'] == valid_time)[0][0]
-            for j in range(nobs):
-                model_equivalents[i,j] = observation_operator(model_theta[:,time_index],zt,z[i,j])
-        model_e_delta_theta = model_equivalents-theta_init
-        model_e_thicknesses = thicknesses
-        model_e_times = t
-
-        # Make plots
-        fig, [[ax1,ax2],[ax3,ax4]] = p.subplots(2,2,constrained_layout=True)
-        fig.set_size_inches(6,6)
-
-        # Time coordinate is hours
-        t = t/3600.
-
-        # Observations
-        c = ax1.pcolormesh(t,z,delta_theta,vmin=-3,vmax=3)
-        ax1.contour(t,z,theta,
-                np.linspace(290,290+0.003*2000,13),
-                colors='white',
-                linestyles='--',
-                linewidths=0.75)
-        ax1.set_ylim([0,2000])
-        ax1.set_ylabel(r'Height (m)')
-        ax1.set_xlabel(r'Time (h)')
-        ax1.set_title(r'$\Delta\overline{\theta}$ (K) observations')
-        p.colorbar(c,orientation='horizontal')
-
-        # Observations
-        d = ax2.pcolormesh(t,z,model_e_delta_theta,vmin=-3,vmax=3)
-        ax2.contour(t,z,model_equivalents,
-                np.linspace(290,290+0.003*2000,13),
-                colors='white',
-                linestyles='--',
-                linewidths=0.75)
-        ax2.set_ylim([0,2000])
-        ax2.set_ylabel(r'Height (m)')
-        ax2.set_xlabel(r'Time (h)')
-        ax2.set_title(r'$\Delta\overline{\theta}$ (K) model equivalents')
-        p.colorbar(d,orientation='horizontal')
-
-        # Difference
-        d = ax3.pcolormesh(t,z,model_equivalents-theta,vmin=-0.5,vmax=0.5,cmap='RdBu_r')
-        ax3.set_ylim([0,2000])
-        ax3.set_ylabel(r'Height (m)')
-        ax3.set_xlabel(r'Time (h)')
-        ax3.set_title(r'$\overline{\theta}_{fc}-\overline{\theta}_{obs}$ (K) differences')
-        ax3.text(3.5,100,'RMSD=%6.4f K'%np.mean((theta-model_equivalents)**2))
-        p.colorbar(d,orientation='horizontal')
-
-        # Energy diagnostics
-        ax4.plot(t[:,0],t[:,0]*3600*hfx,color='k',dashes=[3,1],zorder=10,label=r'$\int H dt$')
-        ax4.plot(model_times/3600,np.sum(model_delta_theta*model_thicknesses,axis=1),color='r',label=r'$\int\Delta\theta dz$, model state')
-        ax4.plot(model_e_times[:,0]/3600,np.sum(model_e_delta_theta*model_e_thicknesses,axis=1),color='orange',label=r'$\int\Delta\theta dz$, model equivalents')
-        ax4.plot(t[:,0],np.sum(delta_theta*thicknesses,axis=1),label=r'$\int\Delta\theta dz$, observations')
-        ax4.set_ylabel(r'$E/(\rho c_p)$ (K m)')
-        ax4.set_xlabel(r'Time (h)')
-        ax4.legend(prop={'size': 6})
-
-        fig.savefig('verification_1.png',format='png',dpi=300)
-        p.close(fig)
-
-    if sensitivity_to_p:
-
-        p_values = np.linspace(0.5,2,31)
-        rmsd = np.zeros(p_values.shape)
-
-        for k in range(p_values.size):
-            print('Run %02u'%k)
-
-            # Run model
-            run_settings = dict(default_cbl_settings)
-            run_settings['pfac'] = p_values[k]
-            run = CBL(run_settings)
-            run.maxtime = 25200
-            run.initialize(1) 
-            run.run(output_full_history=True)
-
-            # Model equivalents
-            model_theta = run.history['theta']
-            model_equivalents = np.zeros(theta.shape)+np.nan
-            for i in range(int(nassim)):
-                valid_time = i*tint
-                time_index = np.argwhere(run.history['time'] == valid_time)[0][0]
-                for j in range(nobs):
-                    model_equivalents[i,j] = observation_operator(model_theta[:,time_index],run.zt,z[i,j])
-
-            rmsd[k] = np.sqrt(np.mean((theta-model_equivalents)**2))
-
-        # Make plots
-        fig, ax1 = p.subplots(1,1,constrained_layout=True)
-        fig.set_size_inches(4,3)
-
-        ax1.plot(p_values,rmsd)
-        ax1.set_xlabel('$p$')
-        ax1.set_ylabel('RMSD (K)')
-
-        fig.savefig('verification_2.png',format='png',dpi=300)
-        p.close(fig)