From 0da787c84dbf909247bf68a6506ade971bf5006c Mon Sep 17 00:00:00 2001
From: lkugler <lukas.kugler@gmail.com>
Date: Mon, 13 Sep 2021 19:05:49 +0200
Subject: [PATCH] bugfix

---
 scripts/assim_synth_obs.py | 99 +++++++++++++++++++++-----------------
 scripts/create_obsseq.py   | 16 +++---
 2 files changed, 65 insertions(+), 50 deletions(-)

diff --git a/scripts/assim_synth_obs.py b/scripts/assim_synth_obs.py
index b15eec7..df29afc 100755
--- a/scripts/assim_synth_obs.py
+++ b/scripts/assim_synth_obs.py
@@ -74,6 +74,7 @@ def replace_errors_obsseqout(f, new_errors):
     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:
@@ -96,7 +97,7 @@ def replace_errors_obsseqout(f, new_errors):
 
             previous_err_var = obsseq[line_error_obs_i]
             new_err_obs_i = new_errors[i_obs]**2  # variance in obs_seq.out
-            #print('previous err var ', previous_err_var, 'new error', new_err_obs_i)
+            if debug: print('previous err var ', previous_err_var, 'new error', new_err_obs_i)
             obsseq[line_error_obs_i] = ' '+str(new_err_obs_i)+' \n'
 
             i_obs += 1  # next iteration
@@ -189,9 +190,10 @@ def obs_operator_ensemble(istage):
         # DART may need a wrfinput file as well, which serves as a template for dimension sizes
         symlink(cluster.dartrundir+'/wrfout_d01', cluster.dartrundir+'/wrfinput_d01')
         
+        # I dont think this is necessary, we do this already in pre_assim.py
         # add geodata, if istage>0, wrfout is DART output (has coords)
-        if istage == 0:
-            wrfout_add_geo.run(cluster.dartrundir+'/geo_em.d01.nc', cluster.dartrundir+'/wrfout_d01')
+        #if istage == 0:
+        #    wrfout_add_geo.run(cluster.dartrundir+'/geo_em.d01.nc', cluster.dartrundir+'/wrfout_d01')
 
         # run perfect_model obs (forward operator)
         os.system('mpirun -np 12 ./perfect_model_obs > /dev/null')
@@ -221,6 +223,7 @@ def link_nature_to_dart_truth(time):
                 cluster.dartrundir+'/wrfout_d01')
     # DART may need a wrfinput file as well, which serves as a template for dimension sizes
     symlink(cluster.dartrundir+'/wrfout_d01', cluster.dartrundir+'/wrfinput_d01')
+    print('linked', time.strftime(cluster.nature_wrfout), 'to', cluster.dartrundir+'/wrfout_d01')
 
 
 def prepare_nature_dart(time):
@@ -254,7 +257,7 @@ def run_perfect_model_obs():
     os.system('mpirun -np 12 ./perfect_model_obs > log.perfect_model_obs')
     if not os.path.exists(cluster.dartrundir+'/obs_seq.out'):
         raise RuntimeError('obs_seq.out does not exist in '+cluster.dartrundir, 
-                           '\n look for '+cluster.dartrundir+'log.perfect_model_obs')
+                           '\n look for '+cluster.dartrundir+'/log.perfect_model_obs')
 
 def assimilate(nproc=96):
     print('time now', dt.datetime.now())
@@ -279,6 +282,8 @@ def archive_diagnostics(archive_dir, time):
     #     warnings.warn(str(e))
 
 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)
 
@@ -344,6 +349,9 @@ if __name__ == "__main__":
     
     Assumptions:
     - x_ensemble is already linked for DART to advance_temp<iens>/wrfout_d01
+
+    Example call:
+    python assim.py 2008-08-07_12:00
     """
 
     time = dt.datetime.strptime(sys.argv[1], '%Y-%m-%d_%H:%M')
@@ -360,20 +368,21 @@ if __name__ == "__main__":
 
     ################################################
     print(' 1) get the assimilation errors in a single vector ')
-    error_assimilate = []
+    error_generate = []
 
     for i, obscfg in enumerate(exp.observations):
         n_obs = obscfg['n_obs']
-        n_obs_z = obscfg.get('heights', 1)
+        n_obs_z = len(obscfg.get('heights', [1,]))
         n_obs_3d = n_obs * n_obs_z
 
         parametrized = obscfg.get('sat_channel') == 6
+
         if not parametrized:
             err_this_type = np.zeros(n_obs_3d) + obscfg['error_generate']
 
         else:  # error parametrization for WV73
             # get observations for sat 6
-            osq.create_obsseqin_alltypes(time, [obscfg,], obs_errors='error_generate')
+            osq.create_obsseqin_alltypes(time, [obscfg,], np.zeros(n_obs_3d))
             run_perfect_model_obs()
             
             # depends on obs_seq.out produced before by run_perfect_model_obs()
@@ -382,11 +391,11 @@ if __name__ == "__main__":
             Hx_prior = obs_operator_ensemble(istage)  # files are already linked to DART directory
             err_this_type = calc_obserr_WV73(Hx_nat, Hx_prior)
      
-        error_assimilate.extend(err_this_type)
+        error_generate.extend(err_this_type)  # the obs-error we assume for generating observations
 
     ################################################
     print(' 2) generate observations ')
-    osq.create_obsseqin_alltypes(time, exp.observations, obs_errors='error_generate',
+    osq.create_obsseqin_alltypes(time, exp.observations, obs_errors=error_generate,
                              archive_obs_coords=archive_stage+'/obs_coords.pkl')
 
     first_obstype = exp.observations[0]
@@ -397,58 +406,60 @@ if __name__ == "__main__":
 
     ################################################
     print(' 3) assimilate with adapted observation-errors ')
+    error_assimilate = np.zeros(n_obs_3d) + obscfg['error_assimilate']  # the obs-error we assume for assimilation
     replace_errors_obsseqout(cluster.dartrundir+'/obs_seq.out', error_assimilate)
-    t = time.time()
+    t = time_module.time()
     assimilate()
+    print('filter took', time_module.time()-t, 'seconds')
     
     dir_obsseq = cluster.archivedir+'/obs_seq_final/assim_stage'+str(istage)
     archive_diagnostics(dir_obsseq, time)
     archive_output(archive_stage)
 
 
-    sys.exit()  # below is the code for separate assimilation of different obs types
+    #sys.exit()  # below is the code for separate assimilation of different obs types
 
-    for istage, obscfg in enumerate(exp.observations):
-        print('running observation stage', istage, obscfg)
+    #for istage, obscfg in enumerate(exp.observations):
+    #    print('running observation stage', istage, obscfg)
 
-        archive_stage = archive_time + '/assim_stage'+str(istage)+'/'
-        n_obs = obscfg['n_obs']
-        n_obs_3d = n_obs * len(obscfg['heights'])
-        sat_channel = obscfg.get('sat_channel', False)
+    #    archive_stage = archive_time + '/assim_stage'+str(istage)+'/'
+    #    n_obs = obscfg['n_obs']
+    #    n_obs_3d = n_obs * len(obscfg['heights'])
+    #    sat_channel = obscfg.get('sat_channel', False)
 
-        # debug option: overwrite time in prior files
-        # for iens in range(1,41):
-        #    os.system('ncks -A -v Times '+cluster.dartrundir+'/wrfout_d01 '+cluster.dartrundir+'/advance_temp'+str(iens)+'/wrfout_d01')
+    #    # debug option: overwrite time in prior files
+    #    # for iens in range(1,41):
+    #    #    os.system('ncks -A -v Times '+cluster.dartrundir+'/wrfout_d01 '+cluster.dartrundir+'/advance_temp'+str(iens)+'/wrfout_d01')
 
-        if error_assimilate == False:
-            # use error parametrization for assimilation-obs.errors
+    #    if error_assimilate == False:
+    #        # use error parametrization for assimilation-obs.errors
 
-            if sat_channel != 6:
-                raise NotImplementedError('sat channel '+str(sat_channel))
+    #        if sat_channel != 6:
+    #            raise NotImplementedError('sat channel '+str(sat_channel))
 
-            # depends on obs_seq.out produced before by run_perfect_model_obs()
-            Hx_nat, _ = read_truth_obs_obsseq(cluster.dartrundir+'/obs_seq.out')
+    #        # depends on obs_seq.out produced before by run_perfect_model_obs()
+    #        Hx_nat, _ = read_truth_obs_obsseq(cluster.dartrundir+'/obs_seq.out')
 
-            Hx_prior = obs_operator_ensemble(istage)  # files are already linked to DART directory
-            error_assimilate = calc_obserr_WV73(Hx_nat, Hx_prior)
+    #        Hx_prior = obs_operator_ensemble(istage)  # files are already linked to DART directory
+    #        error_assimilate = calc_obserr_WV73(Hx_nat, Hx_prior)
 
-        else:
-            # overwrite error values in obs_seq.out
-            error_assimilate = np.zeros(n_obs_3d) + error_assimilate  # ensure shape
+    #    else:
+    #        # overwrite error values in obs_seq.out
+    #        error_assimilate = np.zeros(n_obs_3d) + error_assimilate  # ensure shape
 
-        replace_errors_obsseqout(cluster.dartrundir+'/obs_seq.out', error_assimilate)
-        assimilate()
-        dir_obsseq = cluster.archivedir+'/obs_seq_final/assim_stage'+str(istage)
-        archive_diagnostics(dir_obsseq, time)
+    #    replace_errors_obsseqout(cluster.dartrundir+'/obs_seq.out', error_assimilate)
+    #    assimilate()
+    #    dir_obsseq = cluster.archivedir+'/obs_seq_final/assim_stage'+str(istage)
+    #    archive_diagnostics(dir_obsseq, time)
 
-        if istage < n_stages-1:
-            # recirculation: filter output -> input
-            archive_output(archive_stage)
-            recycle_output()
+    #    if istage < n_stages-1:
+    #        # recirculation: filter output -> input
+    #        archive_output(archive_stage)
+    #        recycle_output()
 
-        elif istage == n_stages-1:
-            # last assimilation, continue integration now
-            archive_output(archive_stage)
+    #    elif istage == n_stages-1:
+    #        # last assimilation, continue integration now
+    #        archive_output(archive_stage)
 
-        else:
-            RuntimeError('this should never occur?!')
+    #    else:
+    #        RuntimeError('this should never occur?!')
diff --git a/scripts/create_obsseq.py b/scripts/create_obsseq.py
index 2b54b79..1d06ac7 100755
--- a/scripts/create_obsseq.py
+++ b/scripts/create_obsseq.py
@@ -143,7 +143,7 @@ def calc_obs_locations(n_obs, coords_from_domaincenter=True,
 
         omit_covloc_radius_on_boundary = True
         if omit_covloc_radius_on_boundary:  #  in order to avoid an increment step on the boundary
-            skip_km = cov_loc_radius_km*1.5
+            skip_km = 50  # cov_loc_radius_km*1.5
             skip_gridpoints = int(skip_km/model_dx_km)  # skip this many gridpoints on each side
 
             gridpoints_left = nx - 2*skip_gridpoints
@@ -376,13 +376,14 @@ def create_obsseq_in_separate_obs(time_dt, obscfg, obs_errors=False,
     write_file(txt, output_path=cluster.dartrundir+'/obs_seq.in')
 
 
-def create_obsseqin_alltypes(time_dt, list_obscfg, obs_errors='error_assimilate', archive_obs_coords=False):
+def create_obsseqin_alltypes(time_dt, list_obscfg, obs_errors, archive_obs_coords=False):
     """Create obs_seq.in with multiple obs types in one file
 
     Args:
         time_dt (dt.datetime): time of observation
         list_obscfg (list of dict)
-        obs_errors (False or str): Key to obsdict, which field contains the error values
+        obs_errors (list of float, False): contains observation errors, one for each observation
+              if False: use zero error
         archive_obs_coords (bool, str): False or str (filepath where `obs_seq.in` will be saved)
     """
     print('creating obs_seq.in:')
@@ -411,9 +412,12 @@ def create_obsseqin_alltypes(time_dt, list_obscfg, obs_errors='error_assimilate'
         n_obs_3d_thistype = len(coords)
 
         # define obs error
-        obserr_std = np.zeros(n_obs_3d_thistype) 
-        if obs_errors:
-            obserr_std += obscfg[obs_errors]
+        if obs_errors == False:  
+            obs_errors = np.zeros(n_obs_3d_thistype)
+        assert len(obs_errors) == n_obs_3d_thistype, 'len(obs_errors) == n_obs_3d_thistype'
+        obserr_std = obs_errors #np.zeros(n_obs_3d_thistype) 
+        #if obs_errors:
+        #    obserr_std += obscfg[obs_errors]
 
         sat_info = write_sat_angle_appendix(sat_channel, lat0, lon0, time_dt)
 
-- 
GitLab