wrfrun 0.1.9__py3-none-any.whl → 0.3.0__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 (66) hide show
  1. wrfrun/__init__.py +8 -3
  2. wrfrun/cli.py +74 -31
  3. wrfrun/core/__init__.py +27 -10
  4. wrfrun/core/_config.py +308 -0
  5. wrfrun/core/_constant.py +236 -0
  6. wrfrun/core/_exec_db.py +105 -0
  7. wrfrun/core/_namelist.py +287 -0
  8. wrfrun/core/_record.py +178 -0
  9. wrfrun/core/_resource.py +172 -0
  10. wrfrun/core/base.py +136 -380
  11. wrfrun/core/core.py +196 -0
  12. wrfrun/core/error.py +35 -2
  13. wrfrun/core/replay.py +10 -96
  14. wrfrun/core/server.py +74 -32
  15. wrfrun/core/type.py +171 -0
  16. wrfrun/data.py +312 -149
  17. wrfrun/extension/goos_sst/__init__.py +2 -2
  18. wrfrun/extension/goos_sst/core.py +9 -14
  19. wrfrun/extension/goos_sst/res/__init__.py +0 -1
  20. wrfrun/extension/goos_sst/utils.py +50 -44
  21. wrfrun/extension/littler/core.py +105 -88
  22. wrfrun/extension/utils.py +5 -3
  23. wrfrun/log.py +117 -0
  24. wrfrun/model/__init__.py +11 -7
  25. wrfrun/model/constants.py +52 -0
  26. wrfrun/model/palm/__init__.py +30 -0
  27. wrfrun/model/palm/core.py +145 -0
  28. wrfrun/model/palm/namelist.py +33 -0
  29. wrfrun/model/plot.py +99 -114
  30. wrfrun/model/type.py +116 -0
  31. wrfrun/model/utils.py +9 -19
  32. wrfrun/model/wrf/__init__.py +4 -9
  33. wrfrun/model/wrf/core.py +262 -165
  34. wrfrun/model/wrf/exec_wrap.py +13 -12
  35. wrfrun/model/wrf/geodata.py +116 -99
  36. wrfrun/model/wrf/log.py +103 -0
  37. wrfrun/model/wrf/namelist.py +92 -76
  38. wrfrun/model/wrf/plot.py +102 -0
  39. wrfrun/model/wrf/scheme.py +108 -52
  40. wrfrun/model/wrf/utils.py +39 -24
  41. wrfrun/model/wrf/vtable.py +42 -7
  42. wrfrun/plot/__init__.py +20 -0
  43. wrfrun/plot/wps.py +90 -73
  44. wrfrun/res/__init__.py +115 -5
  45. wrfrun/res/config/config.template.toml +15 -0
  46. wrfrun/res/config/palm.template.toml +23 -0
  47. wrfrun/run.py +121 -77
  48. wrfrun/scheduler/__init__.py +1 -0
  49. wrfrun/scheduler/lsf.py +4 -1
  50. wrfrun/scheduler/pbs.py +4 -1
  51. wrfrun/scheduler/script.py +19 -5
  52. wrfrun/scheduler/slurm.py +4 -1
  53. wrfrun/scheduler/utils.py +14 -2
  54. wrfrun/utils.py +88 -199
  55. wrfrun/workspace/__init__.py +8 -5
  56. wrfrun/workspace/core.py +21 -11
  57. wrfrun/workspace/palm.py +137 -0
  58. wrfrun/workspace/wrf.py +59 -14
  59. wrfrun-0.3.0.dist-info/METADATA +240 -0
  60. wrfrun-0.3.0.dist-info/RECORD +78 -0
  61. wrfrun/core/config.py +0 -767
  62. wrfrun/model/base.py +0 -14
  63. wrfrun-0.1.9.dist-info/METADATA +0 -68
  64. wrfrun-0.1.9.dist-info/RECORD +0 -62
  65. {wrfrun-0.1.9.dist-info → wrfrun-0.3.0.dist-info}/WHEEL +0 -0
  66. {wrfrun-0.1.9.dist-info → wrfrun-0.3.0.dist-info}/entry_points.txt +0 -0
wrfrun/__init__.py CHANGED
@@ -1,3 +1,8 @@
1
- from .core import *
2
- from .run import *
3
- from .res import *
1
+ """
2
+ wrfrun
3
+ ######
4
+ """
5
+
6
+ from . import core, data, extension, model, plot, res, run, scheduler, utils, workspace
7
+
8
+ __all__ = ["core", "data", "extension", "model", "plot", "res", "run", "scheduler", "utils", "workspace"]
wrfrun/cli.py CHANGED
@@ -1,20 +1,42 @@
1
+ """
2
+ wrfrun.cli
3
+ ##########
4
+
5
+ .. autosummary::
6
+ :toctree: generated/
7
+
8
+ main_entry
9
+
10
+ ``wrfrun`` command line interface (CLI).
11
+
12
+ **This is an experimental tool, NOT BEING STABLE YET.**
13
+
14
+ After installing ``wrfrun``, you can use command ``wrfrun`` to create a simulation project.
15
+ Get more information by running ``wrfrun --help``.
16
+ """
17
+
1
18
  import argparse
2
19
  import sys
3
- from os import makedirs
20
+ from os import listdir, makedirs
4
21
  from os.path import abspath, dirname, exists
5
22
  from shutil import copyfile
6
23
 
7
24
  import tomli
8
25
  import tomli_w
9
26
 
10
- from .core import WRFRUNConfig
11
- from .res import CONFIG_MAIN_TOML_TEMPLATE, CONFIG_WRF_TOML_TEMPLATE
12
- from .utils import logger
27
+ from .core import WRFRunConfig
28
+ from .log import logger
29
+ from .res import CONFIG_MAIN_TOML_TEMPLATE, CONFIG_PALM_TOML_TEMPLATE, CONFIG_WRF_TOML_TEMPLATE, _register_res_uri
13
30
 
14
31
  MODEL_MAP = {
15
- "wrf": CONFIG_WRF_TOML_TEMPLATE
32
+ "wrf": CONFIG_WRF_TOML_TEMPLATE,
33
+ "palm": CONFIG_PALM_TOML_TEMPLATE,
16
34
  }
17
35
 
36
+ # need some mannual calls to make cli work without a config file.
37
+ wrfrun_config = WRFRunConfig("./.wrfrun")
38
+ _register_res_uri(wrfrun_config)
39
+
18
40
 
19
41
  def _entry_init(args: argparse.Namespace):
20
42
  """
@@ -23,27 +45,45 @@ def _entry_init(args: argparse.Namespace):
23
45
  :param args: Arguments namespace.
24
46
  :type args: argparse.Namespace
25
47
  """
26
- args = vars(args)
48
+ configs = vars(args)
49
+
50
+ project_name = configs["name"]
51
+ models = configs["models"]
27
52
 
28
- project_name = args["name"]
29
- models = args["models"]
53
+ if project_name is None:
54
+ project_name = "."
30
55
 
31
56
  if exists(project_name):
32
- logger.error(f"{project_name} already exists.")
33
- exit(1)
57
+ # we need to check if this directory isn't empty.
58
+ files = listdir()
59
+ # exclude:
60
+ exclude_target = [".venv", ".git", ".gitignore", ".gitattribute", "pyproject.toml", "uv.lock"]
61
+ files = [x for x in files if x not in exclude_target]
62
+
63
+ if len(files) != 0:
64
+ logger.error(f"{project_name} isn't empty, choose an empty directory, or backup and delete your files first.")
65
+ exit(1)
34
66
 
35
67
  makedirs(f"{project_name}/configs")
36
68
  makedirs(f"{project_name}/data")
69
+ namelist_path = f"{project_name}/namelists"
70
+ makedirs(namelist_path)
37
71
 
38
- copyfile(WRFRUNConfig.parse_resource_uri(CONFIG_MAIN_TOML_TEMPLATE), f"{project_name}/config.toml")
72
+ copyfile(wrfrun_config.parse_resource_uri(CONFIG_MAIN_TOML_TEMPLATE), f"{project_name}/config.toml")
39
73
 
40
74
  if models is not None:
41
75
  for _model in models:
42
- src_path = WRFRUNConfig.parse_resource_uri(MODEL_MAP[_model])
76
+ src_path = wrfrun_config.parse_resource_uri(MODEL_MAP[_model])
43
77
  copyfile(src_path, f"{project_name}/configs/{_model}.toml")
78
+ makedirs(f"{namelist_path}/{_model}")
44
79
 
45
- logger.info(f"Created project {project_name}.")
46
- logger.info(f"Use command `wrfrun add MODEL_NAME` to add a new model to project.")
80
+ logger.info(f"Created project {project_name}")
81
+ logger.info(f"All your configs should be placed in {project_name}/configs.")
82
+ logger.info(f"All your data should be placed in {project_name}/data.")
83
+ logger.info(f"All your namelist files should be placed in {namelist_path}")
84
+ logger.info(f"Make sure to set `use = True` to enable models in {project_name}/config.toml .")
85
+ logger.info("It is recommanded to use git to track your wrfrun and model configs.")
86
+ logger.info("Use command `wrfrun add MODEL_NAME` to add a new model to project.")
47
87
 
48
88
 
49
89
  def _entry_model(args: argparse.Namespace):
@@ -53,20 +93,16 @@ def _entry_model(args: argparse.Namespace):
53
93
  :param args: Arguments namespace.
54
94
  :type args: argparse.Namespace
55
95
  """
56
- args = vars(args)
57
- new_models = args["add"]
58
- config_path = args["config"]
96
+ configs = vars(args)
97
+ new_models = configs["add"]
98
+ config_path = configs["config"]
59
99
 
60
100
  if not exists(config_path):
61
101
  logger.error(f"Can't find '{config_path}', initialize this project first.")
62
102
  exit(1)
63
103
 
64
- model_config_map = {
65
- "wrf": CONFIG_WRF_TOML_TEMPLATE
66
- }
67
-
68
104
  for _new_model in new_models:
69
- if _new_model not in model_config_map:
105
+ if _new_model not in MODEL_MAP:
70
106
  logger.error(f"Unknow model type: '{_new_model}'")
71
107
  exit(1)
72
108
 
@@ -81,21 +117,27 @@ def _entry_model(args: argparse.Namespace):
81
117
  for _new_model in new_models:
82
118
  if _new_model not in main_config["model"]:
83
119
  main_config["model"][_new_model] = {
84
- "note": "Config of this model is generated by wrfrun cli command. DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools.",
120
+ "note": (
121
+ "Config of this model is generated by wrfrun cli command. "
122
+ "DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools."
123
+ ),
85
124
  "use": True,
86
- "include": f"./configs/{_new_model}.toml"
125
+ "include": f"./configs/{_new_model}.toml",
87
126
  }
88
127
 
89
128
  else:
90
129
  if not ("use" in main_config["model"] and main_config["model"]["use"]):
91
130
  main_config["model"][_new_model] = {
92
- "note": "Config of this model is generated by wrfrun cli command. DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools.",
131
+ "note": (
132
+ "Config of this model is generated by wrfrun cli command. "
133
+ "DO NOT ADD CUSTOM CONFIG IN THIS SECTION because they may be overwrite by wrfrun cli tools."
134
+ ),
93
135
  "use": True,
94
- "include": f"./configs/{_new_model}.toml"
136
+ "include": f"./configs/{_new_model}.toml",
95
137
  }
96
138
 
97
139
  for _new_model in new_models:
98
- copyfile(WRFRUNConfig.parse_resource_uri(model_config_map[_new_model]), f"{config_dir_path}/{_new_model}.toml")
140
+ copyfile(wrfrun_config.parse_resource_uri(MODEL_MAP[_new_model]), f"{config_dir_path}/{_new_model}.toml")
99
141
 
100
142
  with open(config_path, "wb") as f:
101
143
  tomli_w.dump(main_config, f)
@@ -107,18 +149,19 @@ def main_entry():
107
149
  """
108
150
  CLI entry point.
109
151
  """
110
-
111
152
  args_parser = argparse.ArgumentParser()
112
153
  subparsers = args_parser.add_subparsers(title="Subcommands", description="Valid Subcommands", help="Subcommands")
113
154
 
114
155
  init_parser = subparsers.add_parser("init", help="Initialize a wrfrun project.", add_help=True)
115
- init_parser.add_argument("-n", "--name", type=str, required=True, help="Name of the wrfrun project.")
116
- init_parser.add_argument("--models", nargs="*", type=str, help="List of models to use.", choices=["wrf"])
156
+ init_parser.add_argument("-n", "--name", type=str, help="Name of the wrfrun project.")
157
+ init_parser.add_argument("--models", nargs="*", type=str, help="List of models to use.", choices=["wrf", "palm"])
117
158
  init_parser.set_defaults(func=_entry_init)
118
159
 
119
160
  model_parser = subparsers.add_parser("model", help="Manage models used by wrfrun project.", add_help=True)
120
161
  model_parser.add_argument("-c", "--config", type=str, default="config.toml", help="Path of the main config file.")
121
- model_parser.add_argument("-a", "--add", nargs="+", required=True, type=str, help="Add models to the project.")
162
+ model_parser.add_argument(
163
+ "-a", "--add", nargs="+", required=True, type=str, help="Add models to the project.", choices=["wrf", "palm"]
164
+ )
122
165
  model_parser.set_defaults(func=_entry_model)
123
166
 
124
167
  args = args_parser.parse_args(args=None if sys.argv[1:] else ["--help"])
wrfrun/core/__init__.py CHANGED
@@ -12,27 +12,44 @@ The functionalities are split into several submodules, which are listed in the t
12
12
  Submodules
13
13
  **********
14
14
 
15
- ================================ ========================================================
16
- :doc:`base </api/core.base>` Executable base class and related classes.
17
- :doc:`config </api/core.config>` ``wrfrun`` config classes.
18
- :doc:`error </api/core.error>` ``wrfrun`` error classes.
19
- :doc:`replay </api/core.replay>` Functions and classes to record and replay simulations.
20
- :doc:`server </api/core.server>` Functions and classes to start socket server.
21
- ================================ ========================================================
15
+ ====================================== ========================================================
16
+ :doc:`_config </api/core._config>` Definition of ``WRFRunConfig``.
17
+ :doc:`_constant </api/core._constant>` Definition of ``ConstantMixIn``.
18
+ :doc:`_exec_db </api/core._exec_db>` Definition of ``ExecutableDB``.
19
+ :doc:`_namelist </api/core._namelist>` Definition of ``NamelistMixIn``.
20
+ :doc:`_record </api/core._record>` Definition of ``ExecutableRecorder``.
21
+ :doc:`_resource </api/core._resource>` Definition of ``ResourceMixIn``.
22
+ :doc:`base </api/core.base>` Definition of ``Executable`` base class.
23
+ :doc:`core </api/core.core>` Definition of proxy class ``WRFRUNProxy``.
24
+ :doc:`error </api/core.error>` Definition of ``wrfrun`` error exceptions.
25
+ :doc:`replay </api/core.replay>` Functions and classes to replay simulations.
26
+ :doc:`server </api/core.server>` Functions and classes to start socket server.
27
+ :doc:`type </api/core.type>` Definition of various types used in ``wrfrun``.
28
+ ====================================== ========================================================
22
29
 
23
- .. toctree::
30
+ .. toctree::
24
31
  :maxdepth: 1
25
32
  :hidden:
26
33
 
34
+ _config <core._config>
35
+ _constant <core._constant>
36
+ _exec_db <core._exec_db>
37
+ _namelist <core._namelist>
38
+ _record <core._record>
39
+ _resource <core._resource>
27
40
  base <core.base>
28
- config <core.config>
41
+ core <core.core>
29
42
  error <core.error>
30
43
  replay <core.replay>
31
44
  server <core.server>
45
+ type <core.type>
32
46
  """
33
47
 
48
+ from ._config import *
49
+ from ._exec_db import *
34
50
  from .base import *
35
- from .config import *
51
+ from .core import *
36
52
  from .error import *
37
53
  from .replay import *
38
54
  from .server import *
55
+ from .type import *
wrfrun/core/_config.py ADDED
@@ -0,0 +1,308 @@
1
+ """
2
+ wrfrun.core._config
3
+ ###################
4
+
5
+ .. autosummary::
6
+ :toctree: generated/
7
+
8
+ WRFRunConfig
9
+
10
+ WRFRunConfig
11
+ ************
12
+
13
+ This class inherits :class:`ConstantMixIn <wrfrun.core._constant.ConstantMixIn>`,
14
+ :class:`NamelistMixIn <wrfrun.core._namelist.NamelistMixIn>`,
15
+ and :class:`ResourceMixIn <wrfrun.core._resource.ResourceMixIn>`.
16
+
17
+ Besides the methods from its parents, :class:`WRFRunConfig` provides methods to read and access user config files.
18
+ """
19
+
20
+ from copy import deepcopy
21
+ from os import makedirs
22
+ from os.path import abspath, dirname, exists
23
+ from shutil import copyfile
24
+ from typing import Callable, Tuple
25
+
26
+ import tomli
27
+ import tomli_w
28
+
29
+ from ..log import logger
30
+ from ._constant import ConstantMixIn
31
+ from ._namelist import NamelistMixIn
32
+ from ._resource import ResourceMixIn
33
+ from .error import ModelNameError
34
+
35
+
36
+ class WRFRunConfig(ConstantMixIn, NamelistMixIn, ResourceMixIn):
37
+ """
38
+ Comprehensive class to manage wrfrun config, runtime constants, namelists and resource files.
39
+ """
40
+
41
+ def __init__(self, work_dir: str):
42
+ """
43
+
44
+ :param work_dir: ``wrfrun`` work directory path.
45
+ :type work_dir: str
46
+ """
47
+ super().__init__(work_dir=work_dir)
48
+
49
+ self._config = {}
50
+
51
+ self._config_template_file_path = None
52
+
53
+ self._register_wrfrun_uris()
54
+
55
+ def apply_register_func(self, func_list: list[Callable[["WRFRunConfig"], None]]):
56
+ """
57
+ Call register functions provided by other submodules.
58
+
59
+ :param func_list: A list contains register functions.
60
+ :type func_list: list[Callable[["WRFRunConfig"], None]]
61
+ """
62
+ while len(func_list) != 0:
63
+ _func = func_list.pop(0)
64
+ _func(self)
65
+
66
+ @classmethod
67
+ def from_config_file(
68
+ cls, config_file: str, register_funcs: list[Callable[["WRFRunConfig"], None]]
69
+ ) -> "WRFRunConfig":
70
+ """
71
+ Read the config file and create a instance.
72
+
73
+ :param config_file: Config file path.
74
+ :type config_file: str
75
+ :param register_funcs: Register function list.
76
+ :type register_funcs: list[Callable[["WRFRunConfig"], None]]
77
+ :return: New instance
78
+ :rtype: WRFRunConfig
79
+ """
80
+ with open(config_file, "rb") as f:
81
+ config = tomli.load(f)
82
+
83
+ instance = cls(work_dir=config["work_dir"])
84
+ instance.apply_register_func(register_funcs)
85
+ instance.load_wrfrun_config(config_file)
86
+
87
+ return instance
88
+
89
+ def _register_wrfrun_uris(self):
90
+ for key, value in self._get_uri_map().items():
91
+ self.register_resource_uri(key, value)
92
+
93
+ def set_config_template_path(self, file_path: str):
94
+ """
95
+ Set file path of the config template file.
96
+
97
+ ``WRFRunConfig`` needs to know
98
+
99
+ :param file_path: Template file path.
100
+ :type file_path: str
101
+ """
102
+ self._config_template_file_path = file_path
103
+
104
+ def load_wrfrun_config(self, config_path: str):
105
+ """
106
+ Load configs from a config file.
107
+
108
+ If the config path is invalid, ``WRFRunConfig`` will create a new config file at the same place,
109
+ and raise :class:`FileNotFoundError`.
110
+
111
+ :param config_path: TOML config file.
112
+ :type config_path: str
113
+ """
114
+ config_template_path = self.parse_resource_uri(self._config_template_file_path)
115
+
116
+ if not exists(config_path):
117
+ logger.error(f"Config file doesn't exist, copy template config to {config_path}")
118
+ logger.error("Please modify it.")
119
+
120
+ if not exists(dirname(config_path)):
121
+ makedirs(dirname(config_path))
122
+
123
+ copyfile(config_template_path, config_path)
124
+ raise FileNotFoundError(config_path)
125
+
126
+ with open(config_path, "rb") as f:
127
+ self._config = tomli.load(f)
128
+
129
+ config_dir_path = abspath(dirname(config_path))
130
+
131
+ # merge model config.
132
+ keys_list = list(self._config["model"].keys())
133
+ for model_key in keys_list:
134
+ # skip the key that isn't model.
135
+ if model_key == "debug_level":
136
+ continue
137
+
138
+ if "include" not in self._config["model"][model_key]:
139
+ continue
140
+
141
+ # use = True, and have "include" key
142
+ if self._config["model"][model_key]["use"]:
143
+ include_file = self._config["model"][model_key]["include"]
144
+ if include_file[0] != "/":
145
+ include_file = f"{config_dir_path}/{include_file}"
146
+
147
+ with open(include_file, "rb") as f:
148
+ # keep "use" key, as other components may use this key
149
+ _mode_config = tomli.load(f)
150
+ _mode_config.update({"use": True})
151
+ self._config["model"][model_key] = _mode_config
152
+
153
+ else:
154
+ self._config["model"].pop(model_key)
155
+
156
+ # register URI for output directory.
157
+ output_path = abspath(self["output_path"])
158
+ self.unregister_resource_uri(self.WRFRUN_OUTPUT_PATH)
159
+ self.register_resource_uri(self.WRFRUN_OUTPUT_PATH, output_path)
160
+
161
+ # some additional check
162
+ if self._config["input_data_path"] == "":
163
+ logger.warning("It seems you forget to set 'input_data_path', set it to 'data'.")
164
+ self._config["input_data_path"] = "data"
165
+
166
+ def save_wrfrun_config(self, save_path: str):
167
+ """
168
+ Save wrfrun config to a file.
169
+
170
+ :param save_path: Save path of the config.
171
+ :type save_path: str
172
+ """
173
+ save_path = self.parse_resource_uri(save_path)
174
+
175
+ path_dir = dirname(save_path)
176
+ if not exists(path_dir):
177
+ makedirs(path_dir)
178
+
179
+ with open(save_path, "wb") as f:
180
+ tomli_w.dump(self._config, f)
181
+
182
+ def __getitem__(self, item: str):
183
+ """
184
+ You can access wrfrun config like the way to access values in a dictionary.
185
+
186
+ For example:
187
+
188
+ >>> from wrfrun.core import WRFRUN
189
+ >>> model_config = WRFRUN.config["model"] # get all model configs.
190
+
191
+ :param item: Keys.
192
+ :type item: str
193
+ """
194
+ if len(self._config) == 0:
195
+ logger.error("Attempt to read value before load config")
196
+ raise RuntimeError("Attempt to read value before load config")
197
+
198
+ return deepcopy(self._config[item])
199
+
200
+ def __setitem__(self, key: str, value):
201
+ if key == "model":
202
+ logger.error("Use `update_model_config` to change model configurations.")
203
+ raise KeyError("Use `update_model_config` to change model configurations.")
204
+
205
+ if key in self._config:
206
+ self._config[key] = value
207
+
208
+ else:
209
+ logger.error(f"Can't find key '{key}' in your config.")
210
+ raise KeyError(f"Can't find key '{key}' in your config.")
211
+
212
+ def get_input_data_path(self) -> str:
213
+ """
214
+ Get the path of directory in which stores the input data.
215
+
216
+ :return: Directory path.
217
+ :rtype: str
218
+ """
219
+ return deepcopy(self["input_data_path"])
220
+
221
+ def get_model_config(self, model_name: str) -> dict:
222
+ """
223
+ Get the config of a NWP model.
224
+
225
+ An exception :class:`ModelNameError <wrfrun.core.error.ModelNameError>` will be raised
226
+ if the config can't be found.
227
+
228
+ :param model_name: Name of the model. For example, ``wrf``.
229
+ :type model_name: str
230
+ :return: A dictionary.
231
+ :rtype: dict
232
+ """
233
+ if model_name not in self["model"]:
234
+ logger.error(f"Config of model '{model_name}' isn't found in your config file.")
235
+ raise ModelNameError(f"Config of model '{model_name}' isn't found in your config file.")
236
+
237
+ return self["model"][model_name]
238
+
239
+ def update_model_config(self, model_name: str, value: dict):
240
+ """
241
+ Update the config of a NWP model.
242
+
243
+ An exception :class:`ModelNameError <wrfrun.core.error.ModelNameError>` will be raised
244
+ if the config can't be found.
245
+
246
+ :param model_name: Name of the model. For example, ``wrf``.
247
+ :type model_name: str
248
+ :param value: Dictionary contains new values.
249
+ :type value: dict
250
+ """
251
+ if model_name not in self["model"]:
252
+ logger.error(f"Config of model '{model_name}' isn't found in your config file.")
253
+ raise ModelNameError(f"Config of model '{model_name}' isn't found in your config file.")
254
+
255
+ self._config["model"][model_name].update(value)
256
+
257
+ def get_log_path(self) -> str:
258
+ """
259
+ Get the directory path to save logs.
260
+
261
+ :return: A directory path.
262
+ :rtype: str
263
+ """
264
+ return self["log_path"]
265
+
266
+ def get_socket_server_config(self) -> Tuple[str, int]:
267
+ """
268
+ Get settings of the socket server.
269
+
270
+ :return: ("host", port)
271
+ :rtype: tuple
272
+ """
273
+ return self["server_host"], self["server_port"]
274
+
275
+ def get_job_scheduler_config(self) -> dict:
276
+ """
277
+ Get configs of job scheduler.
278
+
279
+ :return: A dict object.
280
+ :rtype: dict
281
+ """
282
+ return deepcopy(self["job_scheduler"])
283
+
284
+ def get_core_num(self) -> int:
285
+ """
286
+ Get the number of CPU cores to be used.
287
+ :return: Core numbers
288
+ :rtype: int
289
+ """
290
+ return self["core_num"]
291
+
292
+ def write_namelist(self, save_path: str, namelist_id: str, overwrite=True):
293
+ """
294
+ Write namelist values of a ``namelist_id`` to a file.
295
+ This method is overwritten to convert URIs in ``save_path`` first.
296
+
297
+ :param save_path: Target file path.
298
+ :type save_path: str
299
+ :param namelist_id: Registered ``namelist_id``.
300
+ :type namelist_id: str
301
+ :param overwrite: If overwrite the existed file.
302
+ :type overwrite: bool
303
+ """
304
+ save_path = self.parse_resource_uri(save_path)
305
+ super().write_namelist(save_path, namelist_id, overwrite)
306
+
307
+
308
+ __all__ = ["WRFRunConfig"]