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.
- wrfrun/cli.py +128 -0
- wrfrun/core/base.py +8 -5
- wrfrun/core/config.py +81 -150
- wrfrun/core/replay.py +1 -1
- wrfrun/core/server.py +81 -78
- wrfrun/extension/goos_sst/__init__.py +5 -5
- wrfrun/extension/goos_sst/core.py +4 -1
- wrfrun/extension/goos_sst/res/Vtable.ERA_GOOS_SST +1 -1
- wrfrun/extension/goos_sst/res/__init__.py +17 -0
- wrfrun/extension/goos_sst/utils.py +21 -5
- wrfrun/extension/littler/__init__.py +57 -1
- wrfrun/extension/littler/{utils.py → core.py} +326 -40
- wrfrun/extension/utils.py +22 -21
- wrfrun/model/__init__.py +24 -1
- wrfrun/model/plot.py +253 -35
- wrfrun/model/utils.py +17 -8
- wrfrun/model/wrf/__init__.py +41 -0
- wrfrun/model/wrf/core.py +215 -99
- wrfrun/model/wrf/exec_wrap.py +49 -35
- wrfrun/model/wrf/namelist.py +79 -4
- wrfrun/model/wrf/{_metgrid.py → utils.py} +36 -2
- wrfrun/model/wrf/vtable.py +2 -1
- wrfrun/res/__init__.py +8 -5
- wrfrun/res/config/config.template.toml +50 -0
- wrfrun/res/{config.toml.template → config/wrf.template.toml} +7 -46
- wrfrun/res/run.template.sh +10 -0
- wrfrun/res/scheduler/lsf.template +5 -0
- wrfrun/res/{job_scheduler → scheduler}/pbs.template +1 -1
- wrfrun/res/{job_scheduler → scheduler}/slurm.template +2 -1
- wrfrun/run.py +19 -23
- wrfrun/scheduler/__init__.py +35 -0
- wrfrun/scheduler/env.py +44 -0
- wrfrun/scheduler/lsf.py +47 -0
- wrfrun/scheduler/pbs.py +48 -0
- wrfrun/scheduler/script.py +70 -0
- wrfrun/scheduler/slurm.py +48 -0
- wrfrun/scheduler/utils.py +14 -0
- wrfrun/utils.py +8 -3
- wrfrun/workspace/__init__.py +38 -0
- wrfrun/workspace/core.py +92 -0
- wrfrun/workspace/wrf.py +121 -0
- {wrfrun-0.1.8.dist-info → wrfrun-0.1.9.dist-info}/METADATA +3 -2
- wrfrun-0.1.9.dist-info/RECORD +62 -0
- wrfrun-0.1.9.dist-info/entry_points.txt +3 -0
- wrfrun/model/wrf/_ndown.py +0 -39
- wrfrun/pbs.py +0 -86
- wrfrun/res/run.sh.template +0 -16
- wrfrun/workspace.py +0 -88
- wrfrun-0.1.8.dist-info/RECORD +0 -51
- {wrfrun-0.1.8.dist-info → wrfrun-0.1.9.dist-info}/WHEEL +0 -0
wrfrun/scheduler/env.py
ADDED
|
@@ -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"]
|
wrfrun/scheduler/lsf.py
ADDED
|
@@ -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"]
|
wrfrun/scheduler/pbs.py
ADDED
|
@@ -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"]
|
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
|
-
|
|
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 *
|
wrfrun/workspace/core.py
ADDED
|
@@ -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"]
|
wrfrun/workspace/wrf.py
ADDED
|
@@ -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.
|
|
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
|
|
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,,
|