pyfemtet 0.4.10__py3-none-any.whl → 0.4.12__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.

Potentially problematic release.


This version of pyfemtet might be problematic. Click here for more details.

Files changed (77) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/_test_util.py +26 -0
  3. pyfemtet/opt/__init__.py +1 -1
  4. pyfemtet/opt/_femopt.py +41 -5
  5. pyfemtet/opt/interface/_base.py +6 -1
  6. pyfemtet/opt/interface/_femtet.py +32 -10
  7. pyfemtet/opt/interface/_femtet_parametric.py +5 -25
  8. pyfemtet/opt/opt/__init__.py +3 -1
  9. pyfemtet/opt/opt/_base.py +88 -8
  10. pyfemtet/opt/opt/_optuna.py +17 -2
  11. pyfemtet/opt/opt/_scipy.py +144 -0
  12. pyfemtet/opt/opt/_scipy_scalar.py +104 -0
  13. pyfemtet/opt/visualization/__init__.py +0 -7
  14. pyfemtet/opt/visualization/_create_wrapped_components.py +93 -0
  15. pyfemtet/opt/visualization/base.py +254 -0
  16. pyfemtet/opt/visualization/complex_components/__init__.py +0 -0
  17. pyfemtet/opt/visualization/complex_components/alert_region.py +71 -0
  18. pyfemtet/opt/visualization/complex_components/control_femtet.py +195 -0
  19. pyfemtet/opt/visualization/{_graphs.py → complex_components/main_figure_creator.py} +13 -49
  20. pyfemtet/opt/visualization/complex_components/main_graph.py +263 -0
  21. pyfemtet/opt/visualization/process_monitor/__init__.py +0 -0
  22. pyfemtet/opt/visualization/process_monitor/application.py +201 -0
  23. pyfemtet/opt/visualization/process_monitor/pages.py +276 -0
  24. pyfemtet/opt/visualization/result_viewer/.gitignore +1 -0
  25. pyfemtet/opt/visualization/result_viewer/__init__.py +0 -0
  26. pyfemtet/opt/visualization/result_viewer/application.py +44 -0
  27. pyfemtet/opt/visualization/result_viewer/pages.py +692 -0
  28. pyfemtet/opt/visualization/result_viewer/tutorial/tutorial.csv +18 -0
  29. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.jpg +0 -0
  30. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.log +81 -0
  31. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  32. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow.csv +28 -0
  33. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow_el.csv +22 -0
  34. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  35. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
  36. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  37. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
  38. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  39. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  40. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  41. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  42. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  43. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  44. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  45. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  46. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  47. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  48. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  49. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
  50. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  51. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
  52. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  53. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
  54. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  55. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
  56. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  57. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
  58. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  59. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
  60. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  61. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
  62. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  63. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
  64. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.femprj +0 -0
  65. pyfemtet/opt/visualization/wrapped_components/__init__.py +0 -0
  66. pyfemtet/opt/visualization/wrapped_components/dbc.py +1518 -0
  67. pyfemtet/opt/visualization/wrapped_components/dcc.py +609 -0
  68. pyfemtet/opt/visualization/wrapped_components/html.py +3570 -0
  69. pyfemtet/opt/visualization/wrapped_components/str_enum.py +43 -0
  70. {pyfemtet-0.4.10.dist-info → pyfemtet-0.4.12.dist-info}/METADATA +1 -1
  71. pyfemtet-0.4.12.dist-info/RECORD +138 -0
  72. {pyfemtet-0.4.10.dist-info → pyfemtet-0.4.12.dist-info}/entry_points.txt +1 -1
  73. pyfemtet/opt/visualization/_monitor.py +0 -1227
  74. pyfemtet/opt/visualization/result_viewer.py +0 -13
  75. pyfemtet-0.4.10.dist-info/RECORD +0 -83
  76. {pyfemtet-0.4.10.dist-info → pyfemtet-0.4.12.dist-info}/LICENSE +0 -0
  77. {pyfemtet-0.4.10.dist-info → pyfemtet-0.4.12.dist-info}/WHEEL +0 -0
@@ -0,0 +1,201 @@
1
+ from typing import List
2
+ from time import sleep
3
+ from threading import Thread
4
+
5
+ import pandas as pd
6
+
7
+ from pyfemtet.opt.visualization.base import PyFemtetApplicationBase, logger
8
+ from pyfemtet.opt.visualization.process_monitor.pages import HomePage, WorkerPage
9
+
10
+
11
+ class ProcessMonitorApplication(PyFemtetApplicationBase):
12
+ """"""
13
+ """
14
+ +------+--------+
15
+ | side | con- |
16
+ | bar | tent |
17
+ +--^---+--^-----+
18
+ │ └─ pages (dict(href: str = layout: Component))
19
+ └──────── nav_links (dict(order: float) = NavLink)
20
+
21
+ Accessible members:
22
+ - history: History
23
+ └ local_df: pd.DataFrame
24
+ - app: Dash
25
+ - local_entire_status_int: int <----------------> femopt.statue: OptimizationStatus(Actor)
26
+ - local_worker_status_int_list: List[int] <-----> femopt.opt.statue: List[OptimizationStatus(Actor)]
27
+ ^
28
+ |
29
+ sync "while" statement in start_server()
30
+ """
31
+
32
+ DEFAULT_PORT = 8080
33
+
34
+ def __init__(
35
+ self,
36
+ history,
37
+ status,
38
+ worker_addresses,
39
+ worker_status_list,
40
+ is_debug=False,
41
+ ):
42
+ super().__init__(
43
+ title='PyFemtet Monitor',
44
+ subtitle='visualize optimization progress',
45
+ history=history,
46
+ )
47
+
48
+ self._should_get_actor_data = False
49
+ self.is_debug = is_debug
50
+
51
+ # type hint (avoid circular import)
52
+ from pyfemtet.opt._femopt_core import OptimizationStatus
53
+
54
+ # register arguments
55
+ self.worker_addresses: List[str] = worker_addresses
56
+ self.entire_status: OptimizationStatus = status # include actor
57
+ self.worker_status_list: List[OptimizationStatus] = worker_status_list # include actor
58
+
59
+ # initialize local members (from actors)
60
+ self._df: pd.DataFrame = self.local_data
61
+ self.local_entire_status_int: int = self.entire_status.get()
62
+ self.local_worker_status_int_list: List[int] = [s.get() for s in self.worker_status_list]
63
+
64
+ @property
65
+ def local_data(self) -> pd.DataFrame:
66
+ if self._should_get_actor_data:
67
+ return self._df
68
+ else:
69
+ return self.history.local_data
70
+
71
+
72
+ @local_data.setter
73
+ def local_data(self, value: pd.DataFrame):
74
+ if self._should_get_actor_data:
75
+ raise NotImplementedError('If should_get_actor_data, ProcessMonitorApplication.local_df is read_only.')
76
+ else:
77
+ self.history.local_data = value
78
+
79
+
80
+ def setup_callback(self, debug=False):
81
+ if not debug:
82
+ super().setup_callback()
83
+
84
+ def start_server(self, host=None, port=None):
85
+ """Callback の中で使いたい Actor のデータを Application クラスのメンバーとやり取りしつつ、server を落とす関数"""
86
+
87
+ self._should_get_actor_data = True
88
+
89
+ # avoid circular import
90
+ from pyfemtet.opt._femopt_core import OptimizationStatus
91
+
92
+ host = host or 'localhost'
93
+ port = port or self.DEFAULT_PORT
94
+
95
+ # dash app server を daemon thread で起動
96
+ server_thread = Thread(
97
+ target=self.run,
98
+ args=(host, port,),
99
+ daemon=True,
100
+ )
101
+ server_thread.start()
102
+
103
+ # dash app (=flask server) の callback で dask の actor にアクセスすると
104
+ # おかしくなることがあるので、ここで必要な情報のみやり取りする
105
+ while True:
106
+ # running 以前に monitor で current status を interrupting にしていれば actor に反映
107
+ if (
108
+ (self.entire_status.get() <= OptimizationStatus.RUNNING) # メインプロセスが RUNNING 以前である
109
+ and (self.local_entire_status_int == OptimizationStatus.INTERRUPTING) # Application で status を INTERRUPT にした
110
+ ):
111
+ self.entire_status.set(OptimizationStatus.INTERRUPTING)
112
+ for worker_status in self.worker_status_list:
113
+ worker_status.set(OptimizationStatus.INTERRUPTING)
114
+
115
+ # status と df を actor から application に反映する
116
+ self._df = self.history.actor_data.copy()
117
+ self.local_entire_status_int = self.entire_status.get()
118
+ self.local_worker_status_int_list = [s.get() for s in self.worker_status_list]
119
+
120
+ # terminate_all 指令があれば flask server をホストするプロセスごと終了する
121
+ if self.entire_status.get() >= OptimizationStatus.TERMINATE_ALL:
122
+ return 0 # take server down with me
123
+
124
+ # interval
125
+ sleep(1)
126
+
127
+ def get_status_color(self, status_int):
128
+ from pyfemtet.opt._femopt_core import OptimizationStatus
129
+ # set color
130
+ if status_int <= OptimizationStatus.SETTING_UP:
131
+ color = 'secondary'
132
+ elif status_int <= OptimizationStatus.WAIT_OTHER_WORKERS:
133
+ color = 'primary'
134
+ elif status_int <= OptimizationStatus.RUNNING:
135
+ color = 'primary'
136
+ elif status_int <= OptimizationStatus.INTERRUPTING:
137
+ color = 'warning'
138
+ elif status_int <= OptimizationStatus.TERMINATE_ALL:
139
+ color = 'dark'
140
+ elif status_int <= OptimizationStatus.CRASHED:
141
+ color = 'danger'
142
+ else:
143
+ color = 'danger'
144
+ return color
145
+
146
+
147
+ def g_debug():
148
+ import os
149
+ os.chdir(os.path.dirname(__file__))
150
+
151
+ from pyfemtet.opt._femopt_core import History, OptimizationStatus
152
+
153
+ class _OS(OptimizationStatus):
154
+
155
+ # noinspection PyMissingConstructor
156
+ def __init__(self, name):
157
+ self.name = name
158
+ self.st = self.INITIALIZING
159
+
160
+ def set(self, status_const):
161
+ self.st = status_const
162
+
163
+ def get(self) -> int:
164
+ return self.st
165
+
166
+ def get_text(self) -> int:
167
+ return self.const_to_str(self.st)
168
+
169
+ g_application = ProcessMonitorApplication(
170
+ history=History(history_path=os.path.join(os.path.dirname(__file__), '..', 'result_viewer', 'sample', 'sample.csv')),
171
+ status=_OS('entire'),
172
+ worker_addresses=['worker1', 'worker2', 'worker3'],
173
+ worker_status_list=[_OS('worker1'), _OS('worker2'), _OS('worker3')],
174
+ is_debug=True,
175
+ )
176
+
177
+ g_home_page = HomePage('Progress')
178
+ g_worker_page = WorkerPage('Workers', '/workers', g_application)
179
+
180
+ g_application.add_page(g_home_page, 0)
181
+ g_application.add_page(g_worker_page, 1)
182
+ g_application.setup_callback(debug=False)
183
+
184
+ g_application.run(debug=True)
185
+
186
+
187
+ def main(history, status, worker_addresses, worker_status_list, host=None, port=None):
188
+ g_application = ProcessMonitorApplication(history, status, worker_addresses, worker_status_list)
189
+
190
+ g_home_page = HomePage('Progress')
191
+ g_worker_page = WorkerPage('Workers', '/workers', g_application)
192
+
193
+ g_application.add_page(g_home_page, 0)
194
+ g_application.add_page(g_worker_page, 1)
195
+ g_application.setup_callback()
196
+
197
+ g_application.start_server(host, port)
198
+
199
+
200
+ if __name__ == '__main__':
201
+ g_debug()
@@ -0,0 +1,276 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+
4
+ from dash import Output, Input, State, callback_context, no_update, ALL
5
+ from dash.exceptions import PreventUpdate
6
+
7
+ from pyfemtet.opt.visualization.wrapped_components import dcc, dbc, html
8
+ from pyfemtet.opt.visualization.base import AbstractPage, logger
9
+ from pyfemtet.opt.visualization.complex_components.main_graph import MainGraph # , FLEXBOX_STYLE_ALLOW_VERTICAL_FILL
10
+
11
+
12
+ DBC_COLUMN_STYLE_CENTER = {
13
+ 'display': 'flex',
14
+ 'justify-content': 'center',
15
+ 'align-items': 'center',
16
+ }
17
+
18
+ DBC_COLUMN_STYLE_RIGHT = {
19
+ 'display': 'flex',
20
+ 'justify-content': 'right',
21
+ 'align-items': 'right',
22
+ }
23
+
24
+
25
+ def is_iterable(component):
26
+ return hasattr(component, '__len__')
27
+
28
+
29
+ class HomePage(AbstractPage):
30
+
31
+ def __init__(self, title, rel_url='/'):
32
+ super().__init__(title, rel_url)
33
+
34
+ def setup_component(self):
35
+ # main graph
36
+ # noinspection PyAttributeOutsideInit
37
+ self.main_graph: MainGraph = MainGraph()
38
+ self.add_subpage(self.main_graph)
39
+
40
+ # entire optimization status
41
+ # noinspection PyAttributeOutsideInit
42
+ self.entire_status_message = html.H4(
43
+ 'Optimization status will be shown here.',
44
+ className='alert-heading',
45
+ id='optimization-entire-status-message',
46
+ )
47
+ # noinspection PyAttributeOutsideInit
48
+ self.entire_status = dbc.Alert(
49
+ children=self.entire_status_message,
50
+ id='optimization-entire-status',
51
+ color='secondary',
52
+ )
53
+
54
+ # stop update button
55
+ # noinspection PyAttributeOutsideInit
56
+ self.toggle_update_graph_button = dbc.Checkbox(
57
+ label='Auto-update graph',
58
+ class_name='form-switch',
59
+ id='toggle-update-graph',
60
+ value=True,
61
+ )
62
+
63
+ # interrupt button
64
+ # noinspection PyAttributeOutsideInit
65
+ self.interrupt_button = dbc.Button(
66
+ children='Interrupt Optimization',
67
+ color='danger',
68
+ id='interrupt-optimization-button',
69
+ disabled=True,
70
+ )
71
+
72
+ # sync interval
73
+ # noinspection PyAttributeOutsideInit
74
+ self.interval = dcc.Interval(id='process-monitor-home-interval', interval=1000)
75
+
76
+ def setup_layout(self):
77
+ """"""
78
+ """
79
+ =======================
80
+ | | ---------------- |
81
+ | | | | |
82
+ | | | Main Graph | |
83
+ | | | | |
84
+ | | ---------------- |
85
+ | | [stop][interrupt]<---- Buttons
86
+ | | ---------------- |
87
+ | | | Status | |
88
+ | ^| ---------------- |
89
+ ==|====================
90
+ |
91
+ SideBar
92
+ """
93
+ self.layout = dbc.Container(
94
+ children=[
95
+ self.interval,
96
+ self.main_graph.layout,
97
+ self.entire_status,
98
+ dbc.Row(
99
+ children=[
100
+ dbc.Col(self.toggle_update_graph_button),
101
+ dbc.Col(self.interrupt_button, style=DBC_COLUMN_STYLE_RIGHT),
102
+ ],
103
+ ),
104
+ ]
105
+ )
106
+
107
+ def setup_callback(self):
108
+ # setup callback of subpages
109
+ super().setup_callback()
110
+
111
+ from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
112
+ from pyfemtet.opt._femopt_core import OptimizationStatus
113
+ self.application: ProcessMonitorApplication = self.application
114
+
115
+ app = self.application.app
116
+
117
+ # ===== Delete Loading Animation =====
118
+ @app.callback(
119
+ Output(self.main_graph.loading.id, self.main_graph.loading.Prop.target_components),
120
+ Input(self.main_graph.graph.id, 'figure'),
121
+ prevent_initial_call=True,
122
+ )
123
+ def disable_loading_animation(_):
124
+ return {}
125
+
126
+ # ===== history data to graph ======
127
+ @app.callback(
128
+ Output(self.main_graph.dummy.id, 'children', allow_duplicate=True), # fire update graph callback
129
+ Input(self.interval.id, self.interval.Prop.n_intervals),
130
+ State(self.toggle_update_graph_button.id, self.toggle_update_graph_button.Prop.value),
131
+ State(self.main_graph.data_length.id, self.main_graph.data_length_prop), # check should update or not
132
+ prevent_initial_call=True,)
133
+ def update_graph(_, update_switch, current_graph_data_length):
134
+ logger.debug('====================')
135
+ logger.debug(f'update_graph called by {callback_context.triggered_id}')
136
+
137
+ current_graph_data_length = 0 if current_graph_data_length is None else current_graph_data_length
138
+
139
+ if callback_context.triggered_id is None:
140
+ raise PreventUpdate
141
+
142
+ # update_switch is unchecked, do nothing
143
+ if not update_switch:
144
+ raise PreventUpdate
145
+
146
+ # If new data does not exist, do nothing
147
+ if len(self.application.local_data) <= current_graph_data_length:
148
+ raise PreventUpdate
149
+
150
+ # fire callback
151
+ return ''
152
+
153
+ # ===== show optimization state =====
154
+ @app.callback(
155
+ Output(self.entire_status.id, self.entire_status.Prop.color),
156
+ Output(self.entire_status_message.id, 'children'),
157
+ Input(self.interval.id, self.interval.Prop.n_intervals),
158
+ prevent_initial_call=False,)
159
+ def update_entire_status(*_):
160
+ # get status message
161
+ status_int = self.application.local_entire_status_int
162
+ msg = OptimizationStatus.const_to_str(status_int)
163
+ color = self.application.get_status_color(status_int)
164
+ return color, msg
165
+
166
+ # ===== Interrupt Optimization and Control Button Disabled =====
167
+ @app.callback(
168
+ Output(self.interrupt_button.id, self.interrupt_button.Prop.disabled),
169
+ Input(self.interrupt_button.id, self.interrupt_button.Prop.n_clicks),
170
+ prevent_initial_call=False,)
171
+ def interrupt_optimization(*_):
172
+ # If page (re)loaded,
173
+ if callback_context.triggered_id is None:
174
+ # Enable only if the entire_state < INTERRUPTING
175
+ if self.application.local_entire_status_int < OptimizationStatus.INTERRUPTING:
176
+ return False
177
+ # Keep disable(default) if process is interrupting or terminating.
178
+ else:
179
+ raise PreventUpdate
180
+
181
+ # If the entire_state < INTERRUPTING, set INTERRUPTING
182
+ if self.application.local_entire_status_int < OptimizationStatus.INTERRUPTING:
183
+ self.application.local_entire_status_int = OptimizationStatus.INTERRUPTING
184
+ return True
185
+
186
+ # keep disabled
187
+ raise PreventUpdate
188
+
189
+ # ===== TEST CODE =====
190
+ if self.application.is_debug:
191
+
192
+ # increment status
193
+ self.layout.children.append(dbc.Button(children='local_status を進める', id='debug-button-1'))
194
+
195
+ @app.callback(Output(self.interval.id, self.interval.Prop.interval),
196
+ Input('debug-button-1', 'n_clicks'),
197
+ prevent_initial_call=True)
198
+ def status_change(*_):
199
+ self.application.local_entire_status_int += 10
200
+ for i in range(len(self.application.local_worker_status_int_list)):
201
+ self.application.local_worker_status_int_list[i] += 10
202
+ raise PreventUpdate
203
+
204
+ # increment data
205
+ self.layout.children.append(dbc.Button(children='local_data を増やす', id='debug-button-2'))
206
+
207
+ @app.callback(Output(self.interval.id, self.interval.Prop.interval, allow_duplicate=True),
208
+ Input('debug-button-2', 'n_clicks'),
209
+ prevent_initial_call=True)
210
+ def add_data(*_):
211
+ metadata = self.application.history.metadata
212
+ df = self.application.local_data
213
+
214
+ new_row = df.iloc[-2:]
215
+ obj_index = np.where(np.array(metadata) == 'obj')[0]
216
+ for idx in obj_index:
217
+ new_row.iloc[:, idx] = np.random.rand(len(new_row))
218
+
219
+ df = pd.concat([df, new_row])
220
+ df.trial = np.array(range(len(df)))
221
+ logger.debug(df)
222
+
223
+ self.application.local_data = df
224
+
225
+ raise PreventUpdate
226
+
227
+
228
+ class WorkerPage(AbstractPage):
229
+
230
+ def __init__(self, title, rel_url, application):
231
+ from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
232
+ self.application: ProcessMonitorApplication = None
233
+ super().__init__(title, rel_url, application)
234
+
235
+ def setup_component(self):
236
+ # noinspection PyAttributeOutsideInit
237
+ self.interval = dcc.Interval(id='worker-page-interval', interval=1000)
238
+
239
+ # noinspection PyAttributeOutsideInit
240
+ self.worker_status_alerts = []
241
+ for i in range(len(self.application.worker_addresses)):
242
+ id_worker_alert = f'worker-status-alert-{i}'
243
+ alert = dbc.Alert('worker status here', id=id_worker_alert, color='dark')
244
+ self.worker_status_alerts.append(alert)
245
+
246
+ def setup_layout(self):
247
+ rows = [self.interval]
248
+ rows.extend([dbc.Row([dbc.Col(html.Div(dcc.Loading(alert, id={"type": "loading", "index": i})))]) for i, alert in enumerate(self.worker_status_alerts)])
249
+
250
+ self.layout = dbc.Container(
251
+ children=rows,
252
+ fluid=True,
253
+ )
254
+
255
+ def setup_callback(self):
256
+ app = self.application.app
257
+
258
+ @app.callback(
259
+ [Output(alert.id, 'children') for alert in self.worker_status_alerts],
260
+ [Output(alert.id, 'color') for alert in self.worker_status_alerts],
261
+ Output({"type": "loading", "index": ALL}, "target_components"),
262
+ Input(self.interval.id, 'n_intervals'),
263
+ )
264
+ def update_worker_state(_):
265
+ from pyfemtet.opt._femopt_core import OptimizationStatus
266
+
267
+ ret = []
268
+
269
+ for worker_address, worker_status_int in zip(self.application.worker_addresses, self.application.local_worker_status_int_list):
270
+ worker_status_message = OptimizationStatus.const_to_str(worker_status_int)
271
+ ret.append(f'{worker_address} is {worker_status_message}')
272
+
273
+ ret.extend([self.application.get_status_color(status_int) for status_int in self.application.local_worker_status_int_list])
274
+ ret.append([({} if callback_context.triggered_id is None else no_update) for _ in range(len(self.worker_status_alerts))])
275
+
276
+ return tuple(ret)
@@ -0,0 +1 @@
1
+ sample
File without changes
@@ -0,0 +1,44 @@
1
+ from pyfemtet.opt.visualization.base import PyFemtetApplicationBase
2
+ from pyfemtet.opt.visualization.result_viewer.pages import HomePage
3
+
4
+
5
+ class ResultViewerApplication(PyFemtetApplicationBase):
6
+
7
+ def __init__(self):
8
+ super().__init__(
9
+ title='PyFemtet ResultView',
10
+ subtitle='visualize optimization result',
11
+ history=None,
12
+ )
13
+
14
+ def setup_callback(self):
15
+ super().setup_callback()
16
+
17
+
18
+ def debug():
19
+ import os
20
+ os.chdir(os.path.dirname(__file__))
21
+
22
+ g_application = ResultViewerApplication()
23
+
24
+ g_home_page = HomePage('result')
25
+
26
+ g_application.add_page(g_home_page, 0)
27
+ g_application.setup_callback()
28
+
29
+ g_application.run(debug=True)
30
+
31
+
32
+ def main():
33
+ g_application = ResultViewerApplication()
34
+
35
+ g_home_page = HomePage('result')
36
+
37
+ g_application.add_page(g_home_page, 0)
38
+ g_application.setup_callback()
39
+
40
+ g_application.run()
41
+
42
+
43
+ if __name__ == '__main__':
44
+ debug()