wrfrun 0.1.8__py3-none-any.whl → 0.1.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. wrfrun/cli.py +128 -0
  2. wrfrun/core/base.py +8 -5
  3. wrfrun/core/config.py +81 -150
  4. wrfrun/core/replay.py +1 -1
  5. wrfrun/core/server.py +81 -78
  6. wrfrun/extension/goos_sst/__init__.py +5 -5
  7. wrfrun/extension/goos_sst/core.py +4 -1
  8. wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +1 -1
  9. wrfrun/extension/goos_sst/res/__init__.py +17 -0
  10. wrfrun/extension/goos_sst/utils.py +21 -5
  11. wrfrun/extension/littler/__init__.py +57 -1
  12. wrfrun/extension/littler/{utils.py → core.py} +326 -40
  13. wrfrun/extension/utils.py +22 -21
  14. wrfrun/model/__init__.py +24 -1
  15. wrfrun/model/plot.py +253 -35
  16. wrfrun/model/utils.py +17 -8
  17. wrfrun/model/wrf/__init__.py +41 -0
  18. wrfrun/model/wrf/core.py +215 -99
  19. wrfrun/model/wrf/exec_wrap.py +49 -35
  20. wrfrun/model/wrf/namelist.py +79 -4
  21. wrfrun/model/wrf/{_metgrid.py → utils.py} +36 -2
  22. wrfrun/model/wrf/vtable.py +2 -1
  23. wrfrun/res/__init__.py +8 -5
  24. wrfrun/res/config/config.template.toml +50 -0
  25. wrfrun/res/{config.toml.template → config/wrf.template.toml} +7 -46
  26. wrfrun/res/run.template.sh +10 -0
  27. wrfrun/res/scheduler/lsf.template +5 -0
  28. wrfrun/res/{job_scheduler → scheduler}/pbs.template +1 -1
  29. wrfrun/res/{job_scheduler → scheduler}/slurm.template +2 -1
  30. wrfrun/run.py +19 -23
  31. wrfrun/scheduler/__init__.py +35 -0
  32. wrfrun/scheduler/env.py +44 -0
  33. wrfrun/scheduler/lsf.py +47 -0
  34. wrfrun/scheduler/pbs.py +48 -0
  35. wrfrun/scheduler/script.py +70 -0
  36. wrfrun/scheduler/slurm.py +48 -0
  37. wrfrun/scheduler/utils.py +14 -0
  38. wrfrun/utils.py +8 -3
  39. wrfrun/workspace/__init__.py +38 -0
  40. wrfrun/workspace/core.py +92 -0
  41. wrfrun/workspace/wrf.py +121 -0
  42. {wrfrun-0.1.8.dist-info → wrfrun-0.1.9.dist-info}/METADATA +3 -2
  43. wrfrun-0.1.9.dist-info/RECORD +62 -0
  44. wrfrun-0.1.9.dist-info/entry_points.txt +3 -0
  45. wrfrun/model/wrf/_ndown.py +0 -39
  46. wrfrun/pbs.py +0 -86
  47. wrfrun/res/run.sh.template +0 -16
  48. wrfrun/workspace.py +0 -88
  49. wrfrun-0.1.8.dist-info/RECORD +0 -51
  50. {wrfrun-0.1.8.dist-info → wrfrun-0.1.9.dist-info}/WHEEL +0 -0
@@ -0,0 +1,44 @@
1
+ """
2
+ wrfrun.scheduler.env
3
+ ####################
4
+
5
+ Functions to manage environment variables in job scheduler.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ in_job_scheduler
11
+
12
+ How Does wrfrun Check If It Is In A Job Scheduler?
13
+ **************************************************
14
+
15
+ If you submit your task through ``wrfrun``, that is,
16
+ set ``submit_job = True`` in :class:`WRFRun <wrfrun.run.WRFRun>`,
17
+ an environment variable called ``WRFRUN_ENV_JOB_SCHEDULER`` will be set.
18
+ ``wrfrun`` will determine if it is in a job scheduler by checking if ``WRFRUN_ENV_JOB_SCHEDULER`` appears in environment.
19
+
20
+ If you submit your task by your own,
21
+ it is recommended that add ``WRFRUN_ENV_JOB_SCHEDULER`` to the environment,
22
+ which can ensure ``wrfrun`` works properly in the job scheduler.
23
+ """
24
+
25
+ from os import environ
26
+
27
+
28
+ def in_job_scheduler() -> bool:
29
+ """
30
+ Check if ``wrfrun`` runs in a job scheduler task.
31
+
32
+ This function checks the environment variable ``WRFRUN_ENV_JOB_SCHEDULER``
33
+ to determine if ``wrfrun`` is running in a job scheduler task.
34
+
35
+ :return: ``True`` if in a job scheduler task, else ``False``.
36
+ :rtype: bool
37
+ """
38
+ if "WRFRUN_ENV_JOB_SCHEDULER" in environ:
39
+ return True
40
+ else:
41
+ return False
42
+
43
+
44
+ __all__ = ["in_job_scheduler"]
@@ -0,0 +1,47 @@
1
+ """
2
+ wrfrun.scheduler.lsf
3
+ ####################
4
+
5
+ Scheduler interface for LSF system.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ lsf_generate_settings
11
+ """
12
+
13
+ from wrfrun.core import WRFRUNConfig
14
+ from wrfrun.res import SCHEDULER_LSF_TEMPLATE
15
+ from .utils import get_core_num
16
+
17
+
18
+ def lsf_generate_settings(scheduler_config: dict) -> str:
19
+ """
20
+ This function generate bash settings for LSF job scheduler.
21
+
22
+ :return: Generated settings.
23
+ :rtype: str
24
+ """
25
+ # get log path and job scheduler config
26
+ log_path = WRFRUNConfig.get_log_path()
27
+
28
+ # get scheduler configs
29
+ stdout_log_path = f"{log_path}/lsf.log"
30
+ stderr_log_path = f"{log_path}/lsf.err"
31
+ node_num = scheduler_config["node_num"]
32
+ queue_name = scheduler_config["queue_name"]
33
+ core_num = get_core_num()
34
+
35
+ template_path = WRFRUNConfig.parse_resource_uri(SCHEDULER_LSF_TEMPLATE)
36
+ with open(template_path, "r") as f:
37
+ template = f.read()
38
+
39
+ return template.format(
40
+ STDOUT_LOG_PATH=stdout_log_path,
41
+ STDERR_LOG_PATH=stderr_log_path,
42
+ CORE_NUM=core_num * node_num,
43
+ QUEUE_NAME=queue_name,
44
+ )
45
+
46
+
47
+ __all__ = ["lsf_generate_settings"]
@@ -0,0 +1,48 @@
1
+ """
2
+ wrfrun.scheduler.pbs
3
+ ####################
4
+
5
+ Scheduler interface for PBS system.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ pbs_generate_settings
11
+ """
12
+
13
+ from wrfrun.core import WRFRUNConfig
14
+ from wrfrun.res import SCHEDULER_PBS_TEMPLATE
15
+ from .utils import get_core_num
16
+
17
+
18
+ def pbs_generate_settings(scheduler_config: dict) -> str:
19
+ """
20
+ This function generate bash settings for PBS job scheduler.
21
+
22
+ :return: Generated settings.
23
+ :rtype: str
24
+ """
25
+ # get log path and job scheduler config
26
+ log_path = WRFRUNConfig.get_log_path()
27
+
28
+ # get scheduler configs
29
+ stdout_log_path = f"{log_path}/pbs.log"
30
+ stderr_log_path = f"{log_path}/pbs.err"
31
+ node_num = scheduler_config["node_num"]
32
+ queue_name = scheduler_config["queue_name"]
33
+ core_num = get_core_num()
34
+
35
+ template_path = WRFRUNConfig.parse_resource_uri(SCHEDULER_PBS_TEMPLATE)
36
+ with open(template_path, "r") as f:
37
+ template = f.read()
38
+
39
+ return template.format(
40
+ STDOUT_LOG_PATH=stdout_log_path,
41
+ STDERR_LOG_PATH=stderr_log_path,
42
+ NODE_NUM=node_num,
43
+ CORE_NUM=core_num,
44
+ QUEUE_NAME=queue_name,
45
+ )
46
+
47
+
48
+ __all__ = ["pbs_generate_settings"]
@@ -0,0 +1,70 @@
1
+ from os.path import exists, abspath, dirname
2
+
3
+ from wrfrun import WRFRUNConfig
4
+ from wrfrun.res import RUN_SH_TEMPLATE
5
+ from wrfrun.utils import logger
6
+ from .lsf import lsf_generate_settings
7
+ from .pbs import pbs_generate_settings
8
+ from .slurm import slurm_generate_settings
9
+
10
+
11
+ def prepare_scheduler_script(main_file_path: str):
12
+ """
13
+ Prepare the bash script to be submitted to job scheduler.
14
+
15
+ :param main_file_path: Path of the main entry file.
16
+ :type main_file_path: str
17
+ """
18
+ # check main file path
19
+ if not exists(main_file_path):
20
+ logger.error(f"Wrong path of main entry file: {main_file_path}")
21
+ raise FileNotFoundError(f"Wrong path of main entry file: {main_file_path}")
22
+
23
+ # get absolute path of main entry file's parent directory
24
+ dir_path = abspath(dirname(main_file_path))
25
+
26
+ scheduler_configs = WRFRUNConfig.get_job_scheduler_config()
27
+
28
+ # generate scheduler settings
29
+ match scheduler_configs["job_scheduler"]:
30
+ case "lsf":
31
+ scheduler_settings = lsf_generate_settings(scheduler_configs)
32
+
33
+ case "pbs":
34
+ scheduler_settings = pbs_generate_settings(scheduler_configs)
35
+
36
+ case "slurm":
37
+ scheduler_settings = slurm_generate_settings(scheduler_configs)
38
+
39
+ case _:
40
+ logger.error(f"Unknown scheduler name: {scheduler_configs['job_scheduler']}")
41
+ raise ValueError(f"Unknown scheduler name: {scheduler_configs['job_scheduler']}")
42
+
43
+ # generate environment settings
44
+ env_settings = 'export WRFRUN_ENV_JOB_SCHEDULER=1\n'
45
+ if len(scheduler_configs["env_settings"]) > 0:
46
+ for key in scheduler_configs["env_settings"]:
47
+ env_settings += f"export {key}={scheduler_configs['env_settings'][key]}\n"
48
+
49
+ # generate command
50
+ exec_cmd = f"{scheduler_configs['python_interpreter']} {main_file_path}"
51
+
52
+ # generate shell script
53
+ shell_template_path = WRFRUNConfig.parse_resource_uri(RUN_SH_TEMPLATE)
54
+ with open(f"{dir_path}/run.sh", "w") as f:
55
+
56
+ with open(shell_template_path, "r") as f_template:
57
+ template = f_template.read()
58
+
59
+ template = template.format(
60
+ SCHEDULER_SETTINGS=scheduler_settings,
61
+ ENV_SETTINGS=env_settings,
62
+ WORK_COMMAND=exec_cmd,
63
+ )
64
+
65
+ f.write(template)
66
+
67
+ logger.info(f"Job scheduler script written to {dir_path}/run.sh")
68
+
69
+
70
+ __all__ = ["prepare_scheduler_script"]
@@ -0,0 +1,48 @@
1
+ """
2
+ wrfrun.scheduler.slurm
3
+ ######################
4
+
5
+ Scheduler interface for Slurm system.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ slurm_generate_settings
11
+ """
12
+
13
+ from wrfrun.core import WRFRUNConfig
14
+ from wrfrun.res import SCHEDULER_SLURM_TEMPLATE
15
+ from .utils import get_core_num
16
+
17
+
18
+ def slurm_generate_settings(scheduler_config: dict) -> str:
19
+ """
20
+ This function generate bash settings for Slurm job scheduler.
21
+
22
+ :return: Generated settings.
23
+ :rtype: str
24
+ """
25
+ # get log path and job scheduler config
26
+ log_path = WRFRUNConfig.get_log_path()
27
+
28
+ # get scheduler configs
29
+ stdout_log_path = f"{log_path}/slurm.log"
30
+ stderr_log_path = f"{log_path}/slurm.err"
31
+ node_num = scheduler_config["node_num"]
32
+ queue_name = scheduler_config["queue_name"]
33
+ core_num = get_core_num()
34
+
35
+ template_path = WRFRUNConfig.parse_resource_uri(SCHEDULER_SLURM_TEMPLATE)
36
+ with open(template_path, "r") as f:
37
+ template = f.read()
38
+
39
+ return template.format(
40
+ STDOUT_LOG_PATH=stdout_log_path,
41
+ STDERR_LOG_PATH=stderr_log_path,
42
+ CORE_NUM=core_num,
43
+ NODE_NUM=node_num,
44
+ QUEUE_NAME=queue_name,
45
+ )
46
+
47
+
48
+ __all__ = ["slurm_generate_settings"]
@@ -0,0 +1,14 @@
1
+ from wrfrun import WRFRUNConfig
2
+
3
+
4
+ def get_core_num() -> int:
5
+ """
6
+ Get core number.
7
+
8
+ :return: Core number.
9
+ :rtype: int
10
+ """
11
+ return WRFRUNConfig["core_num"]
12
+
13
+
14
+ __all__ = ["get_core_num"]
wrfrun/utils.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import subprocess
3
3
  from datetime import datetime
4
- from os import chdir, getcwd, makedirs
4
+ from os import chdir, getcwd, makedirs, environ
5
5
  from os.path import exists
6
6
  from shutil import rmtree
7
7
  from time import time
@@ -45,7 +45,12 @@ def set_logger(logger_list: List[str], logger_level: Optional[Dict] = None):
45
45
 
46
46
  # init wrfrun logger
47
47
  logger = logging.getLogger("wrfrun")
48
- set_logger(["wrfrun", ], {"wrfrun": logging.DEBUG})
48
+ # check environment variables and set logger level
49
+ if "WRFRUN_DEBUG_MODE" in environ and environ["WRFRUN_DEBUG_MODE"]:
50
+ _logger_level = logging.DEBUG
51
+ else:
52
+ _logger_level = logging.INFO
53
+ set_logger(["wrfrun", ], {"wrfrun": _logger_level})
49
54
 
50
55
 
51
56
  def unify_logger_format():
@@ -218,7 +223,7 @@ def check_subprocess_status(status: subprocess.CompletedProcess):
218
223
  logger.error(f"====== ====== ======")
219
224
 
220
225
  # raise error
221
- raise RuntimeError
226
+ raise RuntimeError(f"Failed to exec command: '{command}'. Please check the log above.")
222
227
 
223
228
 
224
229
  def call_subprocess(command: list[str], work_path: Optional[str] = None, print_output=False):
@@ -0,0 +1,38 @@
1
+ """
2
+ wrfrun.workspace
3
+ ################
4
+
5
+ Prepare ``workspace`` for ``wrfrun`` and numerical models.
6
+
7
+ Submodules
8
+ **********
9
+
10
+ ================================= ===========================================================
11
+ :doc:`core </api/workspace.core>` Core functions of this submodule.
12
+ :doc:`wrf </api/workspace.wrf>` Functions to prepare workspace for WPS/WRF model.
13
+ ================================= ===========================================================
14
+
15
+ Workspace
16
+ *********
17
+
18
+ ``workspace`` is a collection of several directories where ``wrfrun``, extensions and numerical model works.
19
+ These directories and their purpose are listed below.
20
+
21
+ =================================== ===========================================================
22
+ Director Path Purpose
23
+ =================================== ===========================================================
24
+ ``/tmp/wrfrun`` Store temporary files.
25
+ ``$HOME/.config/wrfrun`` Main work directory.
26
+ ``$HOME/.config/wrfrun/replay`` Work directory for :doc:`replay <wrfrun.core.replay>`.
27
+ ``$HOME/.config/wrfrun/model`` Work directory for numerical models.
28
+ =================================== ===========================================================
29
+
30
+ .. toctree::
31
+ :maxdepth: 1
32
+ :hidden:
33
+
34
+ core <workspace.core>
35
+ wrf <workspace.wrf>
36
+ """
37
+
38
+ from .core import *
@@ -0,0 +1,92 @@
1
+ """
2
+ wrfrun.workspace.core
3
+ #####################
4
+
5
+ Core functions to prepare ``wrfrun`` workspace.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ prepare_workspace
11
+ """
12
+
13
+ from os.path import exists
14
+ from shutil import rmtree
15
+
16
+ from wrfrun import WRFRUNConfig
17
+ from wrfrun.utils import check_path, logger
18
+ from .wrf import prepare_wrf_workspace, check_wrf_workspace
19
+
20
+
21
+ def prepare_workspace():
22
+ """
23
+ Initialize ``wrfrun`` workspace.
24
+
25
+ This function will check following paths,
26
+ and create them if them don't exist:
27
+
28
+ 1. ``/tmp/wrfrun``
29
+ 2. ``$HOME/.config/wrfrun``
30
+ 3. ``$HOME/.config/wrfrun/replay``
31
+ 4. ``$HOME/.config/wrfrun/model``
32
+
33
+ It will call other responding functions to initialize workspace for numerical models:
34
+
35
+ 1. :doc:`WPS/WRF model </api/workspace.wrf>`
36
+ """
37
+ logger.info(f"Initialize main workspace.")
38
+
39
+ wrfrun_temp_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_TEMP_PATH)
40
+ workspace_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_WORKSPACE_ROOT)
41
+ replay_work_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_WORKSPACE_REPLAY)
42
+ output_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_OUTPUT_PATH)
43
+
44
+ if exists(workspace_path):
45
+ logger.info(f"Remove old files in workspace.")
46
+ rmtree(workspace_path)
47
+
48
+ # check folder
49
+ check_path(wrfrun_temp_path)
50
+ check_path(replay_work_path)
51
+ check_path(output_path)
52
+
53
+ func_map = {
54
+ "wrf": prepare_wrf_workspace
55
+ }
56
+ model_configs = WRFRUNConfig["model"]
57
+
58
+ for model_name in model_configs:
59
+ func_map[model_name](model_configs[model_name])
60
+
61
+
62
+ def check_workspace() -> bool:
63
+ """
64
+ Check if workspace exists.
65
+
66
+ :return: ``True`` if workspace exists, ``False`` otherwise.
67
+ :rtype: bool
68
+ """
69
+
70
+ wrfrun_temp_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_TEMP_PATH)
71
+ workspace_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_WORKSPACE_ROOT)
72
+ replay_work_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_WORKSPACE_REPLAY)
73
+ output_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_OUTPUT_PATH)
74
+
75
+ flag = True
76
+ flag = flag & exists(wrfrun_temp_path) & exists(replay_work_path) & exists(output_path) & exists(workspace_path)
77
+
78
+ func_map = {
79
+ "wrf": check_wrf_workspace
80
+ }
81
+ model_configs = WRFRUNConfig["model"]
82
+
83
+ for model_name in model_configs:
84
+ if model_name == "debug_level":
85
+ continue
86
+
87
+ flag = flag & func_map[model_name](model_configs[model_name])
88
+
89
+ return True
90
+
91
+
92
+ __all__ = ["prepare_workspace", "check_workspace"]
@@ -0,0 +1,121 @@
1
+ """
2
+ wrfrun.workspace.wrf
3
+ ####################
4
+
5
+ Functions to prepare workspace for WPS/WRF model.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ prepare_wrf_workspace
11
+ check_wrf_workspace
12
+ """
13
+
14
+ from os import listdir, makedirs, symlink
15
+ from os.path import exists
16
+
17
+ from wrfrun.core import WRFRUNConfig
18
+ from wrfrun.utils import logger, check_path
19
+
20
+
21
+ WORKSPACE_MODEL_WPS = f"{WRFRUNConfig.WRFRUN_WORKSPACE_MODEL}/WPS"
22
+ WORKSPACE_MODEL_WRF = f"{WRFRUNConfig.WRFRUN_WORKSPACE_MODEL}/WRF"
23
+ WORKSPACE_MODEL_WRFDA = f"{WRFRUNConfig.WRFRUN_WORKSPACE_MODEL}/WRFDA"
24
+
25
+
26
+ def prepare_wrf_workspace(model_config: dict):
27
+ """
28
+ Initialize workspace for WPS/WRF model.
29
+
30
+ This function will check following paths,
31
+ and create them or delete old files inside:
32
+
33
+ 1. ``$HOME/.config/wrfrun/model/WPS``
34
+ 2. ``$HOME/.config/wrfrun/model/WRF``
35
+ 3. ``$HOME/.config/wrfrun/model/WRFDA``
36
+
37
+ :param model_config: Model config.
38
+ :type model_config: dict
39
+ """
40
+ logger.info(f"Initialize workspace for WPS/WRF.")
41
+
42
+ wps_path = model_config["wps_path"]
43
+ wrf_path = model_config["wrf_path"]
44
+ wrfda_path = model_config["wrfda_path"]
45
+
46
+ if not (wps_path and wrf_path):
47
+ logger.warning(f"No WPS/WRF model installation path given, skip initialization.")
48
+ return
49
+
50
+ if wps_path:
51
+ if not exists(wps_path):
52
+ logger.error(f"Your WPS path is wrong.")
53
+ raise FileNotFoundError(f"Your WPS path is wrong.")
54
+
55
+ wps_work_path = WRFRUNConfig.parse_resource_uri(WORKSPACE_MODEL_WPS)
56
+ check_path(wps_work_path, f"{wps_work_path}/outputs", force=True)
57
+
58
+ file_list = [x for x in listdir(wps_path) if x not in ["geogrid", "namelist.wps"]]
59
+ _ = [symlink(f"{wps_path}/{file}", f"{wps_work_path}/{file}") for file in file_list]
60
+ makedirs(f"{wps_work_path}/geogrid")
61
+ symlink(f"{wps_path}/geogrid/GEOGRID.TBL", f"{wps_work_path}/geogrid/GEOGRID.TBL")
62
+
63
+ if wrf_path:
64
+ if not exists(wrf_path):
65
+ logger.error(f"Your WRF path is wrong.")
66
+ raise FileNotFoundError(f"Your WRF path is wrong.")
67
+
68
+ wrf_work_path = WRFRUNConfig.parse_resource_uri(WORKSPACE_MODEL_WRF)
69
+ check_path(wrf_work_path, force=True)
70
+
71
+ file_list = [x for x in listdir(f"{wrf_path}/run") if not x.startswith("namelist")]
72
+ _ = [symlink(f"{wrf_path}/run/{file}", f"{wrf_work_path}/{file}") for file in file_list]
73
+
74
+ if wrfda_path:
75
+ if not exists(wrfda_path):
76
+ logger.error(f"Your WRFDA path is wrong.")
77
+ raise FileNotFoundError(f"Your WRFDA path is wrong.")
78
+
79
+ wrfda_work_path = WRFRUNConfig.parse_resource_uri(WORKSPACE_MODEL_WRFDA)
80
+ check_path(wrfda_work_path, force=True)
81
+
82
+ file_list = ["da_wrfvar.exe", "da_update_bc.exe"]
83
+ _ = [symlink(f"{wrfda_path}/var/build/{file}", f"{wrfda_work_path}/{file}") for file in file_list]
84
+
85
+ file_list = listdir(f"{wrfda_path}/var/run")
86
+ _ = [symlink(f"{wrfda_path}/var/run/{file}", f"{wrfda_work_path}/{file}") for file in file_list]
87
+
88
+ symlink(f"{wrfda_path}/run/LANDUSE.TBL", f"{wrfda_work_path}/LANDUSE.TBL")
89
+
90
+
91
+ def check_wrf_workspace(model_config: dict) -> bool:
92
+ """
93
+ Check if WPS/WRF workspace exists.
94
+
95
+ :param model_config: Model config.
96
+ :type model_config: dict
97
+ :return: ``True`` if WPS/WRF workspace exists, ``False`` otherwise.
98
+ :rtype: bool
99
+ """
100
+ wps_path = model_config["wps_path"]
101
+ wrf_path = model_config["wrf_path"]
102
+ wrfda_path = model_config["wrfda_path"]
103
+
104
+ flag = True
105
+
106
+ if wps_path:
107
+ wps_work_path = WRFRUNConfig.parse_resource_uri(WORKSPACE_MODEL_WPS)
108
+ flag = flag & exists(wps_work_path)
109
+
110
+ if wrf_path:
111
+ wrf_work_path = WRFRUNConfig.parse_resource_uri(WORKSPACE_MODEL_WRF)
112
+ flag = flag & exists(wrf_work_path)
113
+
114
+ if wrfda_path:
115
+ wrfda_work_path = WRFRUNConfig.parse_resource_uri(WORKSPACE_MODEL_WRFDA)
116
+ flag = flag & exists(wrfda_work_path)
117
+
118
+ return flag
119
+
120
+
121
+ __all__ = ["prepare_wrf_workspace", "WORKSPACE_MODEL_WRF", "WORKSPACE_MODEL_WPS", "WORKSPACE_MODEL_WRFDA", "check_wrf_workspace"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wrfrun
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: wrfrun is a comprehensive toolkit for managing and using WRF
5
5
  Keywords: WRF
6
6
  Author-Email: Syize <syizeliu@gmail.com>
@@ -11,7 +11,7 @@ Project-URL: repository, https://github.com/Syize/wrfrun
11
11
  Project-URL: documentation, https://wrfrun.syize.cn
12
12
  Project-URL: Bug Tracker, https://github.com/Syize/wrfrun/issues
13
13
  Requires-Python: >=3.10
14
- Requires-Dist: numpy<2.0.0
14
+ Requires-Dist: numpy
15
15
  Requires-Dist: xarray
16
16
  Requires-Dist: netCDF4
17
17
  Requires-Dist: rich
@@ -24,6 +24,7 @@ Requires-Dist: wrf-python
24
24
  Requires-Dist: cfgrib
25
25
  Requires-Dist: tomli
26
26
  Requires-Dist: tomli-w
27
+ Requires-Dist: haversine
27
28
  Description-Content-Type: text/markdown
28
29
 
29
30
  # wrfrun: A toolkit to control WRF
@@ -0,0 +1,62 @@
1
+ wrfrun-0.1.9.dist-info/METADATA,sha256=RPtBDS1Ctr0OatYSqezZsgRqGj621sS-dijdt4oN2Vk,2932
2
+ wrfrun-0.1.9.dist-info/WHEEL,sha256=5J4neoE7k6LMgx4Fz1FHgBiO3YevhJGtNQ3muDrdLQM,75
3
+ wrfrun-0.1.9.dist-info/entry_points.txt,sha256=G3358n6wW1qZF3hSH9umxrWHJewN-6N1BUloacN2tks,50
4
+ wrfrun/__init__.py,sha256=l2zGk2qDWa3EXIlwvzqBYZHOU9273TN75Rmvx_7PAYM,58
5
+ wrfrun/cli.py,sha256=xaMxiHQCHvgHWKlPavYXkC9hGIo7JpUZaIsV8ZKr_SM,4300
6
+ wrfrun/data.py,sha256=W6IhopHpp0lhvVo-beuO6NsbfsGDmN5MNf8Bqkt7xsA,14845
7
+ wrfrun/run.py,sha256=aYRQ-YqjIt5g4MQEnphmZIwanT9TBlYCddcyXxtgD_s,8918
8
+ wrfrun/utils.py,sha256=BdGP5u2Y2e3tqU0dawfHsTeqZ0q4Ic4MCGR8RU4FJ90,8388
9
+ wrfrun/core/__init__.py,sha256=zsitfcmbO_Qf_Uh0FzZ4rceZAo3WEYev32jSjgRjtkw,1325
10
+ wrfrun/core/base.py,sha256=LXtol0AQlDiZYMZeQT3qRZVcQ-F0ETE7sMXdI1jriLw,30324
11
+ wrfrun/core/config.py,sha256=gljrE1j8qFNJb_VVJwhQ3E2pmapT9cFUg1pyWizEvjA,27457
12
+ wrfrun/core/error.py,sha256=etnImryyqDUggfZOKK1ynOm71GRSFJVGGOwhuiZahTI,2383
13
+ wrfrun/core/replay.py,sha256=jZWN68IgUroxuCzg7EO0FXxe2zwokxJnquu4t81hp7Y,4782
14
+ wrfrun/core/server.py,sha256=Kns4an_wqnrYsi0PJxJgQJY8ShjNDnvrxY5V7gsbDec,8660
15
+ wrfrun/extension/__init__.py,sha256=YDYCS0KD3e-uLvf1K08ktNfP2sUSKpbgkHrvXj21EPQ,913
16
+ wrfrun/extension/utils.py,sha256=mmcyqxOEVGSBu8t8ukB2SeRp9X_PLR0kWvfptBC_WWo,2458
17
+ wrfrun/extension/goos_sst/__init__.py,sha256=QsVheVVL5K0_k-eg8-xe2MLAJ845iivXzGHbp2qARh4,2101
18
+ wrfrun/extension/goos_sst/core.py,sha256=_s53vq0nAwnwWxExD8-73p5seCWLO1XVzRh5T8JofAw,3870
19
+ wrfrun/extension/goos_sst/utils.py,sha256=bomXbhpOuNOYm2rL1SiOeSxVbSaKWfVxX51KoODgBn0,3469
20
+ wrfrun/extension/goos_sst/res/__init__.py,sha256=-Ey6iFHzQYZNOGhVrSkMjOwiXVgt3P6eaumq7pOmh_E,511
21
+ wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST,sha256=UfbzWKEE2pnQO4Q2mkMmkl7pv_bDSxVGaN2jEYfMVzE,534
22
+ wrfrun/extension/littler/__init__.py,sha256=bLiGIpB_FpTyio44CjIzwwcahyFWxGW-gECfBOIG9Y8,2032
23
+ wrfrun/extension/littler/core.py,sha256=0Si4phAUiCwgjEQnDfWKSOvtnyitWYmrDWkB6_2VjUg,34173
24
+ wrfrun/model/__init__.py,sha256=PYA6ZUwL4u3heRIMX_qkLvAA6jDrY4kugD8rCvnl-2Y,803
25
+ wrfrun/model/base.py,sha256=WnVNu12ICJgThfZR7kK6_XLCQWVYFsHrdyAz8wl_YRc,218
26
+ wrfrun/model/plot.py,sha256=SvD5_2sLaLqYvuvcZVX1x3XTrgMW_bsGP-Npr6RKHVU,10335
27
+ wrfrun/model/utils.py,sha256=5_ffMJCPi_n3-Mgaci9F2eMk2fY7_UrcjmK0JSsZZr0,1206
28
+ wrfrun/model/wrf/__init__.py,sha256=KJij1JMTcj3i5e2LcJJJudA99LrsJIVHeMj9ktT9Y_4,1752
29
+ wrfrun/model/wrf/core.py,sha256=Ykw6ElY3mUelWOThDFT--ChnwY7zgcbyooLuJNhGqV4,35627
30
+ wrfrun/model/wrf/exec_wrap.py,sha256=REOtNLCc6IcM2yaaSXoXGgXFA-xjMHmoTiA9B3ZezEA,4418
31
+ wrfrun/model/wrf/geodata.py,sha256=X9OUOm0__5NI7sl2z1F9_ur5wZ4P0HkpBNcRZQYKof0,9740
32
+ wrfrun/model/wrf/namelist.py,sha256=ksxHlh-LtxDBF73cCe8J0wpyGrSvM1dBgPgwK2XseGo,16918
33
+ wrfrun/model/wrf/scheme.py,sha256=8y85Dbu-GajwjHr3Spw8_tN21xAloD-SnmxJd11nXKE,11254
34
+ wrfrun/model/wrf/utils.py,sha256=DuKghfqBT77p_beDKJ3EyyPMuRmBJCgCElvs3YheWak,3709
35
+ wrfrun/model/wrf/vtable.py,sha256=1el_TctQfPVTYnZn0nJNgfDvVXy6q5ZzVIyUgWRfFUs,2478
36
+ wrfrun/plot/__init__.py,sha256=9Kn0IgkX10sHEqHJwk7mZV-dP14XMNcvXN8znO89FIw,19
37
+ wrfrun/plot/wps.py,sha256=pvkxbh5760AAM4KaPteMzhFniZZFtkYF31xhzSBa7lo,5552
38
+ wrfrun/res/__init__.py,sha256=cIjX9Was6nhms-aBLUY0V1393of-LzoSRcWcD_HGgn0,1437
39
+ wrfrun/res/run.template.sh,sha256=k-r4lOOarscmSdiBXGHPnv3oeiRe-qW-VhOBia27ZGU,101
40
+ wrfrun/res/config/config.template.toml,sha256=DjtFjy2sL_P6w63XfLDkmDWhWKyo6qrlwBy69cnbvXA,1378
41
+ wrfrun/res/config/wrf.template.toml,sha256=qQS3OHAXBMaKWgj2qT7jLeDu6tyngPgin7Q-XcE3ZkQ,3189
42
+ wrfrun/res/extension/plotgrids.ncl,sha256=B0mvH1H1j_w7EEana9HmU1XJZtG0w9IccQ54zXpbQG0,7546
43
+ wrfrun/res/namelist/namelist.input.da_wrfvar.template,sha256=Cwc-XPu_spJeQte4duWrulPBOLRMEBtn0mIn0pgMmKY,4912
44
+ wrfrun/res/namelist/namelist.input.dfi.template,sha256=E7MVbIvMopkAM7xGUC4vniC1WOUVbIbdLfkTKHqzX_o,6591
45
+ wrfrun/res/namelist/namelist.input.real.template,sha256=DDUiArtBFmzBwVjkZW4NOrBR34eIOk1vV0VsyL0stsk,6214
46
+ wrfrun/res/namelist/namelist.input.wrf.template,sha256=myrKi79sQ8ABBsmQJkcgN0WLbWJdtMVPIjuAC1MTMuM,6213
47
+ wrfrun/res/namelist/namelist.wps.template,sha256=HlA7-SHs4C-cKRb3h6D0Kl1Y-5VSJ1Lw9hLiXWGAN0Q,1017
48
+ wrfrun/res/namelist/parame.in.template,sha256=vR8JSix20FAKGqj6jK8QuEAeWkGvg8_iptdVlzjPX6o,259
49
+ wrfrun/res/scheduler/lsf.template,sha256=KorLfqTFTqTTctDE9Edgkixi7JLWrcDNRpZknXuxbEQ,111
50
+ wrfrun/res/scheduler/pbs.template,sha256=kP4pGMAq2uz0OZUAWii7dO4ECLC924c8SnciFeBL5QY,155
51
+ wrfrun/res/scheduler/slurm.template,sha256=sQNjkKzOftipDD4kYmzhZkh8fg0M9uaQsdLjDakCVwA,336
52
+ wrfrun/scheduler/__init__.py,sha256=pOqnCAl2-_yC7zPS2VQL5RMltQN4zc0koYS_MESKtHo,1130
53
+ wrfrun/scheduler/env.py,sha256=N_K5yZFRXMEXvW3yjSideEDPWZzoWpbRhFS9LJoZ3R8,1262
54
+ wrfrun/scheduler/lsf.py,sha256=E_sKUk4_RZMBSkHctzDi2sEAy8UrteZvgpbuU2zeSvo,1158
55
+ wrfrun/scheduler/pbs.py,sha256=fqGqoIWG4lh2bT_NqxPxL3XIdPo8keWG2MFqZmOMKpI,1174
56
+ wrfrun/scheduler/script.py,sha256=si2pzrKCOutICcke4t1c5kmCnVlTS9PZJF5MJTp3YTk,2403
57
+ wrfrun/scheduler/slurm.py,sha256=Y3a4MAt5omDgVUtONaL2ajV609HbOZl2opjIGkHUa7g,1196
58
+ wrfrun/scheduler/utils.py,sha256=5BGPEB-oMn4ifo3XZOkDOwAvjWXi69UHLR5HMabwUAM,206
59
+ wrfrun/workspace/__init__.py,sha256=e7ijFWaYRMmBbso0pXnsAc0oUnkQ3t3UguhY3a0U6Qk,1456
60
+ wrfrun/workspace/core.py,sha256=wj9f8XzafazpxXuO_wtConOEhkHwJLyPTwhubXrn20s,2617
61
+ wrfrun/workspace/wrf.py,sha256=wp5pQgKB9B-7JGc2psRIyj_pI7iG344jphBBB0b6PsY,4098
62
+ wrfrun-0.1.9.dist-info/RECORD,,
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ wrfrun = wrfrun.cli:main_entry
3
+