wrfrun 0.1.7__py3-none-any.whl → 0.1.8__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/core/config.py CHANGED
@@ -1,5 +1,23 @@
1
1
  """
2
- This file contains functions to read the config file of wrfrun
2
+ wrfrun.core.config
3
+ ##################
4
+
5
+ All classes in this module is used to manage various configurations of ``wrfrun`` and NWP model.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ WRFRunConfig
11
+ _WRFRunConstants
12
+ _WRFRunNamelist
13
+ _WRFRunResources
14
+
15
+ WRFRunConfig
16
+ ************
17
+
18
+ A comprehensive class which provides interfaces to access various configurations and resources.
19
+ It inherits from three classes: :class:`_WRFRunResources`, :class:`_WRFRunConstants` and :class:`_WRFRunNamelist`.
20
+ Users can use the global variable ``WRFRUNConfig``, which is the instance of this class being created when users import ``wrfrun``.
3
21
  """
4
22
 
5
23
  from copy import deepcopy
@@ -12,22 +30,39 @@ import f90nml
12
30
  import tomli
13
31
  import tomli_w
14
32
 
15
- from .error import ResourceURIError, WRFRunContextError, ModelNameError
33
+ from .error import ResourceURIError, WRFRunContextError, ModelNameError, NamelistIDError, NamelistError
16
34
  from ..utils import logger
17
35
 
18
36
 
19
37
  class _WRFRunResources:
20
38
  """
21
- Manage resource files used by wrfrun components.
22
- These resources include various configuration files from NWP as well as those provided by wrfrun itself.
23
- Since their actual file paths may vary depending on the wrfrun installation environment, wrfrun maps them using URIs to ensure consistent access regardless of the environment.
39
+ Manage resource files used by wrfrun components
24
40
  """
41
+
25
42
  def __init__(self):
43
+ """
44
+ This class manage resource files used by wrfrun components.
45
+
46
+ These resources include various configuration files from NWP as well as those provided by ``wrfrun`` itself.
47
+ Since their actual file paths may vary depending on the installation environment,
48
+ ``wrfrun`` maps them using URIs to ensure consistent access regardless of the environment.
49
+ The URI always starts with the prefix string ``:WRFRUN_`` and ends with ``:``.
50
+
51
+ To register custom URIs, user can use :meth:`_WRFRunResources.register_resource_uri`,
52
+ which will check if the provided URI is valid.
53
+
54
+ To convert any possible URIs in a string, user can use :meth:`_WRFRunResources.parse_resource_uri`
55
+
56
+ For more information about how to use resource files, please see :class:`WRFRunConfig`,
57
+ which inherits this class.
58
+ """
26
59
  self._resource_namespace_db = {}
27
60
 
28
61
  def check_resource_uri(self, unique_uri: str) -> bool:
29
62
  """
30
- Check if the uri has been registered.
63
+ Check if the URI has been registered.
64
+
65
+ ``wrfrun`` uses unique URIs to represent resource files. If you want to register a custom URI, you need to check if it's available.
31
66
 
32
67
  :param unique_uri: Unique URI represents the resource.
33
68
  :type unique_uri: str
@@ -42,16 +77,13 @@ class _WRFRunResources:
42
77
 
43
78
  def register_resource_uri(self, unique_uri: str, res_space_path: str):
44
79
  """
45
- This function should only be used by wrfrun functions.
46
-
47
- Register a unique resource file namespace.
80
+ Register a resource path with a URI. The URI should start with ``:WRFRUN_`` ,end with ``:`` and hasn't been registered yet,
81
+ otherwise an exception :class:`ResourceURIError` will be raised.
48
82
 
49
83
  :param unique_uri: Unique URI represents the resource. It must start with ``:WRFRUN_`` and end with ``:``. For example, ``":WRFRUN_WORK_PATH:"``.
50
84
  :type unique_uri: str
51
85
  :param res_space_path: REAL absolute path of your resource path. For example, "$HOME/.config/wrfrun/res".
52
86
  :type res_space_path: str
53
- :return:
54
- :rtype:
55
87
  """
56
88
  if not (unique_uri.startswith(":WRFRUN_") and unique_uri.endswith(":")):
57
89
  logger.error(f"Can't register resource URI: '{unique_uri}'. It should start with ':WRFRUN_' and end with ':'.")
@@ -61,36 +93,41 @@ class _WRFRunResources:
61
93
  logger.error(f"Resource URI '{unique_uri}' exists.")
62
94
  raise ResourceURIError(f"Resource URI '{unique_uri}' exists.")
63
95
 
64
-
65
-
66
96
  logger.debug(f"Register URI '{unique_uri}' to '{res_space_path}'")
67
97
  self._resource_namespace_db[unique_uri] = res_space_path
68
98
 
69
- def parse_resource_uri(self, file_path: str) -> str:
99
+ def parse_resource_uri(self, resource_path: str) -> str:
70
100
  """
71
- Return a real file path by parsing the URI string in it.
72
-
101
+ Return the converted string by parsing the URI string in it.
73
102
  Normal path will be returned with no change.
74
103
 
75
- :param file_path: File path string which may contain URI string.
76
- :type file_path: str
77
- :return: Real file path.
104
+ If the URI hasn't been registered, an exception :class:`ResourceURIError` will be raised.
105
+
106
+ :param resource_path: Resource path string which may contain URI string.
107
+ :type resource_path: str
108
+ :return: Real resource path.
78
109
  :rtype: str
110
+
111
+ For example, you can get the real path of ``wrfrun`` workspace with this method:
112
+
113
+ >>> workspace_path = f"{WRFRUNConfig.WRFRUN_WORKSPACE_PATH}/WPS" # ":WRFRUN_WORKSPACE_PATH:/WPS"
114
+ >>> real_path = WRFRUNConfig.parse_resource_uri(workspace_path) # should be a valid path like: "/home/syize/.config/wrfrun/workspace/WPS"
115
+
79
116
  """
80
- if not file_path.startswith(":WRFRUN_"):
81
- return file_path
117
+ if not resource_path.startswith(":WRFRUN_"):
118
+ return resource_path
82
119
 
83
- res_namespace_string = file_path.split(":")[1]
120
+ res_namespace_string = resource_path.split(":")[1]
84
121
  res_namespace_string = f":{res_namespace_string}:"
85
122
 
86
123
  if res_namespace_string in self._resource_namespace_db:
87
- file_path = file_path.replace(res_namespace_string, self._resource_namespace_db[res_namespace_string])
124
+ resource_path = resource_path.replace(res_namespace_string, self._resource_namespace_db[res_namespace_string])
88
125
 
89
- if not file_path.startswith(":WRFRUN_"):
90
- return file_path
126
+ if not resource_path.startswith(":WRFRUN_"):
127
+ return resource_path
91
128
 
92
129
  else:
93
- return self.parse_resource_uri(file_path)
130
+ return self.parse_resource_uri(resource_path)
94
131
 
95
132
  else:
96
133
  logger.error(f"Unknown resource URI: '{res_namespace_string}'")
@@ -99,11 +136,16 @@ class _WRFRunResources:
99
136
 
100
137
  class _WRFRunConstants:
101
138
  """
102
- Define all variables that will be used by other wrfrun components.
103
- These variables are related to the wrfrun installation environment and configuration files.
104
- They are defined either directly or mapped using URIs to ensure consistent access across all components.
139
+ Define all variables that will be used by other components.
105
140
  """
141
+
106
142
  def __init__(self):
143
+ """
144
+ Define all variables that will be used by other components.
145
+
146
+ These variables are related to ``wrfrun`` installation environments, configuration files and more.
147
+ They are defined either directly or mapped using URIs to ensure consistent access across all components.
148
+ """
107
149
  # the path we may need to store temp files,
108
150
  # don't worry, it will be deleted once the system reboots
109
151
  self._WRFRUN_TEMP_PATH = "/tmp/wrfrun"
@@ -152,11 +194,11 @@ class _WRFRunConstants:
152
194
 
153
195
  def _get_uri_map(self) -> dict[str, str]:
154
196
  """
155
- Return uri and its value.
156
- We will use this to register uri when initialize config.
197
+ Return URIs and their values.
198
+ ``wrfrun`` will use this to register uri when initialize config.
157
199
 
158
- :return:
159
- :rtype:
200
+ :return: A dict in which URIs are keys and their values are dictionary values.
201
+ :rtype: dict
160
202
  """
161
203
  return {
162
204
  self.WRFRUN_TEMP_PATH: self._WRFRUN_TEMP_PATH,
@@ -170,14 +212,20 @@ class _WRFRunConstants:
170
212
 
171
213
  @property
172
214
  def WRFRUN_REPLAY_WORK_PATH(self) -> str:
215
+ """
216
+ Path (URI) to store related files of ``wrfrun``'s replay functionality.
217
+
218
+ :return: URI.
219
+ :rtype: str
220
+ """
173
221
  return ":WRFRUN_REPLAY_WORK_PATH:"
174
222
 
175
223
  @property
176
224
  def WRFRUN_TEMP_PATH(self) -> str:
177
225
  """
178
- Path of the directory storing temporary files.
226
+ Path to store ``wrfrun`` temporary files.
179
227
 
180
- :return: Path of the directory storing temporary files.
228
+ :return: URI
181
229
  :rtype: str
182
230
  """
183
231
  return ":WRFRUN_TEMP_PATH:"
@@ -185,9 +233,9 @@ class _WRFRunConstants:
185
233
  @property
186
234
  def WRFRUN_HOME_PATH(self) -> str:
187
235
  """
188
- Path of the directory storing wrfrun config files.
236
+ Root path of all others directories. .
189
237
 
190
- :return: Path of the directory storing temporary files.
238
+ :return: URI
191
239
  :rtype: str
192
240
  """
193
241
  return ":WRFRUN_HOME_PATH:"
@@ -195,19 +243,19 @@ class _WRFRunConstants:
195
243
  @property
196
244
  def WRFRUN_WORKSPACE_PATH(self) -> str:
197
245
  """
198
- Path of the wrfrun workspace.
246
+ Path of the workspace, in which ``wrfrun`` runs NWP models.
199
247
 
200
- :return: Path of the wrfrun workspace.
248
+ :return: URI
201
249
  :rtype: str
202
250
  """
203
- return ":WRFRUN_WORK_PATH:"
251
+ return ":WRFRUN_WORKSPACE_PATH:"
204
252
 
205
253
  @property
206
254
  def WPS_WORK_PATH(self) -> str:
207
255
  """
208
- Path of the directory to run WPS.
256
+ Workspace in which ``wrfrun`` runs WPS.
209
257
 
210
- :return: Path of the directory to run WPS.
258
+ :return: URI
211
259
  :rtype: str
212
260
  """
213
261
  return ":WRFRUN_WPS_WORK_PATH:"
@@ -215,9 +263,9 @@ class _WRFRunConstants:
215
263
  @property
216
264
  def WRF_WORK_PATH(self) -> str:
217
265
  """
218
- Path of the directory to run WRF.
266
+ Workspace in which ``wrfrun`` runs WRF.
219
267
 
220
- :return: Path of the directory to run WRF.
268
+ :return: URI
221
269
  :rtype: str
222
270
  """
223
271
  return ":WRFRUN_WRF_WORK_PATH:"
@@ -225,9 +273,9 @@ class _WRFRunConstants:
225
273
  @property
226
274
  def WRFDA_WORK_PATH(self) -> str:
227
275
  """
228
- Path of the directory to run WRFDA.
276
+ Workspace in which ``wrfrun`` runs WRFDA.
229
277
 
230
- :return: Path of the directory to run WRFDA.
278
+ :return: URI
231
279
  :rtype: str
232
280
  """
233
281
  return ":WRFRUN_WRFDA_WORK_PATH:"
@@ -235,28 +283,49 @@ class _WRFRunConstants:
235
283
  @property
236
284
  def WRFRUN_WORK_STATUS(self) -> str:
237
285
  """
238
- wrfrun work status.
286
+ ``wrfrun`` work status.
287
+
288
+ This attribute can be changed by ``Executable`` to reflect the current work progress of ``wrfrun``.
289
+ The returned string is the name of ``Executable``.
239
290
 
240
- :return: wrfrun work status.
291
+ :return: A string reflect the current work progress.
241
292
  :rtype: str
242
293
  """
243
294
  return self._WORK_STATUS
244
295
 
245
296
  @WRFRUN_WORK_STATUS.setter
246
297
  def WRFRUN_WORK_STATUS(self, value: str):
298
+ """
299
+ Set ``wrfrun`` work status.
300
+
301
+ ``wrfrun`` recommends ``Executable`` set the status string with their name,
302
+ so to avoid the possible conflicts with other ``Executable`` and the user can easily understand the current work progress.
303
+
304
+ :param value: A string represents the work status.
305
+ :type value: str
306
+ """
247
307
  if not isinstance(value, str):
248
308
  value = str(value)
249
309
  self._WORK_STATUS = value
250
310
 
251
311
  @property
252
- def UNGRIB_OUT_DIR(self):
312
+ def UNGRIB_OUT_DIR(self) -> str:
253
313
  """
254
- Output directory path of ungrib.
314
+ Output directory path of ``ungrib.exe``.
315
+
316
+ :return: URI
317
+ :rtype: str
255
318
  """
256
319
  return self._UNGRIB_OUT_DIR
257
320
 
258
321
  @UNGRIB_OUT_DIR.setter
259
322
  def UNGRIB_OUT_DIR(self, value: str):
323
+ """
324
+ Set the output directory path of ``ungrib.exe``.
325
+
326
+ :param value: A real path or a URI represents the directory path of ``ungrib.exe``'s output.
327
+ :type value: str
328
+ """
260
329
  if not isinstance(value, str):
261
330
  value = str(value)
262
331
  self._UNGRIB_OUT_DIR = value
@@ -264,22 +333,28 @@ class _WRFRunConstants:
264
333
  @property
265
334
  def WRFRUN_OUTPUT_PATH(self) -> str:
266
335
  """
267
- A marco string represents the save path of output files in wrfrun config.
336
+ The root path to store all outputs of the ``wrfrun`` and NWP model.
337
+
338
+ :return: URI
339
+ :rtype: str
268
340
  """
269
341
  return self._WRFRUN_OUTPUT_PATH
270
342
 
271
343
  @property
272
344
  def WRFRUN_RESOURCE_PATH(self) -> str:
273
345
  """
274
- Return the preserved string used by wrfrun resource files.
346
+ The root path of all ``wrfrun`` resource files.
347
+
348
+ :return: URI
349
+ :rtype: str
275
350
  """
276
351
  return self._WRFRUN_RESOURCE_PATH
277
352
 
278
353
  def check_wrfrun_context(self, error=False) -> bool:
279
354
  """
280
- Check if we're in WRFRun context or not.
355
+ Check if in WRFRun context or not.
281
356
 
282
- :param error: Raise an error if ``error==True`` when we are not in WRFRun context.
357
+ :param error: An exception :class:`WRFRunContextError` will be raised if ``error==True`` when we are not in WRFRun context.
283
358
  :type error: bool
284
359
  :return: True or False.
285
360
  :rtype: bool
@@ -298,7 +373,7 @@ class _WRFRunConstants:
298
373
  """
299
374
  Change ``WRFRun`` context status to True or False.
300
375
 
301
- :param status: ``WRFRun`` context status.
376
+ :param status: ``True`` or ``False``.
302
377
  :type status: bool
303
378
  """
304
379
  self._WRFRUN_CONTEXT_STATUS = status
@@ -306,9 +381,19 @@ class _WRFRunConstants:
306
381
 
307
382
  class _WRFRunNamelist:
308
383
  """
309
- A class to manage namelist config.
384
+ Manage all namelist configurations of NWP models.
310
385
  """
386
+
311
387
  def __init__(self):
388
+ """
389
+ Manage all namelist configurations of NWP models.
390
+
391
+ This class provides interfaces to read and write various namelist values of NWP model.
392
+ Namelist values are stored in a dictionary with a unique ``namelist_id`` to avoid being messed up with other namelist.
393
+
394
+ If you want to use a new ``namelist_id`` other than the defaults to store namelist,
395
+ you can register a new ``namelist_id`` with :meth:`_WRFRunNamelist.register_custom_namelist_id`.
396
+ """
312
397
  self._wps_namelist = {}
313
398
  self._wrf_namelist = {}
314
399
  self._wrfda_namelist = {}
@@ -317,7 +402,7 @@ class _WRFRunNamelist:
317
402
 
318
403
  def register_custom_namelist_id(self, namelist_id: str) -> bool:
319
404
  """
320
- Register a namelist with a unique id so you can read, update and write it later.
405
+ Register a unique ``namelist_id`` so you can read, update and write namelist with it later.
321
406
 
322
407
  :param namelist_id: A unique namelist id.
323
408
  :type namelist_id: str
@@ -333,13 +418,11 @@ class _WRFRunNamelist:
333
418
 
334
419
  def unregister_custom_namelist_id(self, namelist_id: str):
335
420
  """
336
- Unregister a specified namelist id.
337
- If unregister successfully, all data about this namelist kind will be lost.
421
+ Unregister a ``namelist_id``.
422
+ If unregister successfully, all values of this namelist will be deleted.
338
423
 
339
424
  :param namelist_id: A unique namelist id.
340
425
  :type namelist_id: str
341
- :return:
342
- :rtype:
343
426
  """
344
427
  if namelist_id not in self._namelist_id_list:
345
428
  return
@@ -349,11 +432,11 @@ class _WRFRunNamelist:
349
432
 
350
433
  def check_namelist_id(self, namelist_id: str) -> bool:
351
434
  """
352
- Check if a namelist id is registered.
435
+ Check if a ``namelist_id`` is registered.
353
436
 
354
- :param namelist_id: Unique namelist ID.
355
- :type namelist_id: Unique namelist ID.
356
- :return: True if the ID is registered, else False.
437
+ :param namelist_id: A ``namelist_id``.
438
+ :type namelist_id: str
439
+ :return: True if the ``namelist_id`` is registered, else False.
357
440
  :rtype: bool
358
441
  """
359
442
  if namelist_id in self._namelist_id_list:
@@ -363,11 +446,14 @@ class _WRFRunNamelist:
363
446
 
364
447
  def read_namelist(self, file_path: str, namelist_id: str):
365
448
  """
366
- Read namelist.
449
+ Read namelist values from a file and store them with the ``namelist_id``.
450
+
451
+ If ``wrfrun`` can't read the file, ``FileNotFoundError`` will be raised.
452
+ If ``namelist_id`` isn't registered, :class:`NamelistIDError` will be raised.
367
453
 
368
454
  :param file_path: Namelist file path.
369
455
  :type file_path: str
370
- :param namelist_id: ``"wps"``, ``"wrf"``, ``"wrfda"``, or any other id you have registered.
456
+ :param namelist_id: Registered ``namelist_id``.
371
457
  :type namelist_id: str
372
458
  """
373
459
  # check the file path
@@ -377,36 +463,36 @@ class _WRFRunNamelist:
377
463
 
378
464
  if namelist_id not in self._namelist_id_list:
379
465
  logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
380
- raise ValueError(f"Unknown namelist id: {namelist_id}, register it first.")
466
+ raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
381
467
 
382
468
  self._namelist_dict[namelist_id] = f90nml.read(file_path).todict()
383
469
 
384
470
  def write_namelist(self, save_path: str, namelist_id: str, overwrite=True):
385
471
  """
386
- Write namelist to file.
472
+ Write namelist values of a ``namelist_id`` to a file.
387
473
 
388
- :param save_path: Save path.
474
+ :param save_path: Target file path.
389
475
  :type save_path: str
390
- :param namelist_id: ``"wps"``, ``"wrf"``, ``"wrfda"``, or any other id you have registered.
476
+ :param namelist_id: Registered ``namelist_id``.
391
477
  :type namelist_id: str
392
- :param overwrite: If overwrite the existed file, defaults to ``True``.
478
+ :param overwrite: If overwrite the existed file.
393
479
  :type overwrite: bool
394
480
  """
395
481
  if namelist_id not in self._namelist_id_list:
396
482
  logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
397
- raise ValueError(f"Unknown namelist id: {namelist_id}, register it first.")
483
+ raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
398
484
 
399
485
  if namelist_id not in self._namelist_dict:
400
486
  logger.error(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
401
- raise KeyError(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
487
+ raise NamelistError(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
402
488
 
403
489
  f90nml.Namelist(self._namelist_dict[namelist_id]).write(save_path, force=overwrite)
404
490
 
405
491
  def update_namelist(self, new_values: Union[str, dict], namelist_id: str):
406
492
  """
407
- Update value in namelist data.
493
+ Update namelist values of a ``namelist_id``.
408
494
 
409
- You can give your custom namelist file, a whole namelist or a file only contains values you want to change.
495
+ You can give the path of a whole namelist file or a file only contains values you want to change.
410
496
 
411
497
  >>> namelist_file = "./namelist.wps"
412
498
  >>> WRFRUNConfig.update_namelist(namelist_file, namelist_id="wps")
@@ -414,7 +500,7 @@ class _WRFRunNamelist:
414
500
  >>> namelist_file = "./namelist.wrf"
415
501
  >>> WRFRUNConfig.update_namelist(namelist_file, namelist_id="wrf")
416
502
 
417
- Or give a Dict object contains values you want to change.
503
+ You can also give a dict contains values you want to change.
418
504
 
419
505
  >>> namelist_values = {"ungrib": {"prefix": "./output/FILE"}}
420
506
  >>> WRFRUNConfig.update_namelist(namelist_values, namelist_id="wps")
@@ -422,14 +508,14 @@ class _WRFRunNamelist:
422
508
  >>> namelist_values = {"time_control": {"debug_level": 100}}
423
509
  >>> WRFRUNConfig.update_namelist(namelist_values, namelist_id="wrf")
424
510
 
425
- :param new_values: New values.
511
+ :param new_values: The path of a namelist file, or a dict contains namelist values.
426
512
  :type new_values: str | dict
427
- :param namelist_id: ``"wps"``, ``"wrf"``, ``"wrfda"``, or any other id you have registered.
513
+ :param namelist_id: Registered ``namelist_id``.
428
514
  :type namelist_id: str
429
515
  """
430
516
  if namelist_id not in self._namelist_id_list:
431
517
  logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
432
- raise ValueError(f"Unknown namelist id: {namelist_id}, register it first.")
518
+ raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
433
519
 
434
520
  elif namelist_id not in self._namelist_dict:
435
521
  self._namelist_dict[namelist_id] = new_values
@@ -452,29 +538,28 @@ class _WRFRunNamelist:
452
538
 
453
539
  def get_namelist(self, namelist_id: str) -> dict:
454
540
  """
455
- Get specific namelist.
541
+ Get namelist values of a ``namelist_id``.
456
542
 
457
- :param namelist_id: ``"wps"``, ``"wrf"``, ``"wrfda"``, or any other id you have registered.
543
+ :param namelist_id: Registered ``namelist_id``.
458
544
  :type namelist_id: str
459
- :return: Namelist.
545
+ :return: A dictionary which contains namelist values.
460
546
  :rtype: dict
461
547
  """
462
548
  if namelist_id not in self._namelist_id_list:
463
549
  logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
464
- raise ValueError(f"Unknown namelist id: {namelist_id}, register it first.")
550
+ raise NamelistIDError(f"Unknown namelist id: {namelist_id}, register it first.")
465
551
  elif namelist_id not in self._namelist_dict:
466
- return {}
552
+ logger.error(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
553
+ raise NamelistError(f"Can't found custom namelist '{namelist_id}', maybe you forget to read it first")
467
554
  else:
468
555
  return deepcopy(self._namelist_dict[namelist_id])
469
556
 
470
557
  def delete_namelist(self, namelist_id: str):
471
558
  """
472
- Delete specified namelist values.
559
+ Delete namelist values of a ``namelist_id``.
473
560
 
474
- :param namelist_id: ``"wps"``, ``"wrf"``, ``"wrfda"``, or any other id you have registered.
561
+ :param namelist_id: Registered ``namelist_id``.
475
562
  :type namelist_id: str
476
- :return:
477
- :rtype:
478
563
  """
479
564
  if namelist_id not in self._namelist_id_list:
480
565
  logger.error(f"Unknown namelist id: {namelist_id}, register it first.")
@@ -488,12 +573,20 @@ class _WRFRunNamelist:
488
573
 
489
574
  class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
490
575
  """
491
- Class to manage wrfrun config.
576
+ Class to manage wrfrun config, runtime constants, namelists and resource files.
492
577
  """
493
578
  _instance = None
494
579
  _initialized = False
495
580
 
496
581
  def __init__(self):
582
+ """
583
+ This class provides various interfaces to access ``wrfrun``'s config, namelist values of NWP models,
584
+ runtime constants and resource files by inheriting from:
585
+ :class:`_WRFRunConstants`, :class:`_WRFRunNamelist` and :class:`_WRFRunResources`.
586
+
587
+ An instance of this class called ``WRFRUNConfig`` will be created after the user import ``wrfrun``,
588
+ and you should use the instance to access configs or other things instead of creating another instance.
589
+ """
497
590
  if self._initialized:
498
591
  return
499
592
 
@@ -519,20 +612,24 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
519
612
 
520
613
  def set_config_template_path(self, file_path: str):
521
614
  """
522
- Set the path of template file.
615
+ Set file path of the config template file.
523
616
 
524
617
  :param file_path: Template file path.
525
618
  :type file_path: str
526
- :return:
527
- :rtype:
528
619
  """
529
620
  self._config_template_file_path = file_path
530
621
 
531
622
  def load_wrfrun_config(self, config_path: Optional[str] = None):
532
623
  """
533
- Load wrfrun config.
624
+ Load ``wrfrun`` config from a config file.
625
+
626
+ If the config path is invalid, ``wrfrun`` will create a new config file at the same place,
627
+ and raise ``FileNotFoundError``.
628
+
629
+ If you don't give the config path, ``wrfrun`` will create a new config file under the current directory,
630
+ and read it.
534
631
 
535
- :param config_path: YAML config file. Defaults to None.
632
+ :param config_path: TOML config file. Defaults to None.
536
633
  :type config_path: str
537
634
  """
538
635
  config_template_path = self.parse_resource_uri(self._config_template_file_path)
@@ -563,7 +660,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
563
660
 
564
661
  def save_wrfrun_config(self, save_path: str):
565
662
  """
566
- Save config to a file.
663
+ Save ``wrfrun``'s config to a file.
567
664
 
568
665
  :param save_path: Save path of the config.
569
666
  :type save_path: str
@@ -577,29 +674,41 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
577
674
  with open(save_path, "wb") as f:
578
675
  tomli_w.dump(self._config, f)
579
676
 
580
- def __getitem__(self, item):
677
+ def __getitem__(self, item: str):
678
+ """
679
+ You can access ``wrfrun`` config like the way to access values in a dictionary.
680
+
681
+ For example
682
+
683
+ >>> model_config = WRFRUNConfig["model"] # get all model configs.
684
+
685
+ :param item: Keys.
686
+ :type item: str
687
+ """
581
688
  if len(self._config) == 0:
582
689
  logger.error("Attempt to read value before load config")
583
690
  raise RuntimeError("Attempt to read value before load config")
584
691
 
585
692
  return deepcopy(self._config[item])
586
693
 
587
- def get_input_data_path(self) -> list[str]:
694
+ def get_input_data_path(self) -> str:
588
695
  """
589
- Return the path of input data.
696
+ Get the path of directory in which stores the input data.
590
697
 
591
- :return: Path list.
592
- :rtype: list
698
+ :return: Directory path.
699
+ :rtype: str
593
700
  """
594
701
  return deepcopy(self["input_data_path"])
595
702
 
596
703
  def get_model_config(self, model_name: str) -> dict:
597
704
  """
598
- Return the config of a NWP model.
705
+ Get the config of a NWP model.
599
706
 
600
- :param model_name: Name of the model. For example, "wrf".
707
+ An exception :class:`ModelNameError` will be raised if the config can't be found.
708
+
709
+ :param model_name: Name of the model. For example, ``wrf``.
601
710
  :type model_name: str
602
- :return: A dict object.
711
+ :return: A dictionary.
603
712
  :rtype: dict
604
713
  """
605
714
  if model_name not in self["model"]:
@@ -610,7 +719,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
610
719
 
611
720
  def get_log_path(self) -> str:
612
721
  """
613
- Return the save path of logs.
722
+ Get the directory path to save logs.
614
723
 
615
724
  :return: A directory path.
616
725
  :rtype: str
@@ -619,7 +728,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
619
728
 
620
729
  def get_socket_server_config(self) -> Tuple[str, int]:
621
730
  """
622
- Return settings of the socket server.
731
+ Get settings of the socket server.
623
732
 
624
733
  :return: ("host", port)
625
734
  :rtype: tuple
@@ -628,7 +737,7 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
628
737
 
629
738
  def get_job_scheduler_config(self) -> dict:
630
739
  """
631
- Return the config of job scheduler.
740
+ Get configs of job scheduler.
632
741
 
633
742
  :return: A dict object.
634
743
  :rtype: dict
@@ -637,9 +746,9 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
637
746
 
638
747
  def get_core_num(self) -> int:
639
748
  """
640
- Return the number of CPU cores.
641
- :return:
642
- :rtype:
749
+ Get the number of CPU cores to be used.
750
+ :return: Core numbers
751
+ :rtype: int
643
752
  """
644
753
  return self["core_num"]
645
754
 
@@ -672,12 +781,12 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
672
781
 
673
782
  :param prefix: Prefix string of ungrib output (WRF intermediate file).
674
783
  :type prefix: str
675
- :return:
676
- :rtype:
677
784
  """
678
- self.update_namelist({
679
- "ungrib": {"prefix": f"{self.UNGRIB_OUT_DIR}/{prefix}"}
680
- }, "wps")
785
+ self.update_namelist(
786
+ {
787
+ "ungrib": {"prefix": f"{self.UNGRIB_OUT_DIR}/{prefix}"}
788
+ }, "wps"
789
+ )
681
790
 
682
791
  def get_metgrid_fg_names(self) -> list[str]:
683
792
  """
@@ -692,26 +801,36 @@ class WRFRunConfig(_WRFRunConstants, _WRFRunNamelist, _WRFRunResources):
692
801
 
693
802
  def set_metgrid_fg_names(self, prefix: Union[str, list[str]]):
694
803
  """
695
- Set prefix strings from "fg_name" in namelist "metgrid" section.
804
+ Set prefix strings of "fg_name" in namelist "metgrid" section.
696
805
 
697
806
  :param prefix: Prefix strings list.
698
807
  :type prefix: str | list
699
- :return:
700
- :rtype:
701
808
  """
702
809
  if isinstance(prefix, str):
703
810
  prefix = [prefix, ]
704
811
  fg_names = [f"{self.UNGRIB_OUT_DIR}/{x}" for x in prefix]
705
- self.update_namelist({
706
- "metgrid": {"fg_name": fg_names}
707
- }, "wps")
812
+ self.update_namelist(
813
+ {
814
+ "metgrid": {"fg_name": fg_names}
815
+ }, "wps"
816
+ )
708
817
 
709
818
  def write_namelist(self, save_path: str, namelist_id: str, overwrite=True):
819
+ """
820
+ Write namelist values of a ``namelist_id`` to a file.
821
+ This method is overwritten to convert URIs in ``save_path`` first.
822
+
823
+ :param save_path: Target file path.
824
+ :type save_path: str
825
+ :param namelist_id: Registered ``namelist_id``.
826
+ :type namelist_id: str
827
+ :param overwrite: If overwrite the existed file.
828
+ :type overwrite: bool
829
+ """
710
830
  save_path = self.parse_resource_uri(save_path)
711
831
  super().write_namelist(save_path, namelist_id, overwrite)
712
832
 
713
833
 
714
834
  WRFRUNConfig = WRFRunConfig()
715
835
 
716
-
717
836
  __all__ = ["WRFRUNConfig"]