From a54a65f77c389209c8284374ea51e5a5374ea7c8 Mon Sep 17 00:00:00 2001
From: lkugler <lukas.kugler@gmail.com>
Date: Wed, 24 May 2023 15:13:56 +0200
Subject: [PATCH] collect all obs modules in one folder

---
 dartwrf/assim_synth_obs.py                    | 111 ++++--------------
 dartwrf/create_obs_upfront.py                 |   4 +-
 .../create_obsseq_in.py}                      |   4 +-
 dartwrf/obs/create_obsseq_out.py              |  70 +++++++++++
 dartwrf/{ => obs}/obskind.py                  |   0
 dartwrf/{ => obs}/obsseq.py                   |   2 +-
 dartwrf/{ => obs}/obsseq_2dim.py              |   2 +-
 dartwrf/{ => obs}/obsseq_to_netcdf.py         |   2 +-
 dartwrf/{ => obs}/run_obs_diag.py             |   0
 dartwrf/workflows.py                          |   2 +-
 tests/test_assim.py                           |   3 +-
 tests/test_dart-rttov.py                      |   4 +-
 tests/test_obsseq.py                          |   2 +-
 13 files changed, 104 insertions(+), 102 deletions(-)
 rename dartwrf/{create_obsseq.py => obs/create_obsseq_in.py} (99%)
 create mode 100644 dartwrf/obs/create_obsseq_out.py
 rename dartwrf/{ => obs}/obskind.py (100%)
 rename dartwrf/{ => obs}/obsseq.py (99%)
 rename dartwrf/{ => obs}/obsseq_2dim.py (98%)
 rename dartwrf/{ => obs}/obsseq_to_netcdf.py (95%)
 rename dartwrf/{ => obs}/run_obs_diag.py (100%)

diff --git a/dartwrf/assim_synth_obs.py b/dartwrf/assim_synth_obs.py
index 48b74ac..f3cdace 100755
--- a/dartwrf/assim_synth_obs.py
+++ b/dartwrf/assim_synth_obs.py
@@ -3,17 +3,15 @@ import time as time_module
 import datetime as dt
 import numpy as np
 
-from dartwrf.utils import symlink, copy, sed_inplace, append_file, mkdir, try_remove, print, shell, write_txt
-from dartwrf.obs import error_models as err
-import dartwrf.create_obsseq as osq
+from dartwrf.utils import symlink, copy, mkdir, try_remove, print, shell, write_txt
 from dartwrf import wrfout_add_geo
-from dartwrf import obsseq
+from dartwrf.obs import error_models as err
+from dartwrf.obs import obsseq
+from dartwrf.obs import create_obsseq_out as osq_out
 from dartwrf import dart_nml
 
-from dartwrf import exp_config 
-exp = exp_config.exp
-from dartwrf import server_config
-cluster = server_config.cluster
+from dartwrf.exp_config import exp
+from dartwrf.server_config import cluster
 wrfout_format = 'wrfout_d01_%Y-%m-%d_%H:%M:%S'
 
 
@@ -115,19 +113,6 @@ def write_list_of_outputfiles():
         files.append("./filter_restart_d01." + str(iens).zfill(4))
     write_txt(files, cluster.dart_rundir+'/output_list.txt')
 
-def run_perfect_model_obs(nproc=12, verbose=True):
-    if verbose:
-        print("generating observations - running ./perfect_model_obs")
-    os.chdir(cluster.dart_rundir)
-
-    try_remove(cluster.dart_rundir + "/obs_seq.out")
-    if not os.path.exists(cluster.dart_rundir + "/obs_seq.in"):
-        raise RuntimeError("obs_seq.in does not exist in " + cluster.dart_rundir)
-    shell(cluster.dart_modules+' mpirun -np '+str(nproc)+" ./perfect_model_obs > log.perfect_model_obs")
-    if not os.path.exists(cluster.dart_rundir + "/obs_seq.out"):
-        raise RuntimeError(
-            "obs_seq.out does not exist in " + cluster.dart_rundir,
-            "\n look for " + cluster.dart_rundir + "/log.perfect_model_obs")
 
 def filter(nproc=12):
     print("time now", dt.datetime.now())
@@ -219,10 +204,11 @@ def set_obserr_assimilate_in_obsseqout(oso, outfile="./obs_seq.out"):
         osf_prior (ObsSeq): python representation of obs_seq.final (output of filter in evaluate-mode without posterior)
                         contains prior values; used for parameterized errors
     """
+    from dartwrf.obs.obskind import obs_kind_nrs
 
     for obscfg in exp.observations:
         kind_str = obscfg['kind']  # e.g. 'RADIOSONDE_TEMPERATURE'
-        kind = osq.obs_kind_nrs[kind_str]  # e.g. 263
+        kind = obs_kind_nrs[kind_str]  # e.g. 263
 
         # modify observation error of each kind sequentially
         where_oso_iskind = oso.df.kind == kind
@@ -343,80 +329,25 @@ def evaluate(assim_time, obs_seq_out=False,
     copy(cluster.dart_rundir + "/obs_seq.final", fout)
     print(fout, "saved.")
 
-
-
-def generate_obsseq_out(time):
-
-    def ensure_physical_vis(oso):  # set reflectance < surface albedo to surface albedo
-        print(" 2.2) removing obs below surface albedo ")
-        clearsky_albedo = 0.2928
-
-        if_vis_obs = oso.df['kind'].values == 262
-        if_obs_below_surface_albedo = oso.df['observations'].values < clearsky_albedo
-        oso.df.loc[if_vis_obs & if_obs_below_surface_albedo, ('observations')] = clearsky_albedo
-        oso.to_dart(f=cluster.dart_rundir + "/obs_seq.out")
-        return oso
-
-
-    def apply_superobbing(oso):
-        try:
-            f_oso = dir_obsseq + time.strftime("/%Y-%m-%d_%H:%M_obs_seq.out-before_superob")
-            shutil.copy(cluster.dart_rundir + "/obs_seq.out-before_superob", f_oso)
-            print('saved', f_oso)
-        except Exception as e:
-            warnings.warn(str(e))
-
-        print(" 2.3) superobbing to", exp.superob_km, "km")
-        oso.df = oso.df.superob(window_km=exp.superob_km)
-        oso.to_dart(f=cluster.dart_rundir + "/obs_seq.out")
-
-
-    ##############################
-        
-    dir_obsseq=cluster.archivedir + "/obs_seq_out/"
-    os.makedirs(dir_obsseq, exist_ok=True)
-
-    osq.create_obs_seq_in(time, exp.observations)
-    run_perfect_model_obs()  # generate observation, draws from gaussian
-
-    print(" 2.1) obs preprocessing")
-    oso = obsseq.ObsSeq(cluster.dart_rundir + "/obs_seq.out")
-
-    oso = ensure_physical_vis(oso)
-
-    if getattr(exp, "superob_km", False):
-        oso = apply_superobbing(oso)
-
-    # archive complete obsseqout
-    f_oso = dir_obsseq + time.strftime("/%Y-%m-%d_%H:%M_obs_seq.out")
-    shutil.copy(cluster.dart_rundir + "/obs_seq.out", f_oso)
-    print('saved', f_oso)
-    return oso
-
-
 def get_obsseq_out(time):
+    """Prepares an obs_seq.out file in the run_DART folder
+
+    Args:
+        time (datetime): time of assimilation
 
-    # did we specify an obsseqout inputfile?
+    Returns:
+        obsseq.ObsSeq
+    """
     if exp.use_existing_obsseq != False: 
+        # use an existing obs_seq.out file
         f_obsseq = time.strftime(exp.use_existing_obsseq)
         copy(f_obsseq, cluster.dart_rundir+'/obs_seq.out')
         print(f_obsseq, 'copied to', cluster.dart_rundir+'/obs_seq.out')
-        oso = obsseq.ObsSeq(cluster.dart_rundir + "/obs_seq.out")
-    else:
-        # decision to NOT use existing obs_seq.out file
-        
-        # did we already generate observations?
-        # f_oso_thisexp = cluster.archivedir+'/obs_seq_out/'+time.strftime("/%Y-%m-%d_%H:%M_obs_seq.out")
-        # if os.path.isfile(f_oso_thisexp):
-        #     # oso exists
-        #     copy(f_oso_thisexp, cluster.dart_rundir+'/obs_seq.out')
-        #     print('copied existing obsseqout from', f_oso_thisexp)
-        #     oso = obsseq.ObsSeq(cluster.dart_rundir + "/obs_seq.out")
-        # else: 
-
-        # generate observations with new observation noise
-        oso = generate_obsseq_out(time)
-
+        oso = obsseq.ObsSeq(cluster.dart_rundir + "/obs_seq.out")  # read the obs_seq.out file
+    else: 
+        # do NOT use an existing obs_seq.out file
+        # but generate observations with new observation noise
+        oso = osq_out.generate_obsseq_out(time)
     return oso
 
 def prepare_inflation_2(time, prior_init_time):
diff --git a/dartwrf/create_obs_upfront.py b/dartwrf/create_obs_upfront.py
index 4cf876b..c2ffc99 100755
--- a/dartwrf/create_obs_upfront.py
+++ b/dartwrf/create_obs_upfront.py
@@ -7,8 +7,8 @@ import numpy as np
 from dartwrf.exp_config import exp
 from dartwrf.server_config import cluster
 from dartwrf.utils import copy, print
-import dartwrf.create_obsseq as osq
-from dartwrf import obsseq
+import dartwrf.obs.create_obsseq_in as osq
+from dartwrf.obs import obsseq
 from dartwrf import assim_synth_obs as aso
 
 tformat = '%Y-%m-%d_%H:%M'
diff --git a/dartwrf/create_obsseq.py b/dartwrf/obs/create_obsseq_in.py
similarity index 99%
rename from dartwrf/create_obsseq.py
rename to dartwrf/obs/create_obsseq_in.py
index b7792f1..ebcbed5 100755
--- a/dartwrf/create_obsseq.py
+++ b/dartwrf/obs/create_obsseq_in.py
@@ -8,9 +8,9 @@ import datetime as dt
 from pysolar.solar import get_altitude, get_azimuth
 
 from dartwrf.server_config import cluster
-from dartwrf.obs import calculate_obs_locations as col
 from dartwrf import utils
-from dartwrf.obskind import obs_kind_nrs # dictionary string => DART internal indices
+from dartwrf.obs import calculate_obs_locations as col
+from dartwrf.obs.obskind import obs_kind_nrs # dictionary string => DART internal indices
 
 # position on earth for RTTOV ray geometry
 lat0 = 45.
diff --git a/dartwrf/obs/create_obsseq_out.py b/dartwrf/obs/create_obsseq_out.py
new file mode 100644
index 0000000..cb56e85
--- /dev/null
+++ b/dartwrf/obs/create_obsseq_out.py
@@ -0,0 +1,70 @@
+import os, shutil, warnings
+
+from dartwrf.utils import try_remove, print, shell
+import dartwrf.obs.create_obsseq_in as osi
+from dartwrf.obs import obsseq
+
+from dartwrf.exp_config import exp
+from dartwrf.server_config import cluster
+
+def generate_obsseq_out(time):
+
+    def ensure_physical_vis(oso):  # set reflectance < surface albedo to surface albedo
+        print(" 2.2) removing obs below surface albedo ")
+        clearsky_albedo = 0.2928
+
+        if_vis_obs = oso.df['kind'].values == 262
+        if_obs_below_surface_albedo = oso.df['observations'].values < clearsky_albedo
+        oso.df.loc[if_vis_obs & if_obs_below_surface_albedo, ('observations')] = clearsky_albedo
+        oso.to_dart(f=cluster.dart_rundir + "/obs_seq.out")
+        return oso
+
+
+    def apply_superobbing(oso):
+        try:
+            f_oso = dir_obsseq + time.strftime("/%Y-%m-%d_%H:%M_obs_seq.out-before_superob")
+            shutil.copy(cluster.dart_rundir + "/obs_seq.out-before_superob", f_oso)
+            print('saved', f_oso)
+        except Exception as e:
+            warnings.warn(str(e))
+
+        print(" 2.3) superobbing to", exp.superob_km, "km")
+        oso.df = oso.df.superob(window_km=exp.superob_km)
+        oso.to_dart(f=cluster.dart_rundir + "/obs_seq.out")
+
+
+    ##############################
+        
+    dir_obsseq=cluster.archivedir + "/obs_seq_out/"
+    os.makedirs(dir_obsseq, exist_ok=True)
+
+    osi.create_obs_seq_in(time, exp.observations)
+    run_perfect_model_obs()  # generate observation, draws from gaussian
+
+    print(" 2.1) obs preprocessing")
+    oso = obsseq.ObsSeq(cluster.dart_rundir + "/obs_seq.out")
+
+    oso = ensure_physical_vis(oso)
+
+    if getattr(exp, "superob_km", False):
+        oso = apply_superobbing(oso)
+
+    # archive complete obsseqout
+    f_oso = dir_obsseq + time.strftime("/%Y-%m-%d_%H:%M_obs_seq.out")
+    shutil.copy(cluster.dart_rundir + "/obs_seq.out", f_oso)
+    print('saved', f_oso)
+    return oso
+
+def run_perfect_model_obs(nproc=12, verbose=True):
+    if verbose:
+        print("generating observations - running ./perfect_model_obs")
+    os.chdir(cluster.dart_rundir)
+
+    try_remove(cluster.dart_rundir + "/obs_seq.out")
+    if not os.path.exists(cluster.dart_rundir + "/obs_seq.in"):
+        raise RuntimeError("obs_seq.in does not exist in " + cluster.dart_rundir)
+    shell(cluster.dart_modules+' mpirun -np '+str(nproc)+" ./perfect_model_obs > log.perfect_model_obs")
+    if not os.path.exists(cluster.dart_rundir + "/obs_seq.out"):
+        raise RuntimeError(
+            "obs_seq.out does not exist in " + cluster.dart_rundir,
+            "\n look for " + cluster.dart_rundir + "/log.perfect_model_obs")
\ No newline at end of file
diff --git a/dartwrf/obskind.py b/dartwrf/obs/obskind.py
similarity index 100%
rename from dartwrf/obskind.py
rename to dartwrf/obs/obskind.py
diff --git a/dartwrf/obsseq.py b/dartwrf/obs/obsseq.py
similarity index 99%
rename from dartwrf/obsseq.py
rename to dartwrf/obs/obsseq.py
index fc20e51..e108e70 100755
--- a/dartwrf/obsseq.py
+++ b/dartwrf/obs/obsseq.py
@@ -703,7 +703,7 @@ class ObsSeq(object):
 
 
 if __name__ == "__main__":
-    from config.cluster import cluster
+    from dartwrf.server_config import cluster
     # for testing purposes
 
     # f = cluster.scriptsdir + "/../tests/obs_seq.orig.out"
diff --git a/dartwrf/obsseq_2dim.py b/dartwrf/obs/obsseq_2dim.py
similarity index 98%
rename from dartwrf/obsseq_2dim.py
rename to dartwrf/obs/obsseq_2dim.py
index c9a647c..7239906 100755
--- a/dartwrf/obsseq_2dim.py
+++ b/dartwrf/obs/obsseq_2dim.py
@@ -22,7 +22,7 @@ import numpy as np
 from dartwrf.server_config import cluster
 from dartwrf import utils
 from dartwrf import assim_synth_obs as aso
-from dartwrf import obsseq
+from dartwrf.obs import obsseq
 
 def _get_n_obs_per_layer(oso):     
      """Get number of observations per layer"""
diff --git a/dartwrf/obsseq_to_netcdf.py b/dartwrf/obs/obsseq_to_netcdf.py
similarity index 95%
rename from dartwrf/obsseq_to_netcdf.py
rename to dartwrf/obs/obsseq_to_netcdf.py
index 14b0447..db40ff1 100644
--- a/dartwrf/obsseq_to_netcdf.py
+++ b/dartwrf/obs/obsseq_to_netcdf.py
@@ -2,7 +2,7 @@ import os, sys, glob, warnings
 
 from dartwrf.exp_config import exp
 from dartwrf.server_config import cluster
-import dartwrf.run_obs_diag as rod
+import dartwrf.obs.run_obs_diag as rod
 
 def listdir_dirs(path):
     return [a for a in os.listdir(path) if os.path.isdir(os.path.join(path, a))]
diff --git a/dartwrf/run_obs_diag.py b/dartwrf/obs/run_obs_diag.py
similarity index 100%
rename from dartwrf/run_obs_diag.py
rename to dartwrf/obs/run_obs_diag.py
diff --git a/dartwrf/workflows.py b/dartwrf/workflows.py
index bbc67b4..62e1b6a 100644
--- a/dartwrf/workflows.py
+++ b/dartwrf/workflows.py
@@ -112,7 +112,7 @@ class WorkFlows(object):
 
         # copy obs kind def to config, we will read a table from there
         # file needs to exist within package so sphinx can read it
-        _dict_to_py(_obskind_read(), this_dir+'/obskind.py')
+        _dict_to_py(_obskind_read(), this_dir+'/obs/obskind.py')
 
         _copy_dartwrf_to_archive()  # includes config files
 
diff --git a/tests/test_assim.py b/tests/test_assim.py
index d53b53b..7f61e27 100644
--- a/tests/test_assim.py
+++ b/tests/test_assim.py
@@ -1,7 +1,8 @@
 import os, shutil
 import datetime as dt
 
-from dartwrf import obsseq, assim_synth_obs
+from dartwrf import assim_synth_obs
+from dartwrf.obs import obsseq
 from dartwrf.server_config import cluster
 
 class ExperimentConfiguration(object):
diff --git a/tests/test_dart-rttov.py b/tests/test_dart-rttov.py
index ada56bf..f5f3153 100644
--- a/tests/test_dart-rttov.py
+++ b/tests/test_dart-rttov.py
@@ -3,8 +3,8 @@ import numpy as np
 import datetime as dt
 import pandas as pd
 
-from dartwrf import obsseq
-import dartwrf.create_obsseq as osq
+from dartwrf.obs import obsseq
+import dartwrf.obs.create_obsseq_in as osq
 import dartwrf.assim_synth_obs as aso
 from dartwrf import wrfout_add_geo
 
diff --git a/tests/test_obsseq.py b/tests/test_obsseq.py
index 215df54..7769465 100644
--- a/tests/test_obsseq.py
+++ b/tests/test_obsseq.py
@@ -2,7 +2,7 @@ import os, filecmp, shutil
 import numpy as np
 
 from dartwrf.server_config import cluster
-from dartwrf import obsseq
+from dartwrf.obs import obsseq
 
 
 def test_oso():
-- 
GitLab