From 7df30c01181e06d00379d2f056dd8b847263e24f Mon Sep 17 00:00:00 2001 From: lkugler <lukas.kugler@gmail.com> Date: Tue, 18 Oct 2022 11:10:28 +0200 Subject: [PATCH] other --- dartwrf/obs/__init__.py | 0 dartwrf/obsseq.py | 21 ++++-- dartwrf/old_functions.py | 145 +++++++++++++++++++++++++++++++++++++++ dartwrf/run_obs_diag.py | 6 +- templates/input.nml | 2 +- 5 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 dartwrf/obs/__init__.py create mode 100644 dartwrf/old_functions.py diff --git a/dartwrf/obs/__init__.py b/dartwrf/obs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dartwrf/obsseq.py b/dartwrf/obsseq.py index cd71c54..e3fa8ad 100755 --- a/dartwrf/obsseq.py +++ b/dartwrf/obsseq.py @@ -77,7 +77,13 @@ class ObsRecord(pd.DataFrame): def get_posterior_Hx(self): """Return posterior Hx array (n_obs, n_ens)""" - return self._get_model_Hx('posterior') + try: + return self._get_model_Hx('posterior') + except Exception as e: + # this is useful if we evaluate a 'posterior state' + # then the variable is called 'prior' while it really is a posterior + warnings.warn(str(e)+' returning prior from this file instead!') + return self._get_model_Hx('prior') def get_truth_Hx(self): return self['truth'].values @@ -691,12 +697,15 @@ class ObsSeq(object): if __name__ == "__main__": # for testing purposes - obs = ObsSeq(cluster.scriptsdir + "/../tests/obs_seq.orig.out") - print(type(obs)) + # f = cluster.scriptsdir + "/../tests/obs_seq.orig.out" + f = "/home/fs71386/lkugler/data/sim_archive/exp_v1.21_P3_wbub7_VIS_obs2-10_loc20/obs_seq_out/2008-07-30_12:30_obs_seq.out-orig" + obs = ObsSeq(f) # select a subset (lat-lon) - obs.df = obs.df[:].superob(window_km=50) - print(type(obs.df)) + obs.df = obs.df.superob(window_km=10) + # print(type(obs.df)) + + obs.plot(f_out="./map_obs_superobs.png") # write to obs_seq.out in DART format - obs.to_dart(f=cluster.dartrundir + "/obs_seq.out") + # obs.to_dart(f=cluster.dartrundir + "/obs_seq.out") diff --git a/dartwrf/old_functions.py b/dartwrf/old_functions.py new file mode 100644 index 0000000..c8ffebe --- /dev/null +++ b/dartwrf/old_functions.py @@ -0,0 +1,145 @@ +def recycle_output(): + """Use output of assimilation (./filter) as input for another assimilation (with ./filter) + Specifically, this copies the state fields from filter_restart_d01.000x to the wrfout files in advance_temp folders""" + update_vars = ['U', 'V', 'T', 'PH', 'MU', 'QVAPOR', 'QCLOUD', 'QICE', 'QRAIN', 'U10', 'V10', 'T2', 'Q2', 'TSK', 'PSFC', 'CLDFRA'] + updates = ','.join(update_vars) + + print('recycle DART output to be used as input') + for iens in range(1, exp.n_ens+1): + dart_output = cluster.dartrundir+'/filter_restart_d01.'+str(iens).zfill(4) + dart_input = cluster.dartrundir+'/advance_temp'+str(iens)+'/wrfout_d01' + + #print('check for non-monotonic vertical pressure') + + # convert link to file in order to be able to update the content + if os.path.islink(dart_input): + l = os.readlink(dart_input) + os.remove(dart_input) + copy(l, dart_input) + + # print('move DART output to input: '+dart_output+' -> '+dart_input) + # os.rename(dart_output, dart_input) # probably doesnt work + + print('updating', updates, 'in', dart_input, 'from', dart_output) + os.system(cluster.ncks+' -A -v '+updates+' '+dart_output+' '+dart_input) + + +def run_Hx(time, obscfg): + """ + # assumes that prior ensemble is already linked to advance_temp<i>/wrfout_d01 + Creates + obs_seq.final (file): observations on (non-averaged) grid + """ + get_obsseq_out(time) + print("running H(x) : obs operator on ensemble prior") + + # set input.nml to calculate prior Hx + set_DART_nml(just_prior_values=True) + + # run filter to calculate prior Hx + shell("mpirun -np 12 ./filter &> log.filter.preassim") + + osf = obsseq.ObsSeq(cluster.dartrundir + "/obs_seq.final") + + if getattr(exp, "superob_km", False): + df = osf.df + print("superobbing to", exp.superob_km, "km") + osf.df = osf.df.superob(window_km=exp.superob_km) + osf.to_dart(cluster.dartrundir + "/obs_seq.final") + return osf + + + +def replace_errors_obsseqout(f, new_errors): + """Replaces existing observation errors in obs_seq.final files + + new_errors (np.array) : standard deviation, + shape must match the number of observations + """ + debug = True + obsseq = open(f, "r").readlines() + + # find number of lines between two ' OBS ' lines: + first_obs = second_obs = None + for i, line in enumerate(obsseq): + if " OBS " in line: + if first_obs is None: + first_obs = i + else: + second_obs = i + break + if not second_obs: + raise RuntimeError('just one OBS in this file?! '+str(f)) + lines_between = second_obs - first_obs + lines_obserr_after_obsnr = lines_between - 1 # obserr line is one before ' OBS ' line + + # replace values in list obsseq + i_obs = 0 + for i, line in enumerate(obsseq): + if " OBS " in line: + line_error_obs_i = i + lines_obserr_after_obsnr + + previous_err_var = obsseq[line_error_obs_i] + new_err_obs_i = new_errors[i_obs] ** 2 # variance in obs_seq.out + if debug: + print( + line.strip(), + "previous err var ", + float(previous_err_var.strip()), + "new error", + new_err_obs_i, + ) + obsseq[line_error_obs_i] = " " + str(new_err_obs_i) + " \n" + + i_obs += 1 # next iteration + + with open(f, "w") as file: + for line in obsseq: + file.write(line) + print("replaced obs errors in", f) + + + +def obs_operator_nature(time): + print("getting true values in obs space from nature run") + prepare_nature_dart(time) + run_perfect_model_obs() + true, _ = read_truth_obs_obsseq(cluster.dartrundir + "/obs_seq.out") + return true + + + +def read_truth_obs_obsseq(f): + """Reads observed and true values from obs_seq.out/final files.""" + obsseq = open(f, "r").readlines() + true = [] + obs = [] + # read observations from obs_seq.out + for i, line in enumerate(obsseq): + if " OBS " in line: + observed = float(obsseq[i + 1].strip()) + truth = float(obsseq[i + 2].strip()) + true.append(truth) + obs.append(observed) + return true, obs + + +def read_prior_obs(f_obs_prior): + """ + docstring + """ + obsseq = open(f_obs_prior, "r").readlines() + OBSs = [] + # read observations from obs_seq.final + for i, line in enumerate(obsseq): + if " OBS " in line: + observed = float(obsseq[i + 1].strip()) + truth = float(obsseq[i + 2].strip()) + prior_ensmean = float(obsseq[i + 3].strip()) + prior_enssd = float(obsseq[i + 4].strip()) + prior_ens = [] + for j in range(5, 5 + exp.n_ens): + prior_ens.append(float(obsseq[i + j].strip())) + + OBSs.append(dict(observed=observed, truth=truth, prior_ens=np.array(prior_ens))) + return OBSs \ No newline at end of file diff --git a/dartwrf/run_obs_diag.py b/dartwrf/run_obs_diag.py index d3d3feb..fb327b5 100644 --- a/dartwrf/run_obs_diag.py +++ b/dartwrf/run_obs_diag.py @@ -1,6 +1,6 @@ import os, sys, shutil, glob from config.cfg import exp, cluster -from utils import symlink, copy, sed_inplace, append_file +from utils import symlink, copy, sed_inplace, append_file, shell rundir_program = '/home/fs71386/lkugler/data/run_DART/' @@ -38,7 +38,7 @@ def run_obsdiag(filepaths, f_out='./obsdiag.nc'): print('------ running obs_diag program') os.chdir(rundir_program) symlink(cluster.dart_srcdir+'/obs_diag', rundir_program+'/obs_diag') - os.system('./obs_diag >& obs_diag.log') # caution, this overwrites obs_seq_to_netcdf + shell(cluster.container, './obs_diag >& obs_diag.log') # caution, this overwrites obs_seq_to_netcdf # move output to archive #outdir = os.path.dirname(f_out) #'/'.join(folder_obs_seq_final.split('/')[:-1]) @@ -56,7 +56,7 @@ def run_obs_seq_to_netcdf(filepaths, f_out='./obs_epoch.nc'): print('------ running obs_seq_to_netcdf program') #shutil.copy(cluster.dart_srcdir+'/obs_seq_to_netcdf-bak', rundir_program+'/obs_seq_to_netcdf') os.chdir(rundir_program) - os.system('./obs_seq_to_netcdf >& obs_seq_to_netcdf.log') # caution, overwrites its own binary?! + shell(cluster.container, './obs_seq_to_netcdf >& obs_seq_to_netcdf.log') # caution, overwrites its own binary?! shutil.move(rundir_program+'/obs_epoch_001.nc', f_out) print(f_out, 'saved.') diff --git a/templates/input.nml b/templates/input.nml index 97968eb..0e9d7a8 100644 --- a/templates/input.nml +++ b/templates/input.nml @@ -103,7 +103,7 @@ # localization radius, where the influence of an obs decreases # to ~half at 300 km, and ~0 at the edges of the area. &assim_tools_nml - filter_kind = 1, + filter_kind = <filter_kind>, cutoff = <cov_loc_radian>, sort_obs_inc = .false., spread_restoration = .false., -- GitLab