pyfemtet 0.4.12__py3-none-any.whl → 0.4.14__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 (111) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/dispatch_extensions.py +4 -0
  3. pyfemtet/message/1. make_pot.bat +12 -0
  4. pyfemtet/message/2. make_mo.bat +6 -0
  5. pyfemtet/message/__init__.py +5 -0
  6. pyfemtet/message/babel.cfg +2 -0
  7. pyfemtet/message/locales/ja/LC_MESSAGES/messages.po +449 -0
  8. pyfemtet/message/locales/messages.pot +439 -0
  9. pyfemtet/message/messages.py +174 -0
  10. pyfemtet/opt/_femopt.py +9 -9
  11. pyfemtet/opt/_femopt_core.py +22 -17
  12. pyfemtet/opt/femprj_sample/ParametricIF - True.femprj +0 -0
  13. pyfemtet/opt/femprj_sample/ParametricIF.femprj +0 -0
  14. pyfemtet/opt/femprj_sample/ParametricIF.py +31 -0
  15. pyfemtet/opt/femprj_sample/ParametricIF_test_result.reccsv +13 -0
  16. pyfemtet/opt/femprj_sample/cad_ex01_NX_test_result.reccsv +13 -13
  17. pyfemtet/opt/femprj_sample/cad_ex01_SW_test_result.reccsv +13 -13
  18. pyfemtet/opt/femprj_sample/gal_ex58_parametric_test_result.reccsv +13 -13
  19. pyfemtet/opt/femprj_sample/gau_ex08_parametric_test_result.reccsv +23 -23
  20. pyfemtet/opt/femprj_sample/her_ex40_parametric_test_result.reccsv +18 -18
  21. pyfemtet/opt/femprj_sample/paswat_ex1_parametric_test_result.reccsv +18 -18
  22. pyfemtet/opt/femprj_sample/tutorial.femprj +0 -0
  23. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  24. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  25. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
  26. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  27. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
  28. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  29. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  30. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  31. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  32. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  33. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  34. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  35. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  36. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  37. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  38. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  39. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
  40. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  41. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
  42. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  43. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
  44. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  45. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
  46. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  47. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
  48. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  49. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
  50. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  51. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
  52. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  53. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
  54. pyfemtet/opt/femprj_sample/wat_ex14_parametric_test_result.reccsv +18 -18
  55. pyfemtet/opt/femprj_sample_jp/ParametricIF_jp.femprj +0 -0
  56. pyfemtet/opt/femprj_sample_jp/ParametricIF_jp.py +31 -0
  57. pyfemtet/opt/interface/_femtet.py +45 -47
  58. pyfemtet/opt/interface/_femtet_parametric.py +7 -2
  59. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +4 -4
  60. pyfemtet/opt/interface/_femtet_with_nx/update_model.py +6 -6
  61. pyfemtet/opt/interface/_femtet_with_sldworks.py +5 -4
  62. pyfemtet/opt/opt/__init__.py +2 -0
  63. pyfemtet/opt/opt/_base.py +41 -20
  64. pyfemtet/opt/opt/_optuna.py +8 -13
  65. pyfemtet/opt/opt/_scipy.py +4 -8
  66. pyfemtet/opt/opt/_scipy_scalar.py +1 -5
  67. pyfemtet/opt/prediction/__init__.py +0 -0
  68. pyfemtet/opt/prediction/base.py +52 -0
  69. pyfemtet/opt/prediction/single_task_gp.py +82 -0
  70. pyfemtet/opt/visualization/complex_components/control_femtet.py +9 -11
  71. pyfemtet/opt/visualization/complex_components/main_figure_creator.py +24 -11
  72. pyfemtet/opt/visualization/complex_components/main_graph.py +3 -4
  73. pyfemtet/opt/visualization/complex_components/pm_graph.py +715 -0
  74. pyfemtet/opt/visualization/complex_components/pm_graph_creator.py +168 -0
  75. pyfemtet/opt/visualization/process_monitor/application.py +16 -12
  76. pyfemtet/opt/visualization/process_monitor/pages.py +22 -7
  77. pyfemtet/opt/visualization/result_viewer/application.py +8 -3
  78. pyfemtet/opt/visualization/result_viewer/pages.py +59 -47
  79. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/METADATA +2 -1
  80. pyfemtet-0.4.14.dist-info/RECORD +151 -0
  81. pyfemtet/opt/visualization/result_viewer/tutorial/tutorial.csv +0 -18
  82. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.jpg +0 -0
  83. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.log +0 -81
  84. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  85. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow.csv +0 -28
  86. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow_el.csv +0 -22
  87. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  88. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  89. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  90. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  91. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  92. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  93. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  94. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  95. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  96. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  97. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  98. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  99. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  100. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  101. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  102. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  103. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  104. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  105. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  106. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  107. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.femprj +0 -0
  108. pyfemtet-0.4.12.dist-info/RECORD +0 -138
  109. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/LICENSE +0 -0
  110. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/WHEEL +0 -0
  111. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,168 @@
1
+ from typing import Callable, List
2
+
3
+ import torch
4
+ import numpy as np
5
+ import pandas as pd
6
+
7
+ import plotly.graph_objs as go
8
+ import plotly.express as px
9
+
10
+ from pyfemtet.opt._femopt_core import History
11
+
12
+ from pyfemtet.opt.prediction.base import PyFemtetPredictionModel
13
+ from pyfemtet.opt.prediction.single_task_gp import SingleTaskGPModel
14
+ from pyfemtet.message import Msg
15
+
16
+
17
+ class PredictionModelCreator:
18
+
19
+ # noinspection PyAttributeOutsideInit
20
+ def fit(self, history, df):
21
+ # common
22
+ self.history = history # used to check fit or not
23
+ self.df = df
24
+ # method specific
25
+ self.pmm = PyFemtetPredictionModel(history, df, SingleTaskGPModel)
26
+ self.pmm.fit()
27
+
28
+ def create_figure(
29
+ self,
30
+ prm_name_1: str,
31
+ obj_name: str,
32
+ remaining_x: list[float],
33
+ prm_name_2: str = '',
34
+ ):
35
+
36
+ history = self.history
37
+ df = self.df
38
+
39
+ # determine axis1, axis2 range
40
+ lb1 = df[f'{prm_name_1}_lower_bound'].min()
41
+ ub1 = df[f'{prm_name_1}_upper_bound'].max()
42
+ lb1 = df[prm_name_1].min() if np.isnan(lb1) else lb1
43
+ ub1 = df[prm_name_1].max() if np.isnan(ub1) else ub1
44
+ if prm_name_2:
45
+ lb2 = df[f'{prm_name_2}_lower_bound'].min()
46
+ ub2 = df[f'{prm_name_2}_upper_bound'].max()
47
+ lb2 = df[prm_name_2].min() if np.isnan(lb2) else lb2
48
+ ub2 = df[prm_name_2].max() if np.isnan(ub2) else ub2
49
+
50
+ # create grid data
51
+ if prm_name_2:
52
+ N = 20
53
+ x_grid = np.linspace(lb1, ub1, N) # shape: (N,)
54
+ y_grid = np.linspace(lb2, ub2, N)
55
+ xx, yy = np.meshgrid(x_grid, y_grid) # shape: (N, N)
56
+ else:
57
+ N = 100
58
+ xx = np.linspace(lb1, ub1, N) # shape: (N,)
59
+
60
+ # create raveled grid data
61
+ tmp_df = pd.DataFrame(columns=history.prm_names)
62
+ idx = 0
63
+ for prm_name in history.prm_names:
64
+ if prm_name == prm_name_1:
65
+ tmp_df[prm_name_1] = xx.ravel() # shape: (N**2,) or (N,)
66
+ elif prm_name == prm_name_2: # no chance to hit if prm_name_2 == ''
67
+ tmp_df[prm_name_2] = yy.ravel()
68
+ else:
69
+ tmp_df[prm_name] = remaining_x[idx]
70
+ idx += 1
71
+ x = tmp_df.values # shape: (len(prm), N**2)
72
+
73
+ # predict by model
74
+ mean, std = self.pmm.predict(x) # shape: (len(obj), N**2)
75
+
76
+ # create mesh data for graph
77
+ obj_index = history.obj_names.index(obj_name)
78
+ zz_mean = mean[:, obj_index].reshape(xx.shape) # shape: (N**2,) -> (N, N) or (N,) -> (N,)
79
+ zz_std = std[:, obj_index].reshape(xx.shape)
80
+ zz_upper = zz_mean + zz_std
81
+ zz_lower = zz_mean - zz_std
82
+
83
+ # ===== create figure =====
84
+ # description: データ点は多次元空間上の点なので、余剰次元を無視して三次元空間上に投影しても何の意味もない。むしろ混乱するのでやってはいけない。実験的機能として、透明度を設定してみる。
85
+ # calculate distance from super-plane to prm point for opacity of scatter plot
86
+ remaining_prm = list(history.prm_names) # weak copy
87
+ remaining_prm.remove(prm_name_1)
88
+ remaining_prm.remove(prm_name_2) if prm_name_2 in remaining_prm else None
89
+ if len(remaining_prm) > 0:
90
+ super_plane = np.array(remaining_x) # shape: (len(prm_names)-2) or (len(prm_names)-1)
91
+ target_point = df[remaining_prm].values # shape: (len(df), len(prm_names)-2) or (len(df), len(prm_names)-1)
92
+ distance = np.linalg.norm(target_point-super_plane, axis=1, keepdims=False) # shape: (len(df))
93
+ opacity = 1 - (distance / distance.max()) # smaller distance, larger opacity
94
+ else:
95
+ opacity = np.ones(len(df))
96
+
97
+ # scatter plot
98
+ if prm_name_2:
99
+ fig = go.Figure(data=go.Scatter3d(
100
+ x=df[prm_name_1], y=df[prm_name_2], z=df[obj_name],
101
+ mode='markers',
102
+ marker=dict(
103
+ size=3,
104
+ color='black',
105
+ ),
106
+ name='trial',
107
+ ))
108
+ else:
109
+ fig = go.Figure(data=go.Scatter(
110
+ x=df[prm_name_1], y=df[obj_name],
111
+ mode='markers',
112
+ marker=dict(
113
+ color='black',
114
+ ),
115
+ name='trial',
116
+ ))
117
+
118
+ # set opacity by its distance
119
+ def set_opacity(trace):
120
+ trace.marker.color = [f'rgba(0, 0, 0, {o})' for o in opacity]
121
+ fig.for_each_trace(set_opacity)
122
+
123
+ # main RSM
124
+ if prm_name_2:
125
+ contours = dict(
126
+ x=dict(
127
+ highlight=False, show=True, color='blue',
128
+ start=lb1, end=ub1, size=(ub1-lb1)/N,
129
+ ),
130
+ y=dict(
131
+ highlight=False, show=True, color='blue',
132
+ start=lb2, end=ub2, size=(ub1-lb1)/N
133
+ ),
134
+ z=dict(highlight=False, show=False),
135
+ )
136
+ fig.add_trace(go.Surface(z=zz_mean, x=xx, y=yy, contours=contours))
137
+ # std
138
+ fig.add_trace(go.Surface(z=zz_upper, x=xx, y=yy, showscale=False, opacity=0.3))
139
+ fig.add_trace(go.Surface(z=zz_lower, x=xx, y=yy, showscale=False, opacity=0.3))
140
+
141
+ # layout
142
+ fig.update_layout(
143
+ title=Msg.GRAPH_TITLE_PREDICTION_MODEL,
144
+ scene=dict(
145
+ xaxis_title=prm_name_1,
146
+ yaxis_title=prm_name_2,
147
+ zaxis_title=obj_name
148
+ ),
149
+ margin=dict(l=0, r=0, b=0, t=0),
150
+ )
151
+
152
+
153
+ else:
154
+ fig.add_trace(
155
+ go.Scatter(x=xx, y=zz_mean, name=Msg.LEGEND_LABEL_PREDICTION_MODEL)
156
+ )
157
+ # std
158
+ fig.add_trace(
159
+ go.Scatter(
160
+ x=np.concatenate([xx, xx[::-1]]),
161
+ y=np.concatenate([zz_upper, zz_lower[::-1]]),
162
+ opacity=0.3,
163
+ fill='toself',
164
+ name=Msg.LEGEND_LABEL_PREDICTION_MODEL_STDDEV,
165
+ )
166
+ )
167
+
168
+ return fig
@@ -5,7 +5,8 @@ from threading import Thread
5
5
  import pandas as pd
6
6
 
7
7
  from pyfemtet.opt.visualization.base import PyFemtetApplicationBase, logger
8
- from pyfemtet.opt.visualization.process_monitor.pages import HomePage, WorkerPage
8
+ from pyfemtet.opt.visualization.process_monitor.pages import HomePage, WorkerPage, PredictionModelPage
9
+ from pyfemtet.message import Msg
9
10
 
10
11
 
11
12
  class ProcessMonitorApplication(PyFemtetApplicationBase):
@@ -68,7 +69,6 @@ class ProcessMonitorApplication(PyFemtetApplicationBase):
68
69
  else:
69
70
  return self.history.local_data
70
71
 
71
-
72
72
  @local_data.setter
73
73
  def local_data(self, value: pd.DataFrame):
74
74
  if self._should_get_actor_data:
@@ -76,7 +76,6 @@ class ProcessMonitorApplication(PyFemtetApplicationBase):
76
76
  else:
77
77
  self.history.local_data = value
78
78
 
79
-
80
79
  def setup_callback(self, debug=False):
81
80
  if not debug:
82
81
  super().setup_callback()
@@ -124,7 +123,8 @@ class ProcessMonitorApplication(PyFemtetApplicationBase):
124
123
  # interval
125
124
  sleep(1)
126
125
 
127
- def get_status_color(self, status_int):
126
+ @staticmethod
127
+ def get_status_color(status_int):
128
128
  from pyfemtet.opt._femopt_core import OptimizationStatus
129
129
  # set color
130
130
  if status_int <= OptimizationStatus.SETTING_UP:
@@ -171,27 +171,31 @@ def g_debug():
171
171
  status=_OS('entire'),
172
172
  worker_addresses=['worker1', 'worker2', 'worker3'],
173
173
  worker_status_list=[_OS('worker1'), _OS('worker2'), _OS('worker3')],
174
- is_debug=True,
174
+ is_debug=False,
175
175
  )
176
176
 
177
- g_home_page = HomePage('Progress')
178
- g_worker_page = WorkerPage('Workers', '/workers', g_application)
177
+ g_home_page = HomePage(Msg.PAGE_TITLE_PROGRESS)
178
+ g_rsm_page = PredictionModelPage(Msg.PAGE_TITLE_PREDICTION_MODEL, '/prediction-model', g_application)
179
+ g_worker_page = WorkerPage(Msg.PAGE_TITLE_WORKERS, '/workers', g_application)
179
180
 
180
181
  g_application.add_page(g_home_page, 0)
181
- g_application.add_page(g_worker_page, 1)
182
+ g_application.add_page(g_rsm_page, 1)
183
+ g_application.add_page(g_worker_page, 2)
182
184
  g_application.setup_callback(debug=False)
183
185
 
184
- g_application.run(debug=True)
186
+ g_application.run(debug=False)
185
187
 
186
188
 
187
189
  def main(history, status, worker_addresses, worker_status_list, host=None, port=None):
188
190
  g_application = ProcessMonitorApplication(history, status, worker_addresses, worker_status_list)
189
191
 
190
- g_home_page = HomePage('Progress')
191
- g_worker_page = WorkerPage('Workers', '/workers', g_application)
192
+ g_home_page = HomePage(Msg.PAGE_TITLE_PROGRESS)
193
+ g_rsm_page = PredictionModelPage(Msg.PAGE_TITLE_PREDICTION_MODEL, '/prediction-model', g_application)
194
+ g_worker_page = WorkerPage(Msg.PAGE_TITLE_WORKERS, '/workers', g_application)
192
195
 
193
196
  g_application.add_page(g_home_page, 0)
194
- g_application.add_page(g_worker_page, 1)
197
+ g_application.add_page(g_rsm_page, 1)
198
+ g_application.add_page(g_worker_page, 2)
195
199
  g_application.setup_callback()
196
200
 
197
201
  g_application.start_server(host, port)
@@ -7,6 +7,8 @@ from dash.exceptions import PreventUpdate
7
7
  from pyfemtet.opt.visualization.wrapped_components import dcc, dbc, html
8
8
  from pyfemtet.opt.visualization.base import AbstractPage, logger
9
9
  from pyfemtet.opt.visualization.complex_components.main_graph import MainGraph # , FLEXBOX_STYLE_ALLOW_VERTICAL_FILL
10
+ from pyfemtet.opt.visualization.complex_components.pm_graph import PredictionModelGraph
11
+ from pyfemtet.message import Msg
10
12
 
11
13
 
12
14
  DBC_COLUMN_STYLE_CENTER = {
@@ -40,7 +42,7 @@ class HomePage(AbstractPage):
40
42
  # entire optimization status
41
43
  # noinspection PyAttributeOutsideInit
42
44
  self.entire_status_message = html.H4(
43
- 'Optimization status will be shown here.',
45
+ Msg.DEFAULT_STATUS_ALERT,
44
46
  className='alert-heading',
45
47
  id='optimization-entire-status-message',
46
48
  )
@@ -54,7 +56,7 @@ class HomePage(AbstractPage):
54
56
  # stop update button
55
57
  # noinspection PyAttributeOutsideInit
56
58
  self.toggle_update_graph_button = dbc.Checkbox(
57
- label='Auto-update graph',
59
+ label=Msg.LABEL_AUTO_UPDATE,
58
60
  class_name='form-switch',
59
61
  id='toggle-update-graph',
60
62
  value=True,
@@ -63,7 +65,7 @@ class HomePage(AbstractPage):
63
65
  # interrupt button
64
66
  # noinspection PyAttributeOutsideInit
65
67
  self.interrupt_button = dbc.Button(
66
- children='Interrupt Optimization',
68
+ children=Msg.LABEL_INTERRUPT,
67
69
  color='danger',
68
70
  id='interrupt-optimization-button',
69
71
  disabled=True,
@@ -71,7 +73,7 @@ class HomePage(AbstractPage):
71
73
 
72
74
  # sync interval
73
75
  # noinspection PyAttributeOutsideInit
74
- self.interval = dcc.Interval(id='process-monitor-home-interval', interval=1000)
76
+ self.interval = dcc.Interval(id='process-monitor-home-interval', interval=3000)
75
77
 
76
78
  def setup_layout(self):
77
79
  """"""
@@ -131,9 +133,6 @@ class HomePage(AbstractPage):
131
133
  State(self.main_graph.data_length.id, self.main_graph.data_length_prop), # check should update or not
132
134
  prevent_initial_call=True,)
133
135
  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
136
  current_graph_data_length = 0 if current_graph_data_length is None else current_graph_data_length
138
137
 
139
138
  if callback_context.triggered_id is None:
@@ -274,3 +273,19 @@ class WorkerPage(AbstractPage):
274
273
  ret.append([({} if callback_context.triggered_id is None else no_update) for _ in range(len(self.worker_status_alerts))])
275
274
 
276
275
  return tuple(ret)
276
+
277
+
278
+ class PredictionModelPage(AbstractPage):
279
+ """"""
280
+
281
+ def __init__(self, title, rel_url, application):
282
+ from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
283
+ self.application: ProcessMonitorApplication = None
284
+ super().__init__(title, rel_url, application)
285
+
286
+ def setup_component(self):
287
+ self.rsm_graph: PredictionModelGraph = PredictionModelGraph()
288
+ self.add_subpage(self.rsm_graph)
289
+
290
+ def setup_layout(self):
291
+ self.layout = self.rsm_graph.layout
@@ -1,5 +1,6 @@
1
1
  from pyfemtet.opt.visualization.base import PyFemtetApplicationBase
2
- from pyfemtet.opt.visualization.result_viewer.pages import HomePage
2
+ from pyfemtet.opt.visualization.result_viewer.pages import HomePage, PredictionModelPage
3
+ from pyfemtet.message import Msg
3
4
 
4
5
 
5
6
  class ResultViewerApplication(PyFemtetApplicationBase):
@@ -21,9 +22,11 @@ def debug():
21
22
 
22
23
  g_application = ResultViewerApplication()
23
24
 
24
- g_home_page = HomePage('result')
25
+ g_home_page = HomePage(Msg.PAGE_TITLE_RESULT)
26
+ g_rsm_page = PredictionModelPage(Msg.PAGE_TITLE_PREDICTION_MODEL, '/prediction-model', g_application)
25
27
 
26
28
  g_application.add_page(g_home_page, 0)
29
+ g_application.add_page(g_rsm_page, 1)
27
30
  g_application.setup_callback()
28
31
 
29
32
  g_application.run(debug=True)
@@ -32,9 +35,11 @@ def debug():
32
35
  def main():
33
36
  g_application = ResultViewerApplication()
34
37
 
35
- g_home_page = HomePage('result')
38
+ g_home_page = HomePage(Msg.PAGE_TITLE_RESULT)
39
+ g_rsm_page = PredictionModelPage(Msg.PAGE_TITLE_PREDICTION_MODEL, '/prediction-model', g_application)
36
40
 
37
41
  g_application.add_page(g_home_page, 0)
42
+ g_application.add_page(g_rsm_page, 1)
38
43
  g_application.setup_callback()
39
44
 
40
45
  g_application.run()
@@ -15,9 +15,12 @@ from pyfemtet.opt.visualization.base import AbstractPage # , logger
15
15
  from pyfemtet.opt.visualization.complex_components.main_graph import MainGraph # , FLEXBOX_STYLE_ALLOW_VERTICAL_FILL
16
16
  from pyfemtet.opt.visualization.complex_components.control_femtet import FemtetControl, FemtetState
17
17
  from pyfemtet.opt.visualization.complex_components.alert_region import AlertRegion
18
+ from pyfemtet.opt.visualization.complex_components.pm_graph import PredictionModelGraph
18
19
 
19
20
  from pyfemtet.opt._femopt_core import History
20
21
 
22
+ from pyfemtet.message import Msg
23
+
21
24
 
22
25
  class HomePage(AbstractPage):
23
26
 
@@ -43,7 +46,7 @@ class HomePage(AbstractPage):
43
46
 
44
47
  # open pdt (or transfer variable to femtet)
45
48
  self.open_pdt_button = dbc.Button(
46
- 'Open Result in Femtet',
49
+ Msg.LABEL_OPEN_PDT_BUTTON,
47
50
  id='open-pdt-button',
48
51
  color='primary',
49
52
  className="position-relative", # need to show badge
@@ -51,14 +54,14 @@ class HomePage(AbstractPage):
51
54
 
52
55
  # update parameter
53
56
  self.update_parameter_button = dbc.Button(
54
- 'Reconstruct Model',
57
+ Msg.LABEL_RECONSTRUCT_MODEL_BUTTON,
55
58
  id='update-parameter-button',
56
59
  color='secondary',
57
60
  )
58
61
 
59
62
  # file picker
60
63
  self.file_picker_button = dbc.Button(
61
- 'drag and drop or select files',
64
+ Msg.LABEL_FILE_PICKER,
62
65
  id='file-picker-button',
63
66
  color='primary',
64
67
  )
@@ -169,14 +172,13 @@ class HomePage(AbstractPage):
169
172
  # check Femtet state
170
173
  connection_state = self.femtet_control.check_femtet_state()
171
174
  if connection_state == FemtetState.missing or connection_state == FemtetState.unconnected:
172
- msg = ('Connection to Femtet is not established. '
173
- 'Launch Femtet and Open a project.')
175
+ msg = Msg.ERR_NO_CONNECTION_ESTABLISHED
174
176
  alerts = self.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
175
177
  return alerts
176
178
 
177
179
  # check selection
178
180
  if selection_data is None:
179
- msg = 'No result plot is selected.'
181
+ msg = Msg.ERR_NO_SOLUTION_SELECTED
180
182
  alerts = self.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
181
183
  return alerts
182
184
 
@@ -187,12 +189,12 @@ class HomePage(AbstractPage):
187
189
 
188
190
  # check metadata is valid
189
191
  if femprj_path is None:
190
- msg = 'The femprj file path in the history csv is not found or valid. '
192
+ msg = Msg.ERR_FEMPRJ_IN_CSV_NOT_FOUND
191
193
  alerts = self.alert_region.create_alerts(msg, color='danger')
192
194
  return alerts
193
195
 
194
196
  if model_name is None:
195
- msg = 'The model name in the history csv is not found.'
197
+ msg = Msg.ERR_MODEL_IN_CSV_NOT_FOUND
196
198
  alerts = self.alert_region.create_alerts(msg, color='danger')
197
199
  return alerts
198
200
 
@@ -218,7 +220,7 @@ class HomePage(AbstractPage):
218
220
  succeed = Femtet.OpenPDT(pdt_path, True)
219
221
 
220
222
  if not succeed:
221
- msg = f'Failed to open {pdt_path}.'
223
+ msg = Msg.ERR_FAILED_TO_OPEN_PREFIX + pdt_path
222
224
  alerts = self.alert_region.create_alerts(msg, color='danger')
223
225
  return alerts
224
226
 
@@ -237,27 +239,23 @@ class HomePage(AbstractPage):
237
239
  # check Femtet state
238
240
  connection_state = self.femtet_control.check_femtet_state()
239
241
  if connection_state != FemtetState.connected:
240
- msg = ('Connection to Femtet is not established. '
241
- 'Launch Femtet and Open a project.')
242
+ msg = Msg.ERR_NO_CONNECTION_ESTABLISHED
242
243
  alerts = self.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
243
244
  return alerts
244
245
 
245
246
  # check selection
246
247
  if selection_data is None:
247
- msg = 'No result plot is selected.'
248
+ msg = Msg.ERR_NO_SOLUTION_SELECTED
248
249
  alerts = self.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
249
250
  return alerts
250
251
 
251
252
  try:
252
253
  Femtet = self.femtet_control.fem.Femtet
253
254
 
254
-
255
255
  # check model to open is included in current project
256
256
  if (self.femtet_control.fem.femprj_path != Femtet.Project) \
257
257
  or (self.femtet_control.fem.model_name not in Femtet.GetAnalysisModelNames_py()):
258
- msg = (f'{self.femtet_control.fem.model_name} is not in current project. '
259
- f'Please check opened project. '
260
- f'For example, not "analysis model only" but your .femprj file.')
258
+ msg = Msg.ERR_NO_SUCH_MODEL_IN_FEMPRJ + f' model name: {self.femtet_control.fem.model_name}'
261
259
  alerts = self.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
262
260
  return alerts
263
261
 
@@ -362,19 +360,19 @@ class HomePage(AbstractPage):
362
360
  # alert
363
361
  new_alerts = current_alerts
364
362
  if femprj_path_history_on_history is None:
365
- msg = '.femprj file path of the history csv is invalid. Please certify matching between csv and opening .femprj file.'
363
+ msg = Msg.WARN_INCONSISTENT_FEMPRJ_PATH
366
364
  new_alerts = self.alert_region.create_alerts(msg, 'warning', new_alerts)
367
365
  else:
368
366
  if not is_same_femprj:
369
- msg = '.femprj file path of the history csv and opened in Femtet is inconsistent. Please certify matching between csv and .femprj file.'
367
+ msg = Msg.WARN_INCONSISTENT_FEMPRJ_PATH
370
368
  new_alerts = self.alert_region.create_alerts(msg, 'warning', new_alerts)
371
369
 
372
370
  if model_name_on_history is None:
373
- msg = 'Analysis model name of the history csv is invalid. Please certify matching between csv and opening analysis model.'
371
+ msg = Msg.WARN_INVALID_MODEL_NAME
374
372
  new_alerts = self.alert_region.create_alerts(msg, 'warning', new_alerts)
375
373
  else:
376
374
  if not is_same_model:
377
- msg = 'Analysis model name of the history csv and opened in Femtet is inconsistent. Please certify matching between csv and opening analysis model.'
375
+ msg = Msg.WARN_INCONSISTENT_MODEL_NAME
378
376
  new_alerts = self.alert_region.create_alerts(msg, 'warning', new_alerts)
379
377
 
380
378
  if new_alerts == current_alerts:
@@ -408,7 +406,7 @@ class Tutorial(AbstractPage):
408
406
 
409
407
  # switch tutorial mode (always visible)
410
408
  self.tutorial_mode_switch = dbc.Checklist(
411
- ['tutorial mode'],
409
+ [Msg.LABEL_TUTORIAL_MODE_SWITCH],
412
410
  id='tutorial-mode-switch',
413
411
  switch=True,
414
412
  value=False
@@ -417,17 +415,14 @@ class Tutorial(AbstractPage):
417
415
  # load sample csv
418
416
  self.load_sample_csv_badge = self.create_badge('Click Me!', 'load-sample-csv-badge')
419
417
  self.load_sample_csv_button = dbc.Button(
420
- children=['Load sample csv', self.load_sample_csv_badge],
418
+ children=[Msg.LABEL_LOAD_SAMPLE_CSV, self.load_sample_csv_badge],
421
419
  id='load-sample-csv-button',
422
420
  className="position-relative", # need to show badge
423
421
  )
424
422
  self.load_sample_csv_popover = dbc.Popover(
425
423
  children=[
426
- dbc.PopoverHeader('Load CSV'),
427
- dbc.PopoverBody(
428
- 'Open your optimization result. Then connecting to femtet will start automatically. '
429
- 'Note that in tutorial mode, this button loads the ready-made sample csv and open sample femprj.'
430
- ),
424
+ dbc.PopoverHeader(Msg.LOAD_CSV_POPOVER_HEADER),
425
+ dbc.PopoverBody(Msg.LOAD_CSV_POPOVER_BODY),
431
426
  ],
432
427
  id='load-sample-csv-popover',
433
428
  target=self.load_sample_csv_button.id,
@@ -444,12 +439,10 @@ class Tutorial(AbstractPage):
444
439
  self.graph_badge = self.create_badge('Choose a Point!', 'graph-badge')
445
440
  self.graph_popover = dbc.Popover(
446
441
  children=[
447
- dbc.PopoverHeader('Main Graph'),
442
+ dbc.PopoverHeader(Msg.MAIN_GRAPH_POPOVER_HEADER),
448
443
  dbc.PopoverBody(
449
444
  children=[
450
- 'Here the optimization history is shown. '
451
- 'Each plot represents single FEM result. '
452
- 'You can pick a result to open the corresponding result in Femtet. ',
445
+ Msg.MAIN_GRAPH_POPOVER_BODY,
453
446
  self.graph_badge
454
447
  ],
455
448
  className="position-relative", # need to show badge
@@ -459,17 +452,15 @@ class Tutorial(AbstractPage):
459
452
  target=self.main_graph.tabs.id,
460
453
  is_open=False,
461
454
  placement='bottom',
455
+ hide_arrow=True,
462
456
  )
463
457
 
464
458
  # popover and badge of open pdt
465
459
  self.open_pdt_badge = self.create_badge('Click Me!', 'open-pdt-badge')
466
460
  self.open_pdt_popover = dbc.Popover(
467
461
  children=[
468
- dbc.PopoverHeader('Open Result'),
469
- dbc.PopoverBody(
470
- 'After pick a point in the main graph, '
471
- 'This button shows the corresponding FEM result in Femtet.'
472
- ),
462
+ dbc.PopoverHeader(Msg.OPEN_PDT_POPOVER_HEADER),
463
+ dbc.PopoverBody(Msg.OPEN_PDT_POPOVER_BODY),
473
464
  ],
474
465
  id='open-pdt-popover',
475
466
  target=self.home_page.open_pdt_button.id,
@@ -479,7 +470,7 @@ class Tutorial(AbstractPage):
479
470
  # popover of connect-femtet
480
471
  self.connect_femtet_popover = dbc.Popover(
481
472
  children=[
482
- dbc.PopoverBody('You can re-make connection to Femtet if it misses.'),
473
+ dbc.PopoverBody(Msg.CONNECT_FEMTET_POPOVER_BODY),
483
474
  ],
484
475
  id='connect-femtet-popover',
485
476
  target=self.femtet_control.connect_femtet_button.id,
@@ -487,7 +478,6 @@ class Tutorial(AbstractPage):
487
478
  placement='bottom',
488
479
  )
489
480
 
490
-
491
481
  def setup_layout(self):
492
482
  pass
493
483
 
@@ -624,28 +614,34 @@ class Tutorial(AbstractPage):
624
614
  if callback_context.triggered_id is None:
625
615
  raise PreventUpdate
626
616
 
627
- path = os.path.join(os.path.dirname(__file__), 'tutorial', 'tutorial.csv')
617
+ # get sample file
618
+ import pyfemtet
619
+ package_root = os.path.dirname(pyfemtet.__file__)
620
+ sample_dir = os.path.join(package_root, 'opt', 'femprj_sample') # FIXME: locale によってパスを変える
621
+ path = os.path.join(sample_dir, 'wat_ex14_parametric_test_result.reccsv')
628
622
 
629
623
  if not os.path.exists(path):
630
- msg = 'Sample csv is not found. Please consider to re-install pyfemtet by `py -m pip install pyfemtet -U --force-reinstall`'
624
+ msg = Msg.ERR_SAMPLE_CSV_NOT_FOUND
631
625
  alerts = self.home_page.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
632
626
  return no_update, no_update, no_update, alerts
633
- self.application.history = History(path)
627
+ destination_file = path.replace('wat_ex14_parametric_test_result.reccsv', 'tutorial.csv')
628
+ shutil.copyfile(path, destination_file)
629
+ self.application.history = History(destination_file)
634
630
 
635
- source_file = path.replace('tutorial.csv', 'wat_ex14_parametric.femprj')
631
+ source_file = path.replace('_test_result.reccsv', '.femprj')
636
632
  if not os.path.exists(source_file):
637
- msg = 'Sample femprj file is not found. Please consider to re-install pyfemtet by `py -m pip install pyfemtet -U --force-reinstall`'
633
+ msg = Msg.ERR_SAMPLE_FEMPRJ_NOT_FOUND
638
634
  alerts = self.home_page.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
639
635
  return no_update, no_update, no_update, alerts
640
- destination_file = path.replace('tutorial.csv', 'tutorial.femprj')
636
+ destination_file = source_file.replace('wat_ex14_parametric', 'tutorial')
641
637
  shutil.copyfile(source_file, destination_file)
642
638
 
643
- source_folder = path.replace('tutorial.csv', 'wat_ex14_parametric.Results')
639
+ source_folder = path.replace('_test_result.reccsv', '.Results')
644
640
  if not os.path.exists(source_file):
645
- msg = 'Sample femprj result folder is not found. Please consider to re-install pyfemtet by `py -m pip install pyfemtet -U --force-reinstall`'
641
+ msg = Msg.ERR_FEMPRJ_RESULT_NOT_FOUND
646
642
  alerts = self.home_page.alert_region.create_alerts(msg, color='danger', current_alerts=current_alerts)
647
643
  return no_update, no_update, no_update, alerts
648
- destination_folder = path.replace('tutorial.csv', 'tutorial.Results')
644
+ destination_folder = source_folder.replace('wat_ex14_parametric', 'tutorial')
649
645
  shutil.copytree(source_folder, destination_folder, dirs_exist_ok=True)
650
646
 
651
647
  self.application.history.metadata[0] = json.dumps(
@@ -690,3 +686,19 @@ class Tutorial(AbstractPage):
690
686
  else:
691
687
  current_style.update(part)
692
688
  return current_style
689
+
690
+
691
+ class PredictionModelPage(AbstractPage):
692
+ """"""
693
+
694
+ def __init__(self, title, rel_url, application):
695
+ from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
696
+ self.application: ProcessMonitorApplication = None
697
+ super().__init__(title, rel_url, application)
698
+
699
+ def setup_component(self):
700
+ self.rsm_graph: PredictionModelGraph = PredictionModelGraph()
701
+ self.add_subpage(self.rsm_graph)
702
+
703
+ def setup_layout(self):
704
+ self.layout = self.rsm_graph.layout
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyfemtet
3
- Version: 0.4.12
3
+ Version: 0.4.14
4
4
  Summary: Design parameter optimization using Femtet.
5
5
  Home-page: https://github.com/pyfemtet/pyfemtet
6
6
  License: BSD-3-Clause
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Dist: babel (>=2.15.0,<3.0.0)
15
16
  Requires-Dist: botorch (>=0.9.5) ; python_version >= "3.12" and python_version < "3.13"
16
17
  Requires-Dist: botorch (>=0.9.5,<0.10.0) ; python_version < "3.12"
17
18
  Requires-Dist: colorlog (>=6.8.0,<7.0.0)