wrfrun 0.2.0__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 +69 -29
  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 +132 -406
  11. wrfrun/core/core.py +196 -0
  12. wrfrun/core/error.py +28 -2
  13. wrfrun/core/replay.py +10 -96
  14. wrfrun/core/server.py +52 -27
  15. wrfrun/core/type.py +171 -0
  16. wrfrun/data.py +304 -139
  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 +4 -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 -119
  30. wrfrun/model/type.py +116 -0
  31. wrfrun/model/utils.py +9 -20
  32. wrfrun/model/wrf/__init__.py +4 -9
  33. wrfrun/model/wrf/core.py +246 -161
  34. wrfrun/model/wrf/exec_wrap.py +13 -12
  35. wrfrun/model/wrf/geodata.py +116 -100
  36. wrfrun/model/wrf/log.py +103 -0
  37. wrfrun/model/wrf/namelist.py +90 -73
  38. wrfrun/model/wrf/plot.py +102 -0
  39. wrfrun/model/wrf/scheme.py +108 -52
  40. wrfrun/model/wrf/utils.py +39 -25
  41. wrfrun/model/wrf/vtable.py +35 -3
  42. wrfrun/plot/__init__.py +20 -0
  43. wrfrun/plot/wps.py +90 -73
  44. wrfrun/res/__init__.py +103 -5
  45. wrfrun/res/config/config.template.toml +8 -0
  46. wrfrun/res/config/palm.template.toml +23 -0
  47. wrfrun/run.py +105 -77
  48. wrfrun/scheduler/__init__.py +1 -0
  49. wrfrun/scheduler/lsf.py +3 -2
  50. wrfrun/scheduler/pbs.py +3 -2
  51. wrfrun/scheduler/script.py +17 -5
  52. wrfrun/scheduler/slurm.py +3 -2
  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 +20 -12
  57. wrfrun/workspace/palm.py +137 -0
  58. wrfrun/workspace/wrf.py +16 -15
  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 -923
  62. wrfrun/model/base.py +0 -14
  63. wrfrun-0.2.0.dist-info/METADATA +0 -68
  64. wrfrun-0.2.0.dist-info/RECORD +0 -62
  65. {wrfrun-0.2.0.dist-info → wrfrun-0.3.0.dist-info}/WHEEL +0 -0
  66. {wrfrun-0.2.0.dist-info → wrfrun-0.3.0.dist-info}/entry_points.txt +0 -0
wrfrun/core/core.py ADDED
@@ -0,0 +1,196 @@
1
+ """
2
+ wrfrun.core.core
3
+ ################
4
+
5
+ .. autosummary::
6
+ :toctree: generated/
7
+
8
+ WRFRUNProxy
9
+
10
+ Global variable "WRFRUN"
11
+ ************************
12
+
13
+ ``WRFRUN`` is an instance of :class:`WRFRUNProxy`.
14
+ It holds the instance of :class:`WRFRunConfig <wrfrun.core._config.WRFRunConfig>`,
15
+ :class:`ExecutableDB <wrfrun.core._exec_db.ExecutableDB>`,
16
+ and :class:`ExecutableRecorder <wrfrun.core._record.ExecutableRecorder>`.
17
+ Through this global variable, other submodules of wrfrun and users can access attributes and methods of these classes.
18
+ """
19
+
20
+ from typing import Callable, Literal
21
+
22
+ from ..log import logger
23
+ from ._config import WRFRunConfig
24
+ from ._exec_db import ExecutableDB
25
+ from ._record import ExecutableRecorder
26
+ from .error import ConfigError
27
+
28
+
29
+ class WRFRUNProxy:
30
+ """
31
+ Proxy class to access :class:`WRFRunConfig <wrfrun.core._config.WRFRunConfig>`,
32
+ :class:`ExecutableDB <wrfrun.core._exec_db.ExecutableDB>`,
33
+ and :class:`ExecutableRecorder <wrfrun.core._record.ExecutableRecorder>`.
34
+ """
35
+
36
+ def __init__(self):
37
+ """
38
+ Proxy class to access :class:`WRFRunConfig <wrfrun.core._config.WRFRunConfig>`,
39
+ :class:`ExecutableDB <wrfrun.core._exec_db.ExecutableDB>`,
40
+ and :class:`ExecutableRecorder <wrfrun.core._record.ExecutableRecorder>`.
41
+ """
42
+ self._config: WRFRunConfig | None = None
43
+ self._config_initialized = False
44
+ self._exec_db: ExecutableDB | None = None
45
+ self._exec_db_initialized = False
46
+ self._recorder: ExecutableRecorder | None = None
47
+ self._recorder_initialized = False
48
+
49
+ self._config_register_funcs: list[Callable[["WRFRunConfig"], None]] = []
50
+ self._exec_db_register_funcs: list[Callable[["ExecutableDB"], None]] = []
51
+
52
+ self.init_exec_db()
53
+
54
+ @property
55
+ def config(self) -> WRFRunConfig:
56
+ """
57
+ Access wrfrun config.
58
+
59
+ :return: wrfrun config.
60
+ :rtype: WRFRunConfig
61
+ """
62
+ if self._config is None:
63
+ logger.error("You haven't initialize `CONFIG` yet.")
64
+ raise ConfigError("You haven't initialize `CONFIG` yet.")
65
+ return self._config
66
+
67
+ @property
68
+ def ExecDB(self) -> ExecutableDB:
69
+ """
70
+ Access Executable DB.
71
+
72
+ :return: Executable DB.
73
+ :rtype: ExecutableDB
74
+ """
75
+ if self._exec_db is None:
76
+ logger.error("You haven't initialize `ExecDB` yet.")
77
+ raise ConfigError("You haven't initialize `ExecDB` yet.")
78
+ return self._exec_db
79
+
80
+ @property
81
+ def record(self) -> ExecutableRecorder:
82
+ """
83
+ Access simulation recorder.
84
+
85
+ :return: Simulation recorder.
86
+ :rtype: ExecutableRecorder
87
+ """
88
+ if self._recorder is None:
89
+ logger.error("You haven't initialize simulation recorder yet.")
90
+ raise ConfigError("You haven't initialize simulation recorder yet.")
91
+ return self._recorder
92
+
93
+ def set_exec_db(self, exec_db: ExecutableDB):
94
+ """
95
+ Initialize Executable DB.
96
+
97
+ :param exec_db: Executables DB.
98
+ :type exec_db: ExecutableDB
99
+ """
100
+ self._exec_db = exec_db
101
+ self._exec_db_initialized = True
102
+
103
+ def set_config_register_func(self, func: Callable[["WRFRunConfig"], None]):
104
+ """
105
+ Set register function which will be called by wrfrun config.
106
+ This functions should accept a ``WRFRunConfig`` instance.
107
+
108
+ If wrfrun config hasn't been initialized, the function will be stored
109
+ and called in order by the time wrfrun config is initialized.
110
+
111
+ :param func: Register functions.
112
+ :type func: Callable[["WRFRunConfig"], None]
113
+ """
114
+ if self._config_initialized:
115
+ func(self._config)
116
+
117
+ else:
118
+ if func not in self._config_register_funcs:
119
+ self._config_register_funcs.append(func)
120
+
121
+ def set_exec_db_register_func(self, func: Callable[["ExecutableDB"], None]):
122
+ """
123
+ Set register function which will be called by executables DB.
124
+ This function should accept a :class:`WRFRunExecutableRegisterCenter` instance.
125
+
126
+ If executables DB hasn't been initialized, the function will be stored
127
+ and called in order by the time executables DB is initialized.
128
+
129
+ :param func: Register functions.
130
+ :type func: Callable[["WRFRunExecutableRegisterCenter"], None]
131
+ """
132
+ if self._exec_db_initialized:
133
+ func(self._exec_db)
134
+
135
+ else:
136
+ if func not in self._exec_db_register_funcs:
137
+ self._exec_db_register_funcs.append(func)
138
+
139
+ def is_initialized(self, name: Literal["config", "exec_db", "record"]) -> bool:
140
+ """
141
+ Check if the config has been initialized.
142
+
143
+ :param name: Name of the instance.
144
+ :type name: str
145
+ :return: True or False.
146
+ :rtype: bool
147
+ """
148
+ flag = False
149
+
150
+ match name:
151
+ case "config":
152
+ flag = self._config_initialized
153
+
154
+ case "exec_db":
155
+ flag = self._exec_db_initialized
156
+
157
+ case "record":
158
+ flag = self._recorder_initialized
159
+
160
+ return flag
161
+
162
+ def init_wrfrun_config(self, config_file: str):
163
+ """
164
+ Initialize wrfrun config with the given config file.
165
+
166
+ :param config_file: Config file path.
167
+ :type config_file: str
168
+ """
169
+ logger.info(f"Initialize `WRFRUNConfig` with config: {config_file}")
170
+ self._config = WRFRunConfig.from_config_file(config_file, self._config_register_funcs)
171
+ self._config_initialized = True
172
+
173
+ def init_exec_db(self):
174
+ """
175
+ Initialize Executable DB.
176
+ """
177
+ self._exec_db = ExecutableDB()
178
+ self._exec_db.apply_register_func(self._exec_db_register_funcs)
179
+ self._exec_db_initialized = True
180
+
181
+ def init_recorder(self, save_path: str, include_data: bool):
182
+ """
183
+ Initialize simulation recorder.
184
+
185
+ :param save_path: Save path of the replay file.
186
+ :type save_path: str
187
+ :param include_data: If includes data.
188
+ :type include_data: bool
189
+ """
190
+ self._recorder = ExecutableRecorder(self._config, save_path, include_data)
191
+ self._recorder_initialized = True
192
+
193
+
194
+ WRFRUN = WRFRUNProxy()
195
+
196
+ __all__ = ["WRFRUN", "WRFRUNProxy"]
wrfrun/core/error.py CHANGED
@@ -26,6 +26,7 @@ class WRFRunBasicError(Exception):
26
26
  """
27
27
  Basic exception class of ``wrfrun``. New exception **MUST** inherit this class.
28
28
  """
29
+
29
30
  pass
30
31
 
31
32
 
@@ -33,6 +34,7 @@ class ConfigError(WRFRunBasicError):
33
34
  """
34
35
  Exception indicates the config of ``wrfrun`` or NWP model can't be used.
35
36
  """
37
+
36
38
  pass
37
39
 
38
40
 
@@ -40,6 +42,7 @@ class WRFRunContextError(WRFRunBasicError):
40
42
  """
41
43
  Exception indicates ``wrfrun`` is running out of the ``wrfrun`` context.
42
44
  """
45
+
43
46
  pass
44
47
 
45
48
 
@@ -47,6 +50,7 @@ class CommandError(WRFRunBasicError):
47
50
  """
48
51
  Exception indicates the command of ``Executable`` can't be executed successfully.
49
52
  """
53
+
50
54
  pass
51
55
 
52
56
 
@@ -54,6 +58,7 @@ class OutputFileError(WRFRunBasicError):
54
58
  """
55
59
  Exception indicates ``wrfrun`` can't find any output files with the given rules.
56
60
  """
61
+
57
62
  pass
58
63
 
59
64
 
@@ -61,6 +66,7 @@ class ResourceURIError(WRFRunBasicError):
61
66
  """
62
67
  Exception indicates ``wrfrun`` can't parse the URI.
63
68
  """
69
+
64
70
  pass
65
71
 
66
72
 
@@ -68,6 +74,7 @@ class InputFileError(WRFRunBasicError):
68
74
  """
69
75
  Exception indicates ``wrfrun`` can't find specified input files.
70
76
  """
77
+
71
78
  pass
72
79
 
73
80
 
@@ -75,6 +82,7 @@ class NamelistError(WRFRunBasicError):
75
82
  """
76
83
  Exception indicates ``wrfrun`` can't find the namelist user want to use.
77
84
  """
85
+
78
86
  pass
79
87
 
80
88
 
@@ -82,6 +90,7 @@ class NamelistIDError(WRFRunBasicError):
82
90
  """
83
91
  Exception indicates ``wrfrun`` can't register the specified namelist id.
84
92
  """
93
+
85
94
  pass
86
95
 
87
96
 
@@ -89,6 +98,7 @@ class ExecRegisterError(WRFRunBasicError):
89
98
  """
90
99
  Exception indicates ``wrfrun`` can't register the specified ``Executable``.
91
100
  """
101
+
92
102
  pass
93
103
 
94
104
 
@@ -96,6 +106,7 @@ class GetExecClassError(WRFRunBasicError):
96
106
  """
97
107
  Exception indicates ``wrfrun`` can't find the specified ``Executable``.
98
108
  """
109
+
99
110
  pass
100
111
 
101
112
 
@@ -103,6 +114,7 @@ class ModelNameError(WRFRunBasicError):
103
114
  """
104
115
  Exception indicates ``wrfrun`` can't find config of the specified NWP model in the config file.
105
116
  """
117
+
106
118
  pass
107
119
 
108
120
 
@@ -110,8 +122,22 @@ class RecordError(WRFRunBasicError):
110
122
  """
111
123
  Exception indicates ``wrfrun`` can't record simulations.
112
124
  """
125
+
113
126
  pass
114
127
 
115
128
 
116
- __all__ = ["WRFRunBasicError", "ConfigError", "WRFRunContextError", "CommandError", "OutputFileError", "ResourceURIError", "InputFileError",
117
- "NamelistError", "ExecRegisterError", "GetExecClassError", "ModelNameError", "NamelistIDError", "RecordError"]
129
+ __all__ = [
130
+ "WRFRunBasicError",
131
+ "ConfigError",
132
+ "WRFRunContextError",
133
+ "CommandError",
134
+ "OutputFileError",
135
+ "ResourceURIError",
136
+ "InputFileError",
137
+ "NamelistError",
138
+ "ExecRegisterError",
139
+ "GetExecClassError",
140
+ "ModelNameError",
141
+ "NamelistIDError",
142
+ "RecordError",
143
+ ]
wrfrun/core/replay.py CHANGED
@@ -2,115 +2,29 @@
2
2
  wrfrun.core.replay
3
3
  ##################
4
4
 
5
- This module provides methods to read config from ``.replay`` file and reproduce the simulation.
5
+ This module provides methods to read configs from replay file and reproduce simulations.
6
6
 
7
7
  .. autosummary::
8
8
  :toctree: generated/
9
9
 
10
- WRFRunExecutableRegisterCenter
11
10
  replay_config_generator
12
-
13
- WRFRUNExecDB
14
- ************
15
-
16
- In order to load ``Executable`` correctly based on the stored ``name`` in ``.replay`` files,
17
- ``wrfrun`` uses ``WRFRUNExecDB``, which is the instance of :class:`WRFRunExecutableRegisterCenter`,
18
- to records all ``Executable`` classes and corresponding ``name``.
19
- When ``wrfrun`` replays the simulation, it gets the right ``Executable`` from ``WRFRUNExecDB`` and executes it.
20
11
  """
21
12
 
22
13
  from collections.abc import Generator
23
14
  from json import loads
24
15
  from os.path import exists
25
16
  from shutil import unpack_archive
26
- from typing import Any
27
-
28
- from .base import ExecutableBase, ExecutableConfig
29
- from .config import WRFRUNConfig
30
- from .error import ExecRegisterError, GetExecClassError
31
- from ..utils import logger
32
-
33
- WRFRUN_REPLAY_URI = ":WRFRUN_REPLAY:"
34
-
35
-
36
- class WRFRunExecutableRegisterCenter:
37
- """
38
- This class provides the method to records ``Executable``'s class with a unique ``name``.
39
- Later you can get the class with the ``name``.
40
- """
41
- _instance = None
42
- _initialized = False
43
-
44
- def __init__(self):
45
- if self._initialized:
46
- return
47
-
48
- self._exec_db = {}
49
-
50
- self._initialized = True
51
-
52
- def __new__(cls, *args, **kwargs):
53
- if cls._instance is None:
54
- cls._instance = super().__new__(cls)
55
-
56
- return cls._instance
57
-
58
- def register_exec(self, name: str, cls: type):
59
- """
60
- Register an ``Executable``'s class with a unique ``name``.
61
-
62
- If the ``name`` has been used, :class:`ExecRegisterError` will be raised.
63
-
64
- :param name: ``Executable``'s unique name.
65
- :type name: str
66
- :param cls: ``Executable``'s class.
67
- :type cls: type
68
- """
69
- if name in self._exec_db:
70
- logger.error(f"'{name}' has been registered.")
71
- raise ExecRegisterError(f"'{name}' has been registered.")
72
-
73
- self._exec_db[name] = cls
74
-
75
- def is_registered(self, name: str) -> bool:
76
- """
77
- Check if an ``Executable``'s class has been registered.
78
-
79
- :param name: ``Executable``'s unique name.
80
- :type name: str
81
- :return: True or False.
82
- :rtype: bool
83
- """
84
- if name in self._exec_db:
85
- return True
86
- else:
87
- return False
88
-
89
- def get_cls(self, name: str) -> type:
90
- """
91
- Get an ``Executable``'s class with the ``name``.
92
-
93
- If the ``name`` can't be found, :class:`GetExecClassError` will be raised.
94
-
95
- :param name: ``Executable``'s unique name.
96
- :type name: str
97
- :return: ``Executable``'s class.
98
- :rtype: type
99
- """
100
- if name not in self._exec_db:
101
- logger.error(f"Executable class '{name}' not found.")
102
- raise GetExecClassError(f"Executable class '{name}' not found.")
103
-
104
- return self._exec_db[name]
105
-
106
17
 
107
- WRFRUNExecDB = WRFRunExecutableRegisterCenter()
18
+ from ..log import logger
19
+ from .base import ExecutableBase
20
+ from .core import WRFRUN
21
+ from .type import ExecutableConfig
108
22
 
109
23
 
110
- def replay_config_generator(replay_config_file: str) -> Generator[tuple[str, ExecutableBase], Any, None]:
24
+ def replay_config_generator(replay_config_file: str) -> Generator[tuple[str, ExecutableBase], None, None]:
111
25
  """
112
26
  This method can read the ``.replay`` file and returns a generator which yields ``Executable`` and their names.
113
- If this method doesn't find ``config.json`` in the ``.replay`` file, ``FileNotFoundError`` will be raised.
27
+ If this method doesn't find ``config.json`` in the ``.replay`` file, :class:`FileNotFoundError` will be raised.
114
28
 
115
29
  The ``Executable`` you get from the generator has been initialized so you can execute it directly.
116
30
 
@@ -124,7 +38,7 @@ def replay_config_generator(replay_config_file: str) -> Generator[tuple[str, Exe
124
38
  :rtype: Generator
125
39
  """
126
40
  logger.info(f"Loading replay resources from: {replay_config_file}")
127
- work_path = WRFRUNConfig.parse_resource_uri(WRFRUNConfig.WRFRUN_WORKSPACE_REPLAY)
41
+ work_path = WRFRUN.config.parse_resource_uri(WRFRUN.config.WRFRUN_WORKSPACE_REPLAY)
128
42
 
129
43
  unpack_archive(replay_config_file, work_path, "zip")
130
44
 
@@ -138,9 +52,9 @@ def replay_config_generator(replay_config_file: str) -> Generator[tuple[str, Exe
138
52
  for _config in replay_config_list:
139
53
  args = _config["class_config"]["class_args"]
140
54
  kwargs = _config["class_config"]["class_kwargs"]
141
- executable: ExecutableBase = WRFRUNExecDB.get_cls(_config["name"])(*args, **kwargs)
55
+ executable: ExecutableBase = WRFRUN.ExecDB.get_cls(_config["name"])(*args, **kwargs)
142
56
  executable.load_config(_config)
143
57
  yield _config["name"], executable
144
58
 
145
59
 
146
- __all__ = ["WRFRUNExecDB", "replay_config_generator"]
60
+ __all__ = ["replay_config_generator"]
wrfrun/core/server.py CHANGED
@@ -2,8 +2,7 @@
2
2
  wrfrun.core.server
3
3
  ##################
4
4
 
5
- Currently, ``wrfrun`` provides the method to reads log file of WRF and calculates simulation progress.
6
- In order to report the progress to user, ``wrfrun`` provides :class:`WRFRunServer` to set up a socket server.
5
+ This module defines the socket server to report simulation progress.
7
6
 
8
7
  .. autosummary::
9
8
  :toctree: generated/
@@ -12,6 +11,29 @@ In order to report the progress to user, ``wrfrun`` provides :class:`WRFRunServe
12
11
  WRFRunServer
13
12
  WRFRunServerHandler
14
13
  stop_server
14
+
15
+ How does wrfrun get simulation progress?
16
+ ****************************************
17
+
18
+ Currently, wrfrun relies on the log parse function provided by :doc:`model </api/model>`.
19
+ The log parse function should accept one parameter ``datetime``,
20
+ and return an integer represents how many seconds the model has simulated.
21
+ For example, the signature of :func:`get_wrf_simulated_seconds <wrfrun.model.wrf.log.get_wrf_simulated_seconds>` is:
22
+
23
+ .. code-block:: Python
24
+
25
+ def get_wrf_simulated_seconds(start_datetime: datetime) -> int:
26
+ pass
27
+
28
+ Socket server API list
29
+ **********************
30
+
31
+ The socket server accepts a JSON string: ``{"message": "MESSAGE"}``.
32
+ The ``MESSAGE`` can be:
33
+
34
+ * "stop": Stop the socket server.
35
+ * "debug": Get the start date of the simulation, and the total seconds it will simulate: ``{"start_date": "...", "total_seconds": "..."}``.
36
+ * Any string else: Simulation progress: ``{"usage": "...", "status": "...", "progress": "..."}``.
15
37
  """
16
38
 
17
39
  import socket
@@ -19,19 +41,21 @@ import socketserver
19
41
  import threading
20
42
  from collections.abc import Callable
21
43
  from datetime import datetime
22
- from json import dumps
44
+ from json import dumps, loads
23
45
  from time import time
24
- from typing import Tuple
46
+ from typing import Any, Tuple
25
47
 
26
- from .config import WRFRUNConfig
27
- from ..utils import logger
48
+ from ..log import logger
49
+ from .core import WRFRUN
28
50
 
29
- WRFRUN_SERVER_INSTANCE = None
30
- WRFRUN_SERVER_THREAD = None
51
+
52
+ def _defaut_log_parser(date: datetime) -> int:
53
+ return -1
31
54
 
32
55
 
33
56
  SET_LOG_PARSER_LOCK = threading.Lock()
34
- LOG_PARSER: Callable[[datetime], int] | None = None
57
+ # default parser returns -1
58
+ LOG_PARSER: Callable[[datetime], int] = _defaut_log_parser
35
59
 
36
60
 
37
61
  def set_log_parse_func(func: Callable[[datetime], int]):
@@ -175,6 +199,7 @@ class WRFRunServerHandler(socketserver.StreamRequestHandler):
175
199
  ``status`` represents work status,
176
200
  ``progress`` represents simulation progress of the status in percentage.
177
201
  """
202
+
178
203
  def __init__(self, request, client_address, server: WRFRunServer) -> None:
179
204
  """
180
205
  :class:`WRFRunServer` handler.
@@ -189,7 +214,7 @@ class WRFRunServerHandler(socketserver.StreamRequestHandler):
189
214
  super().__init__(request, client_address, server)
190
215
 
191
216
  # get server
192
- self.server: WRFRunServer = server
217
+ self._server: WRFRunServer = server
193
218
 
194
219
  def calculate_time_usage(self) -> int:
195
220
  """
@@ -203,7 +228,7 @@ class WRFRunServerHandler(socketserver.StreamRequestHandler):
203
228
  current_timestamp = datetime.fromtimestamp(time())
204
229
 
205
230
  # get delta second
206
- seconds_diff = current_timestamp - self.server.get_start_time()
231
+ seconds_diff = current_timestamp - self._server.get_start_time()
207
232
  seconds_diff = seconds_diff.seconds
208
233
 
209
234
  return seconds_diff
@@ -216,20 +241,17 @@ class WRFRunServerHandler(socketserver.StreamRequestHandler):
216
241
  ``progress`` represents simulation progress of the status in percentage.
217
242
  :rtype: tuple[str, int]
218
243
  """
219
- start_date, simulate_seconds = self.server.get_model_simulate_settings()
244
+ start_date, simulate_seconds = self._server.get_model_simulate_settings()
220
245
 
221
246
  with SET_LOG_PARSER_LOCK:
222
- if LOG_PARSER is None:
223
- simulated_seconds = -1
224
- else:
225
- simulated_seconds = LOG_PARSER(start_date)
247
+ simulated_seconds = LOG_PARSER(start_date)
226
248
 
227
249
  if simulated_seconds > 0:
228
250
  progress = simulated_seconds * 100 // simulate_seconds
229
251
  else:
230
252
  progress = -1
231
253
 
232
- status = WRFRUNConfig.WRFRUN_WORK_STATUS
254
+ status = WRFRUN.config.WRFRUN_WORK_STATUS
233
255
 
234
256
  if status == "":
235
257
  status = "*"
@@ -240,20 +262,20 @@ class WRFRunServerHandler(socketserver.StreamRequestHandler):
240
262
  """
241
263
  Request handler.
242
264
  """
243
-
244
265
  # check if we will to stop server
245
- msg = self.rfile.readline().decode().split('\n')[0]
266
+ request: dict[str, Any] = loads(self.rfile.readline().decode())
267
+ msg = request["message"]
246
268
 
247
269
  if msg == "stop":
248
- self.server.shutdown()
249
- self.wfile.write(f"Server stop\n".encode())
250
-
270
+ self._server.shutdown()
271
+ self.wfile.write("Server stop\n".encode())
272
+
251
273
  elif msg == "debug":
252
- start_date, simulate_seconds = self.server.get_model_simulate_settings()
274
+ start_date, simulate_seconds = self._server.get_model_simulate_settings()
253
275
  start_date = start_date.strftime("%Y-%m-%d %H:%M")
254
-
276
+
255
277
  self.wfile.write(dumps({"start_date": start_date, "total_seconds": simulate_seconds}).encode())
256
-
278
+
257
279
  else:
258
280
  status, progress = self.calculate_progress()
259
281
  time_usage = self.calculate_time_usage()
@@ -275,10 +297,13 @@ def stop_server(socket_ip: str, socket_port: int):
275
297
  sock.connect((socket_ip, socket_port))
276
298
 
277
299
  # send msg to server
278
- sock.sendall("stop\n".encode())
300
+ # TODO:
301
+ # Need to test the new socket server.
302
+ msg = dumps({"message": "stop"})
303
+ sock.sendall(msg.encode())
279
304
 
280
305
  # receive the message
281
- msg = sock.recv(1024).decode().split('\n')[0]
306
+ msg = sock.recv(1024).decode().split("\n")[0]
282
307
 
283
308
  logger.info(f"WRFRunServer: {msg}")
284
309