pyfemtet 0.4.9__py3-none-any.whl → 0.4.11__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 (73) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/opt/_femopt.py +9 -3
  3. pyfemtet/opt/femprj_sample/wat_ex14_parametric_parallel.py +66 -0
  4. pyfemtet/opt/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py +64 -0
  5. pyfemtet/opt/interface/_femtet.py +32 -10
  6. pyfemtet/opt/interface/_femtet_parametric.py +5 -25
  7. pyfemtet/opt/opt/_base.py +9 -1
  8. pyfemtet/opt/opt/_optuna.py +4 -0
  9. pyfemtet/opt/visualization/__init__.py +0 -7
  10. pyfemtet/opt/visualization/_create_wrapped_components.py +93 -0
  11. pyfemtet/opt/visualization/base.py +254 -0
  12. pyfemtet/opt/visualization/complex_components/__init__.py +0 -0
  13. pyfemtet/opt/visualization/complex_components/alert_region.py +71 -0
  14. pyfemtet/opt/visualization/complex_components/control_femtet.py +195 -0
  15. pyfemtet/opt/visualization/{_graphs.py → complex_components/main_figure_creator.py} +13 -49
  16. pyfemtet/opt/visualization/complex_components/main_graph.py +263 -0
  17. pyfemtet/opt/visualization/process_monitor/__init__.py +0 -0
  18. pyfemtet/opt/visualization/process_monitor/application.py +201 -0
  19. pyfemtet/opt/visualization/process_monitor/pages.py +276 -0
  20. pyfemtet/opt/visualization/result_viewer/.gitignore +1 -0
  21. pyfemtet/opt/visualization/result_viewer/__init__.py +0 -0
  22. pyfemtet/opt/visualization/result_viewer/application.py +44 -0
  23. pyfemtet/opt/visualization/result_viewer/pages.py +692 -0
  24. pyfemtet/opt/visualization/result_viewer/tutorial/tutorial.csv +18 -0
  25. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.jpg +0 -0
  26. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.log +81 -0
  27. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  28. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow.csv +28 -0
  29. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow_el.csv +22 -0
  30. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  31. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
  32. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  33. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
  34. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  35. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  36. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  37. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  38. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  39. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  40. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  41. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  42. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  43. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  44. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  45. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
  46. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  47. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
  48. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  49. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
  50. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  51. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
  52. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  53. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
  54. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  55. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
  56. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  57. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
  58. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  59. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
  60. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.femprj +0 -0
  61. pyfemtet/opt/visualization/wrapped_components/__init__.py +0 -0
  62. pyfemtet/opt/visualization/wrapped_components/dbc.py +1518 -0
  63. pyfemtet/opt/visualization/wrapped_components/dcc.py +609 -0
  64. pyfemtet/opt/visualization/wrapped_components/html.py +3570 -0
  65. pyfemtet/opt/visualization/wrapped_components/str_enum.py +43 -0
  66. {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/METADATA +1 -1
  67. pyfemtet-0.4.11.dist-info/RECORD +136 -0
  68. {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/entry_points.txt +1 -1
  69. pyfemtet/opt/visualization/_monitor.py +0 -1227
  70. pyfemtet/opt/visualization/result_viewer.py +0 -13
  71. pyfemtet-0.4.9.dist-info/RECORD +0 -81
  72. {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/LICENSE +0 -0
  73. {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/WHEEL +0 -0
@@ -0,0 +1,263 @@
1
+ # type hint
2
+ from dash.development.base_component import Component
3
+
4
+ # callback
5
+ from dash import Output, Input, State, no_update, callback_context
6
+ from dash.exceptions import PreventUpdate
7
+
8
+ # components
9
+ from dash import dash_table
10
+ from pyfemtet.opt.visualization.wrapped_components import html, dcc, dbc
11
+
12
+ # graph
13
+ import pandas as pd
14
+ # import plotly.express as px
15
+ import plotly.graph_objs as go
16
+
17
+ # the others
18
+ import os
19
+ import base64
20
+ import json
21
+ import numpy as np
22
+
23
+ from pyfemtet.opt.visualization.complex_components import main_figure_creator
24
+ from pyfemtet.opt.visualization.base import PyFemtetApplicationBase, AbstractPage, logger
25
+
26
+
27
+ FLEXBOX_STYLE_ALLOW_VERTICAL_FILL = {
28
+ 'display': 'flex',
29
+ 'flex-direction': 'column',
30
+ 'flex-grow': '1',
31
+ }
32
+
33
+
34
+ # noinspection PyAttributeOutsideInit
35
+ class MainGraph(AbstractPage):
36
+ """"""
37
+ """
38
+ +=================+
39
+ |tab1|tab2| | <- CardHeader
40
+ | +------------+
41
+ | +-------------+ |
42
+ | | Loading | | <- CardBody
43
+ | | +---------+ | |
44
+ | | | graph <-------- ToolTip
45
+ | | +---------+ | |
46
+ | +-------------+ |
47
+ +=================+
48
+
49
+ Data(data-selection)
50
+
51
+ """
52
+
53
+ def __init__(self):
54
+ self.setup_figure_creator()
55
+ super().__init__()
56
+
57
+ def setup_figure_creator(self):
58
+ # setup figure creators
59
+ # list[0] is the default tab
60
+ self.figure_creators = [
61
+ dict(
62
+ tab_id='tab-objective-plot',
63
+ label='objectives',
64
+ creator=main_figure_creator.get_default_figure,
65
+ ),
66
+ dict(
67
+ tab_id='tab-hypervolume-plot',
68
+ label='hypervolume',
69
+ creator=main_figure_creator.get_hypervolume_plot,
70
+ ),
71
+ ]
72
+
73
+ def setup_component(self):
74
+ self.dummy = html.Div(id='main-graph-dummy')
75
+ self.location = dcc.Location(id='main-graph-location', refresh=True)
76
+
77
+ # setup header
78
+ self.tab_list = [dbc.Tab(label=d['label'], tab_id=d['tab_id']) for d in self.figure_creators]
79
+ self.tabs = dbc.Tabs(self.tab_list, id='main-graph-tabs')
80
+ self.card_header = dbc.CardHeader(self.tabs)
81
+
82
+ # setup body
83
+ self.tooltip = dcc.Tooltip(id='main-graph-tooltip')
84
+
85
+ # set kwargs of Graph to reconstruct Graph in ProcessMonitor.
86
+ self.graph_kwargs = dict(
87
+ id='main-graph',
88
+ # animate=True, # THIS CAUSE THE UPDATED DATA / NOT-UPDATED FIGURE STATE.
89
+ clear_on_unhover=True,
90
+ style={
91
+ # 'flex-grow': '1', # Uncomment if the plotly's specification if fixed, and we can use dcc.Graph with FlexBox.
92
+ 'height': '60vh',
93
+ },
94
+ figure=go.Figure()
95
+ )
96
+
97
+ self.graph: dcc.Graph = dcc.Graph(
98
+ **self.graph_kwargs
99
+ ) # Graph make an element by js, so Flexbox CSS cannot apply to the graph (The element can be bigger, but cannot be smaller.)
100
+
101
+ self.loading = dcc.Loading(
102
+ children=self.graph,
103
+ id='loading-main-graph',
104
+ ) # Loading make an element that doesn't contain a style attribute, so Flexbox CSS cannot apply to the graph
105
+
106
+ self.card_body = dbc.CardBody(
107
+ children=html.Div([self.loading, self.tooltip]), # If list is passed to CardBody's children, create element that doesn't contain a style attribute, so Flexbox CSS cannot apply to graph
108
+ id='main-graph-card-body',
109
+ # style=FLEXBOX_STYLE_ALLOW_VERTICAL_FILL,
110
+ )
111
+
112
+ # setup selection data
113
+ self.selection_data_property = 'data-selection' # must be starts with "data-"
114
+ self.selection_data = html.Data(id='selection-data', **{self.selection_data_property: {}})
115
+
116
+ # set data length
117
+ self.data_length_prop = 'data-df-length' # must start with "data-"
118
+ self.data_length = html.Data(id='df-length-data', **{self.data_length_prop: None})
119
+
120
+ def setup_layout(self):
121
+ # setup component
122
+ self.graph_card = dbc.Card(
123
+ [
124
+ self.dummy,
125
+ self.location,
126
+ self.data_length,
127
+ self.card_header,
128
+ self.card_body,
129
+ self.selection_data,
130
+ ],
131
+ # style=FLEXBOX_STYLE_ALLOW_VERTICAL_FILL,
132
+ )
133
+
134
+ self.layout = self.graph_card
135
+
136
+ def setup_callback(self):
137
+ # setup callback of subpages
138
+ super().setup_callback()
139
+
140
+ app = self.application.app
141
+
142
+ # ===== Update Graph =====
143
+ @app.callback(
144
+ Output(self.graph.id, 'figure'),
145
+ Output(self.data_length.id, self.data_length_prop), # To determine whether Process Monitor should update the graph, the main graph remembers the current amount of data.
146
+ Input(self.tabs.id, 'active_tab'),
147
+ Input(self.dummy, 'children'),
148
+ prevent_initial_call=False,)
149
+ def redraw_main_graph(active_tab_id, _):
150
+ logger.debug('====================')
151
+ logger.debug(f'redraw_main_graph called by {callback_context.triggered_id}')
152
+ figure, length = self.get_fig_by_tab_id(active_tab_id, with_length=True)
153
+ return figure, length
154
+
155
+ # ===== Save Selection =====
156
+ @app.callback(
157
+ Output(self.selection_data.id, self.selection_data_property),
158
+ Input(self.graph.id, 'selectedData'))
159
+ def save_selection(data):
160
+ return data
161
+
162
+ # ===== Show Image and Parameter on Hover =====
163
+ @app.callback(
164
+ Output(self.tooltip.id, "show"),
165
+ Output(self.tooltip.id, "bbox"),
166
+ Output(self.tooltip.id, "children"),
167
+ Input(self.graph.id, "hoverData"),)
168
+ def show_hover(hoverData):
169
+ if hoverData is None:
170
+ return False, no_update, no_update
171
+
172
+ if self.application.history is None:
173
+ raise PreventUpdate
174
+
175
+ # get hover location
176
+ pt = hoverData["points"][0]
177
+ bbox = pt["bbox"]
178
+
179
+ # get row of the history from customdata defined in main_figure
180
+ trial = pt['customdata'][0]
181
+
182
+ df = self.data_accessor()
183
+ row = df[df['trial'] == trial]
184
+
185
+ # create component
186
+ title_component = html.H3(f"trial{trial}", style={"color": "darkblue"})
187
+ img_component = self.create_image_content_if_femtet(trial)
188
+ tbl_component = self.create_formatted_parameter(row)
189
+
190
+ # create layout
191
+ description = html.Div([
192
+ title_component,
193
+ tbl_component,
194
+ ])
195
+ tooltip_layout = html.Div([
196
+ html.Div(img_component, style={'display': 'inline-block', 'margin-right': '10px', 'vertical-align': 'top'}),
197
+ html.Div(description, style={'display': 'inline-block', 'margin-right': '10px'})
198
+ ])
199
+
200
+ return True, bbox, tooltip_layout
201
+
202
+ def create_formatted_parameter(self, row) -> Component:
203
+ metadata = self.application.history.metadata
204
+ pd.options.display.float_format = '{:.4e}'.format
205
+ parameters = row.iloc[:, np.where(np.array(metadata) == 'prm')[0]]
206
+ names = parameters.columns
207
+ values = [f'{value:.3e}' for value in parameters.values.ravel()]
208
+ data = pd.DataFrame(dict(
209
+ name=names, value=values
210
+ ))
211
+ table = dash_table.DataTable(
212
+ columns=[{'name': col, 'id': col} for col in data.columns],
213
+ data=data.to_dict('records')
214
+ )
215
+ return table
216
+
217
+ def create_image_content_if_femtet(self, trial) -> Component:
218
+ img_url = None
219
+ metadata = self.application.history.metadata
220
+ if metadata[0] != '':
221
+ # get img path
222
+ d = json.loads(metadata[0])
223
+ femprj_path = d['femprj_path']
224
+ model_name = d['model_name']
225
+ femprj_result_dir = femprj_path.replace('.femprj', '.Results')
226
+ img_path = os.path.join(femprj_result_dir, f'{model_name}_trial{trial}.jpg')
227
+ if os.path.exists(img_path):
228
+ # create encoded image
229
+ with open(img_path, 'rb') as f:
230
+ content = f.read()
231
+ encoded_image = base64.b64encode(content).decode('utf-8')
232
+ img_url = 'data:image/jpeg;base64, ' + encoded_image
233
+ return html.Img(src=img_url, style={"width": "200px"}) if img_url is not None else html.Div()
234
+
235
+ def get_fig_by_tab_id(self, tab_id, with_length=False):
236
+ # If the history is not loaded, do nothing
237
+ if self.application.history is None:
238
+ raise PreventUpdate
239
+
240
+ # else, get creator by tab_id
241
+ if tab_id == 'default':
242
+ creator = self.figure_creators[0]['creator']
243
+ else:
244
+ creators = [d['creator'] for d in self.figure_creators if d['tab_id'] == tab_id]
245
+ if len(creators) == 0:
246
+ raise PreventUpdate
247
+ creator = creators[0]
248
+
249
+ # create figure
250
+ df = self.data_accessor()
251
+ fig = creator(self.application.history, df)
252
+ if with_length:
253
+ return fig, len(df)
254
+ else:
255
+ return fig
256
+
257
+ def data_accessor(self) -> pd.DataFrame:
258
+ from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
259
+ if isinstance(self.application, ProcessMonitorApplication):
260
+ df = self.application.local_data
261
+ else:
262
+ df = self.application.history.local_data
263
+ return df
File without changes
@@ -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()