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/log.py ADDED
@@ -0,0 +1,117 @@
1
+ """
2
+ wrfrun.log
3
+ ##########
4
+
5
+ .. autosummary::
6
+ :toctree: generated/
7
+
8
+ get_wrfrun_rich_console
9
+ logger_add_file_handler
10
+ set_logger
11
+ unify_logger_format
12
+
13
+ ``wrfrun`` submodule to manage logs. This submodule only take care of ``wrfrun``'s log.
14
+
15
+ For functions and classes which parse numerical models' log, please check :doc:`model </api/model>`.
16
+ """
17
+
18
+ import logging
19
+ from datetime import datetime
20
+ from os import environ
21
+ from time import time
22
+ from typing import Dict, List, Optional
23
+
24
+ from rich.console import Console
25
+ from rich.logging import RichHandler
26
+
27
+ from .utils import check_path
28
+
29
+ WRFRUN_RICH_CONSOLE = Console()
30
+
31
+
32
+ def set_logger(logger_list: List[str], logger_level: Optional[Dict] = None):
33
+ """
34
+ This function will replace all handlers of each logger in ``logger_list`` with RichHandler.
35
+
36
+ If there are some custom handlers in logger, they will be replaced too.
37
+
38
+ :param logger_list: A list contains loggers.
39
+ :type logger_list: list
40
+ :param logger_level: You can specify the log level in ``logger_level``, with the name of logger is the key,
41
+ and the level of logger is the value.
42
+ Default if None, with which all loggers' level will be set to ``logging.WARNING``.
43
+ :type logger_level: list | None
44
+ """
45
+ formatter = logging.Formatter("%(name)s :: %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
46
+ # use rich handler
47
+ handler = RichHandler(console=WRFRUN_RICH_CONSOLE)
48
+ handler.setFormatter(formatter)
49
+
50
+ for logger_name in logger_list:
51
+ if logger_name in logging.root.manager.loggerDict:
52
+ _logger = logging.getLogger(logger_name)
53
+ for _handler in _logger.handlers:
54
+ _logger.removeHandler(_handler)
55
+ _logger.addHandler(handler)
56
+
57
+ if logger_level is not None and logger_name in logger_level:
58
+ _logger.setLevel(logger_level[logger_name])
59
+ else:
60
+ _logger.setLevel(logging.WARNING)
61
+
62
+
63
+ def unify_logger_format():
64
+ """
65
+ This function is only supposed to be used internally.
66
+
67
+ This function will replace all handlers of each logger with ``rich.logging.RichHandler``.
68
+ Use this carefully.
69
+ """
70
+ set_logger(
71
+ ["cdsapi", "cfgrib", "datapi"],
72
+ {"cdsapi": logging.INFO, "cfgrib": logging.ERROR, "datapi": logging.INFO},
73
+ )
74
+
75
+
76
+ # init wrfrun logger
77
+ logger = logging.getLogger("wrfrun")
78
+ # check environment variables and set logger level
79
+ if "WRFRUN_DEBUG_MODE" in environ and environ["WRFRUN_DEBUG_MODE"]:
80
+ _logger_level = logging.DEBUG
81
+ _debug_mode = True
82
+ else:
83
+ _logger_level = logging.INFO
84
+ _debug_mode = False
85
+ set_logger(["wrfrun"], {"wrfrun": _logger_level})
86
+ logger.debug(f"DEBUG MODE: {_debug_mode}")
87
+
88
+
89
+ def logger_add_file_handler(log_path: str):
90
+ """
91
+ Set log file of logger.
92
+
93
+ :param log_path: Log file path.
94
+ :type log_path: str
95
+ """
96
+ # check log save path
97
+ check_path(log_path)
98
+
99
+ # add file handler
100
+ file_handler = logging.FileHandler(f"{log_path}/{datetime.fromtimestamp(time()).strftime('%Y-%m-%d %H:%M:%S')}.log")
101
+ file_handler.setFormatter(
102
+ logging.Formatter("%(asctime)s - %(name)s - %(levelname)s :: %(message)s", datefmt="%m-%d %H:%M:%S")
103
+ )
104
+ logger.addHandler(file_handler)
105
+
106
+
107
+ def get_wrfrun_rich_console() -> Console:
108
+ """
109
+ Get ``rich.console.Console`` instance used in wrfrun.
110
+
111
+ :return: Console instance.
112
+ :rtype: Console
113
+ """
114
+ return WRFRUN_RICH_CONSOLE
115
+
116
+
117
+ __all__ = ["set_logger", "unify_logger_format", "logger_add_file_handler", "logger", "get_wrfrun_rich_console"]
wrfrun/model/__init__.py CHANGED
@@ -3,12 +3,14 @@ wrfrun.model
3
3
  ############
4
4
 
5
5
  To be able to handle different numerical models,
6
- ``wrfrun`` implements various ``Executable`` for model's binary executable based on :class:`ExecutableBase <wrfrun.core.base.ExecutableBase>`,
6
+ ``wrfrun`` implements various ``Executable`` for model's binary executable
7
+ based on :class:`ExecutableBase <wrfrun.core.base.ExecutableBase>`,
7
8
  which are all placed in this module.
8
9
 
9
10
  ``wrfrun.model`` currently supports following numerical models:
10
11
 
11
12
  ========================================= ==========================================
13
+ :doc:`palm </api/model.palm>` Support for PALM
12
14
  :doc:`wrf </api/model.wrf>` Support for WRF
13
15
  ========================================= ==========================================
14
16
 
@@ -16,15 +18,17 @@ which are all placed in this module.
16
18
  :maxdepth: 1
17
19
  :hidden:
18
20
 
19
- wrf <model.wrf>
20
- base <model.base>
21
+ constants <model.constants>
22
+ palm <model.palm>
21
23
  plot <model.plot>
24
+ type <model.type>
22
25
  utils <model.utils>
26
+ wrf <model.wrf>
23
27
  """
24
28
 
25
- from .base import *
29
+ # just to register executables
30
+ from . import palm as _
31
+ from . import wrf as _
32
+ from .constants import *
26
33
  from .plot import *
27
34
  from .utils import *
28
-
29
- # just to register executables
30
- from . import wrf
@@ -0,0 +1,52 @@
1
+ """
2
+ wrfrun.model.constants
3
+ ######################
4
+
5
+ Definition of constants used by models.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ NamelistName
11
+ """
12
+
13
+ from dataclasses import dataclass
14
+
15
+
16
+ @dataclass
17
+ class NamelistName:
18
+ """
19
+ Namelist file names.
20
+
21
+ .. py:attribute:: WPS
22
+ :type: str
23
+ :value: namelist.wps
24
+
25
+ WPS namelist file name.
26
+
27
+ .. py:attribute:: WRF
28
+ :type: str
29
+ :value: namelist.input
30
+
31
+ WRF namelist file name.
32
+
33
+ .. py:attribute:: WRFDA
34
+ :type: str
35
+ :value: namelist.input
36
+
37
+ WRFDA namelist file name.
38
+
39
+ .. py:attribute:: PALM
40
+ :type: str
41
+ :value: wrfrun_p3d
42
+
43
+ PALM namelist file name.
44
+ """
45
+
46
+ WPS = "namelist.wps"
47
+ WRF = "namelist.input"
48
+ WRFDA = "namelist.input"
49
+ PALM = "wrfrun_p3d"
50
+
51
+
52
+ __all__ = ["NamelistName"]
@@ -0,0 +1,30 @@
1
+ """
2
+ wrfrun.model.palm
3
+ #################
4
+
5
+ Implementation of PALM model.
6
+
7
+ Submodules
8
+ **********
9
+
10
+ ============================================ ==================================================================================
11
+ :doc:`core </api/model.palm.core>` Core implementation of PALM model.
12
+ :doc:`namelist </api/model.palm.namelist>` Functions to process PALM namelist files.
13
+ ============================================ ==================================================================================
14
+
15
+ About the implementation of PALM
16
+ ********************************
17
+
18
+ Since ``PALM`` provides a bash script ``palmrun`` to take care of the running of ``palm``,
19
+ ``wrfrun`` just simply wraps the bash script.
20
+
21
+ .. toctree::
22
+ :maxdepth: 1
23
+ :hidden:
24
+
25
+ core <model.palm.core>
26
+ namelist <model.palm.namelist>
27
+ """
28
+
29
+ from .core import *
30
+ from .namelist import *
@@ -0,0 +1,145 @@
1
+ """
2
+ wrfrun.model.palm.core
3
+ ######################
4
+
5
+ Core implementation of PALM model. All ``Executable`` and function interface of PALM model are defined here.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ _check_and_prepare_namelist
11
+ PALMRun
12
+ palmrun
13
+ """
14
+
15
+ from os.path import exists
16
+ from typing import Optional
17
+
18
+ from wrfrun.core import WRFRUN, ExecutableBase, ExecutableDB
19
+ from wrfrun.log import logger
20
+ from wrfrun.workspace.palm import get_palm_workspace_path
21
+
22
+ from ..constants import NamelistName
23
+ from .namelist import prepare_palm_namelist
24
+
25
+
26
+ def _check_and_prepare_namelist():
27
+ """
28
+ Check if namelist of ``PALM`` has been loaded.
29
+ If not, call :func:`prepare_palm_namelist <wrfrun.model.palm.namelist.prepare_palm_namelist>` to load it.
30
+ """
31
+ if not WRFRUN.config.check_namelist("palm"):
32
+ prepare_palm_namelist()
33
+
34
+
35
+ class PALMRun(ExecutableBase):
36
+ """
37
+ ``Executable`` for bash script "palmrun".
38
+ """
39
+
40
+ def __init__(self, config_id: str = "default", core_num: Optional[int] = None):
41
+ """
42
+ ``Executable`` for bash script "palmrun".
43
+
44
+ :param config_id: Configuration identifier of ``PALM``, defaults to "default"
45
+ :type config_id: str, optional
46
+ :param core_num: CPU cores to use, defaults to None
47
+ :type core_num: Optional[int], optional
48
+ """
49
+ if isinstance(core_num, int) and core_num <= 0:
50
+ logger.warning("`core_num` should be greater than 0")
51
+ core_num = None
52
+
53
+ mpi_use = False
54
+ mpi_cmd = None
55
+ mpi_core_num = None
56
+
57
+ cmd = f"./palmrun -r wrfrun -c {config_id} -a d3# -X {core_num} -v"
58
+
59
+ super().__init__("palmrun", cmd, get_palm_workspace_path(), mpi_use, mpi_cmd, mpi_core_num)
60
+
61
+ _check_and_prepare_namelist()
62
+
63
+ def generate_custom_config(self):
64
+ """
65
+ Store custom configs, including:
66
+
67
+ * Namelist settings.
68
+ """
69
+ self.custom_config.update({"namelist": WRFRUN.config.get_namelist("palm")})
70
+
71
+ def load_custom_config(self):
72
+ """
73
+ Load custom configs, including:
74
+
75
+ * Namelist settings.
76
+ """
77
+ WRFRUN.config.update_namelist(self.custom_config["namelist"], "palm")
78
+
79
+ def before_exec(self):
80
+ WRFRUN.config.check_wrfrun_context(True)
81
+ WRFRUN.config.WRFRUN_WORK_STATUS = "palm"
82
+
83
+ config = WRFRUN.config.get_model_config("palm")
84
+
85
+ if not WRFRUN.config.IS_IN_REPLAY:
86
+ # check if user provides topography files
87
+ if exists(config["topography_file"]):
88
+ self.add_input_files(
89
+ {
90
+ "file_path": config["topography_file"],
91
+ "save_path": get_palm_workspace_path("input"),
92
+ "save_name": "palmrun.topo",
93
+ "is_data": True,
94
+ "is_output": False,
95
+ }
96
+ )
97
+
98
+ super().before_exec()
99
+
100
+ WRFRUN.config.write_namelist(f"{get_palm_workspace_path('input')}/{NamelistName.PALM}", "palm")
101
+
102
+ # print debug logs
103
+ logger.debug("Namelist settings of 'palmrun':")
104
+ logger.debug(WRFRUN.config.get_namelist("palm"))
105
+
106
+ def after_exec(self):
107
+ if not WRFRUN.config.IS_IN_REPLAY:
108
+ self.add_output_files(
109
+ output_dir=get_palm_workspace_path("output"), save_path=self._output_save_path, startswith="wrfrun_"
110
+ )
111
+
112
+ super().after_exec()
113
+
114
+ logger.info(f"All PALM output files have been copied to {WRFRUN.config.parse_resource_uri(self._output_save_path)}")
115
+
116
+
117
+ def palmrun():
118
+ """
119
+ Function interface for :class:`PALMRun`.
120
+
121
+ Parameters needed to initialize :class:`PALMRun` is read from global variable :doc:`WRFRUN </api/core.core>`.
122
+ """
123
+ config = WRFRUN.config.get_model_config("palm")
124
+ PALMRun(config["config_identifier"], WRFRUN.config.get_core_num())()
125
+
126
+
127
+ def _exec_register_func(exec_db: ExecutableDB):
128
+ """
129
+ Function to register ``Executable``.
130
+
131
+ :param exec_db: ``ExecutableDB`` instance.
132
+ :type exec_db: ExecutableDB
133
+ """
134
+ class_list = [PALMRun]
135
+ class_id_list = ["palmrun"]
136
+
137
+ for _class, _id in zip(class_list, class_id_list):
138
+ if not exec_db.is_registered(_id):
139
+ exec_db.register_exec(_id, _class)
140
+
141
+
142
+ WRFRUN.set_exec_db_register_func(_exec_register_func)
143
+
144
+
145
+ __all__ = ["PALMRun", "palmrun"]
@@ -0,0 +1,33 @@
1
+ """
2
+ wrfrun.model.palm.namelist
3
+ ##########################
4
+
5
+ Functions to process namelist for ``PALM``.
6
+
7
+ .. autosummary::
8
+ :toctree: generated/
9
+
10
+ prepare_palm_namelist
11
+ """
12
+
13
+ from os.path import exists
14
+
15
+ from wrfrun.core import WRFRUN
16
+ from wrfrun.log import logger
17
+
18
+
19
+ def prepare_palm_namelist():
20
+ """
21
+ This function loads user PALM namelist file and save it in :doc:`WRFRUN </api/core.core>`.
22
+ """
23
+ palm_config = WRFRUN.config.get_model_config("palm")
24
+ namelist_file = palm_config["user_namelist"]
25
+
26
+ if not exists(namelist_file):
27
+ logger.error(f"Can't find PALM namelist: {namelist_file}")
28
+ raise FileNotFoundError(f"Can't find PALM namelist: {namelist_file}")
29
+
30
+ WRFRUN.config.read_namelist(namelist_file, "palm")
31
+
32
+
33
+ __all__ = ["prepare_palm_namelist"]