pyfemtet 0.7.0__py3-none-any.whl → 0.8.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.

Potentially problematic release.


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

Files changed (46) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/_message/locales/ja/LC_MESSAGES/messages.mo +0 -0
  3. pyfemtet/_message/locales/ja/LC_MESSAGES/messages.po +112 -90
  4. pyfemtet/_message/locales/messages.pot +105 -89
  5. pyfemtet/_message/messages.py +6 -2
  6. pyfemtet/_util/dask_util.py +10 -0
  7. pyfemtet/_util/excel_macro_util.py +16 -4
  8. pyfemtet/_util/excel_parse_util.py +138 -0
  9. pyfemtet/_util/sample.xlsx +0 -0
  10. pyfemtet/brep/__init__.py +0 -3
  11. pyfemtet/brep/_impl.py +7 -3
  12. pyfemtet/opt/_femopt.py +69 -31
  13. pyfemtet/opt/_femopt_core.py +100 -36
  14. pyfemtet/opt/advanced_samples/excel_ui/(ref) original_project.femprj +0 -0
  15. pyfemtet/opt/advanced_samples/excel_ui/femtet-macro.xlsm +0 -0
  16. pyfemtet/opt/advanced_samples/excel_ui/pyfemtet-core.py +291 -0
  17. pyfemtet/opt/advanced_samples/excel_ui/test-pyfemtet-core.cmd +22 -0
  18. pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_create_training_data.py +60 -0
  19. pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_create_training_data_jp.py +57 -0
  20. pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate.py +100 -0
  21. pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate_jp.py +90 -0
  22. pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_parametric.femprj +0 -0
  23. pyfemtet/opt/interface/__init__.py +2 -0
  24. pyfemtet/opt/interface/_base.py +3 -0
  25. pyfemtet/opt/interface/_excel_interface.py +565 -204
  26. pyfemtet/opt/interface/_femtet.py +26 -29
  27. pyfemtet/opt/interface/_surrogate/__init__.py +5 -0
  28. pyfemtet/opt/interface/_surrogate/_base.py +85 -0
  29. pyfemtet/opt/interface/_surrogate/_chaospy.py +71 -0
  30. pyfemtet/opt/interface/_surrogate/_singletaskgp.py +70 -0
  31. pyfemtet/opt/optimizer/_base.py +30 -19
  32. pyfemtet/opt/optimizer/_optuna/_optuna.py +20 -8
  33. pyfemtet/opt/optimizer/_optuna/_pof_botorch.py +60 -18
  34. pyfemtet/opt/prediction/_base.py +8 -0
  35. pyfemtet/opt/prediction/single_task_gp.py +85 -62
  36. pyfemtet/opt/visualization/_complex_components/main_figure_creator.py +5 -5
  37. pyfemtet/opt/visualization/_complex_components/main_graph.py +7 -1
  38. pyfemtet/opt/visualization/_complex_components/pm_graph.py +1 -1
  39. pyfemtet/opt/visualization/_process_monitor/application.py +2 -2
  40. pyfemtet/opt/visualization/_process_monitor/pages.py +1 -1
  41. pyfemtet/opt/visualization/result_viewer/pages.py +1 -1
  42. {pyfemtet-0.7.0.dist-info → pyfemtet-0.8.0.dist-info}/METADATA +3 -2
  43. {pyfemtet-0.7.0.dist-info → pyfemtet-0.8.0.dist-info}/RECORD +46 -29
  44. {pyfemtet-0.7.0.dist-info → pyfemtet-0.8.0.dist-info}/WHEEL +1 -1
  45. {pyfemtet-0.7.0.dist-info → pyfemtet-0.8.0.dist-info}/LICENSE +0 -0
  46. {pyfemtet-0.7.0.dist-info → pyfemtet-0.8.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,291 @@
1
+ """同梱する femtet-macro.xlsm から pyfemtet を呼び出す際の pyfemtet スクリプト。"""
2
+
3
+
4
+ import os
5
+
6
+ from fire import Fire
7
+
8
+
9
+ def get_sampler_class(sampling_method):
10
+ if sampling_method is None:
11
+ # default
12
+ from pyfemtet.opt.optimizer import PoFBoTorchSampler
13
+ return PoFBoTorchSampler
14
+ elif sampling_method == 'QMC':
15
+ from optuna.samplers import QMCSampler
16
+ return QMCSampler
17
+ elif sampling_method == 'PoFBoTorch':
18
+ from pyfemtet.opt.optimizer import PoFBoTorchSampler
19
+ return PoFBoTorchSampler
20
+ elif sampling_method == 'Random':
21
+ from optuna.samplers import RandomSampler
22
+ return RandomSampler
23
+ elif sampling_method == 'NSGA2':
24
+ from optuna.samplers import NSGAIISampler
25
+ return NSGAIISampler
26
+ elif sampling_method == 'TPE':
27
+ from optuna.samplers import TPESampler
28
+ return TPESampler
29
+ elif sampling_method == 'BoTorch':
30
+ from optuna_integration import BoTorchSampler
31
+ return BoTorchSampler
32
+ else:
33
+ raise NotImplementedError(f'The method {sampling_method} is not implemented.')
34
+
35
+
36
+ def core(
37
+ xlsm_path: str,
38
+ csv_path: str or None,
39
+ femprj_path: str or None, # xlsm と同じフォルダに配置する前提。
40
+ model_name: str or None,
41
+ input_sheet_name: str,
42
+
43
+ output_sheet_name: str or None,
44
+ constraint_sheet_name: str or None,
45
+ procedure_name: str or None, # 引数に拡張子を除く femprj ファイル名を取るように実装すること
46
+ setup_procedure_name: str or None,
47
+ teardown_procedure_name: str or None,
48
+
49
+ sampler_class: type('BaseSampler') or None,
50
+ sampler_kwargs: dict or None,
51
+
52
+ n_parallel: int,
53
+ n_trials: int or None,
54
+ timeout: float or None,
55
+ seed: int or None,
56
+ ):
57
+ from pathlib import Path
58
+ from pyfemtet.opt import FEMOpt, OptunaOptimizer
59
+ from pyfemtet.opt.interface._excel_interface import ExcelInterface
60
+
61
+ procedure_args = []
62
+ related_file_paths = []
63
+ if femprj_path is not None:
64
+ prj_name = os.path.basename(femprj_path).removesuffix('.femprj')
65
+ procedure_args.append(prj_name)
66
+ related_file_paths = [Path(femprj_path)]
67
+ if model_name is not None:
68
+ procedure_args.append(model_name)
69
+ if femprj_path is None and model_name is not None:
70
+ raise NotImplementedError
71
+
72
+ fem = ExcelInterface(
73
+ input_xlsm_path=xlsm_path,
74
+ input_sheet_name=input_sheet_name,
75
+ output_xlsm_path=None,
76
+ output_sheet_name=output_sheet_name,
77
+ constraint_xlsm_path=None,
78
+ constraint_sheet_name=constraint_sheet_name,
79
+ procedure_name=procedure_name,
80
+ procedure_args=procedure_args,
81
+ connect_method='new',
82
+ setup_procedure_name=setup_procedure_name,
83
+ teardown_procedure_name=teardown_procedure_name,
84
+ related_file_paths=related_file_paths,
85
+ visible=False,
86
+ interactive=True,
87
+ )
88
+
89
+ opt = OptunaOptimizer(
90
+ sampler_class=sampler_class,
91
+ sampler_kwargs=sampler_kwargs,
92
+ )
93
+
94
+ femopt = FEMOpt(
95
+ fem=fem,
96
+ opt=opt,
97
+ history_path=csv_path,
98
+ )
99
+
100
+ if seed is not None:
101
+ femopt.set_random_seed(42)
102
+
103
+ femopt.optimize(
104
+ n_trials=n_trials,
105
+ n_parallel=n_parallel,
106
+ timeout=timeout,
107
+ confirm_before_exit=True,
108
+ )
109
+
110
+
111
+ def main(
112
+ # これらは Fire キーワード引数指定できるように None を与えているが必須
113
+ xlsm_path: str = None,
114
+ input_sheet_name: str = None,
115
+ n_parallel: int = 1,
116
+ output_sheet_name: str or None = None,
117
+
118
+ femprj_path: str or None = None, # 指定する場合は xlsm と同じフォルダに配置する前提にすること
119
+ model_name: str = None,
120
+ csv_path: str or None = None,
121
+ constraint_sheet_name: str or None = None,
122
+ procedure_name: str or None = None, # 引数に拡張子を除く femprj ファイル名を取るように実装すること
123
+ setup_procedure_name: str or None = None,
124
+ teardown_procedure_name: str or None = None,
125
+
126
+ algorithm: str or None = None,
127
+
128
+ n_trials: int or None = None,
129
+ timeout: float or None = None,
130
+ seed: int or None = None,
131
+
132
+ **algorithm_settings: dict,
133
+
134
+ ):
135
+ import sys
136
+ import inspect
137
+ from pyfemtet.logger import get_module_logger
138
+
139
+ # ----- Fire memo -----
140
+ # print(csv_path) # 与えなければ None
141
+ # print(algorithm_settings) # 与えなければ {}, 与えれば {'n_startup_trials': 10} など
142
+ # print(n_parallel, type(n_parallel)) # int か float に自動変換される
143
+ # print(timeout, type(timeout)) # int か float に自動変換される
144
+
145
+
146
+ # ----- check 必須 args -----
147
+ logger = get_module_logger('opt.script', __name__)
148
+
149
+ os.chdir(os.path.dirname(__file__))
150
+
151
+ if xlsm_path is None:
152
+ logger.error(f'xlsm_path を指定してください。')
153
+ input('終了するには Enter を押してください。')
154
+ sys.exit(1)
155
+
156
+ if input_sheet_name is None:
157
+ logger.error(f'input_sheet_name を指定してください。')
158
+ input('終了するには Enter を押してください。')
159
+ sys.exit(1)
160
+
161
+ if output_sheet_name is None:
162
+ logger.error(f'output_sheet_name を指定してください。')
163
+ input('終了するには Enter を押してください。')
164
+ sys.exit(1)
165
+
166
+
167
+ # ----- check args -----
168
+ logger.info(f'{os.path.basename(__file__)} は {os.path.basename(xlsm_path)} に呼び出されました.')
169
+
170
+ # xlsm_path
171
+ xlsm_path = os.path.abspath(xlsm_path)
172
+ if not os.path.exists(xlsm_path):
173
+ logger.error(f'{xlsm_path} が見つかりませんでした。')
174
+ input('終了するには Enter を押してください。')
175
+ sys.exit(1)
176
+
177
+ # femprj_path
178
+ if femprj_path is not None:
179
+ femprj_path = os.path.abspath(femprj_path)
180
+ if not os.path.exists(femprj_path):
181
+ logger.error(f'{femprj_path} が見つかりませんでした。')
182
+ input('終了するには Enter を押してください。')
183
+ sys.exit(1)
184
+
185
+ # model_name
186
+ if model_name is not None and femprj_path is None:
187
+ logger.error(f'model_name ({model_name}) を指定する場合は femprj_path も指定してください。')
188
+ input('終了するには Enter を押してください。')
189
+ sys.exit(1)
190
+
191
+ # n_parallel
192
+ try:
193
+ n_parallel = int(n_parallel)
194
+ except ValueError:
195
+ logger.error(f'n_parallel ({n_parallel}) は自然数にできません。')
196
+ input('終了するには Enter を押してください。')
197
+ sys.exit(1)
198
+
199
+ # csv_path
200
+ csv_path = os.path.abspath(csv_path) if csv_path is not None else csv_path
201
+
202
+ # n_trials
203
+ if n_trials is not None:
204
+ try:
205
+ n_trials = int(n_trials)
206
+ except ValueError:
207
+ logger.error(f'n_trials ({n_trials}) は自然数にできません。')
208
+ input('終了するには Enter を押してください。')
209
+ sys.exit(1)
210
+
211
+ # timeout
212
+ if timeout is not None:
213
+ try:
214
+ timeout = float(timeout)
215
+ except ValueError:
216
+ logger.error(f'timeout ({timeout}) は数値にできません。')
217
+ input('終了するには Enter を押してください。')
218
+ sys.exit(1)
219
+
220
+ # seed
221
+ if seed is not None:
222
+ try:
223
+ seed = int(seed)
224
+ except ValueError:
225
+ logger.error(f'seed ({seed}) は自然数にできません。')
226
+ input('終了するには Enter を押してください。')
227
+ sys.exit(1)
228
+
229
+ # sampler
230
+ try:
231
+ sampler_class = get_sampler_class(algorithm)
232
+ except NotImplementedError:
233
+ logger.error(f'algorithm ({algorithm}) は非対応です。')
234
+ input('終了するには Enter を押してください。')
235
+ sys.exit(1)
236
+
237
+ # sampler_kwargs
238
+ sampler_kwargs = algorithm_settings
239
+ # noinspection PyUnboundLocalVariable
240
+ available_sampler_kwarg_keys = inspect.signature(sampler_class).parameters.keys()
241
+ for given_key in sampler_kwargs.keys():
242
+ if given_key not in available_sampler_kwarg_keys:
243
+ print()
244
+ print(sampler_class.__doc__)
245
+ print()
246
+ logger.error(f'algorithm_setting の項目 ({given_key}) は {sampler_class.__name__} に設定できません。詳しくは上記のドキュメントをご覧ください。')
247
+ input('終了するには Enter を押してください。')
248
+ sys.exit(1)
249
+
250
+ logger.info('引数の整合性チェックが終了しました。最適化を実行します。しばらくお待ちください...')
251
+
252
+ core(
253
+ xlsm_path,
254
+ csv_path,
255
+ femprj_path, # xlsm と同じフォルダに配置する前提。
256
+ model_name,
257
+ input_sheet_name,
258
+
259
+ output_sheet_name,
260
+ constraint_sheet_name,
261
+ procedure_name, # 引数に拡張子を除く femprj ファイル名を取るように実装すること
262
+ setup_procedure_name,
263
+ teardown_procedure_name,
264
+
265
+ sampler_class,
266
+ sampler_kwargs,
267
+
268
+ n_parallel,
269
+ n_trials,
270
+ timeout,
271
+ seed,
272
+ )
273
+
274
+
275
+ if __name__ == '__main__':
276
+ Fire(main)
277
+
278
+ # ===== Debug Code =====
279
+ # import os
280
+ # os.chdir(os.path.dirname(__file__))
281
+ # main(
282
+ # xlsm_path='インターフェース.xlsm',
283
+ # input_sheet_name='設計変数',
284
+ # n_parallel=1,
285
+ # output_sheet_name='目的関数',
286
+ # constraint_sheet_name='拘束関数',
287
+ # procedure_name='FemtetMacro.FemtetMain',
288
+ # setup_procedure_name='setup',
289
+ # teardown_procedure_name='teardown',
290
+ # n_trials=3,
291
+ # )
@@ -0,0 +1,22 @@
1
+ cd %~dp0
2
+ rem poetry run python pyfemtet-core.py --help
3
+ rem poetry run python pyfemtet-core.py "xlsm" "femprj" "input_sheet" 3
4
+ rem poetry run python pyfemtet-core.py "xlsm" "femprj" "input_sheet" 3 --n_startup_trials=10 --timeout=3.14
5
+ rem poetry run python pyfemtet-core.py "xlsm" "femprj" "input_sheet" 3 --n_startup_trials=10 --timeout=5
6
+ rem poetry run python pyfemtet-core.py "xlsm" "femprj" "input_sheet" 3.14 --n_startup_trials=10 --timeout=5
7
+ poetry run python pyfemtet-core.py ^
8
+ �C���^�[�t�F�[�X.xlsm ^
9
+ --input_sheet_name="�݌v�ϐ�" ^
10
+ --output_sheet_name="�ړI�֐�" ^
11
+ --constraint_sheet_name="�S���֐�" ^
12
+
13
+ --n_parallel=1 ^
14
+ --csv_path="test.csv" ^
15
+ --procedure_name=FemtetMacro.FemtetMain ^
16
+ --setup_procedure_name=PrePostProcessing.setup ^
17
+ --teardown_procedure_name=PrePostProcessing.teardown ^
18
+
19
+ --algorithm=Random ^
20
+ --n_startup_trials=10 ^
21
+
22
+ pause
@@ -0,0 +1,60 @@
1
+ import os
2
+ from time import sleep
3
+
4
+ from optuna.samplers import RandomSampler
5
+
6
+ from pyfemtet.opt import FEMOpt, FemtetInterface, OptunaOptimizer
7
+
8
+
9
+ def get_res_freq(Femtet):
10
+ Galileo = Femtet.Gogh.Galileo
11
+ Galileo.Mode = 0
12
+ sleep(0.01)
13
+ return Galileo.GetFreq().Real
14
+
15
+
16
+ if __name__ == '__main__':
17
+
18
+ os.chdir(os.path.dirname(__file__))
19
+
20
+ # Connect to Femtet.
21
+ fem = FemtetInterface(
22
+ femprj_path='gal_ex13_parametric.femprj',
23
+ )
24
+
25
+ # Initialize the optimization object.
26
+ # However, this script is not for optimization;
27
+ # instead, it is for creating training data.
28
+ # Therefore, we will use Optuna's random sampling
29
+ # class to select the design variables.
30
+ opt = OptunaOptimizer(
31
+ sampler_class=RandomSampler,
32
+ )
33
+
34
+ # We will set up the FEMOpt object. To refer to
35
+ # history_path in the optimization script, we will
36
+ # specify a clear CSV file name.
37
+ femopt = FEMOpt(
38
+ fem=fem,
39
+ opt=opt,
40
+ history_path='training_data.csv'
41
+ )
42
+
43
+ # Set the design variables.
44
+ femopt.add_parameter('length', 0.1, 0.02, 0.2)
45
+ femopt.add_parameter('width', 0.01, 0.001, 0.02)
46
+ femopt.add_parameter('base_radius', 0.008, 0.006, 0.01)
47
+
48
+ # Set the objective function. Since this is random
49
+ # sampling, specifying the direction does not affect
50
+ # the sampling.
51
+ femopt.add_objective(fun=get_res_freq, name='First Resonant Frequency (Hz)')
52
+
53
+ # Create the training data.
54
+ # If no termination condition is specified,
55
+ # it will continue creating training data until
56
+ # manually stopped.
57
+ femopt.set_random_seed(42)
58
+ femopt.optimize(
59
+ # n_trials=100
60
+ )
@@ -0,0 +1,57 @@
1
+ import os
2
+ from time import sleep
3
+
4
+ from optuna.samplers import RandomSampler
5
+
6
+ from pyfemtet.opt import FEMOpt, FemtetInterface, OptunaOptimizer
7
+
8
+
9
+ def get_res_freq(Femtet):
10
+ Galileo = Femtet.Gogh.Galileo
11
+ Galileo.Mode = 0
12
+ sleep(0.01)
13
+ return Galileo.GetFreq().Real
14
+
15
+
16
+ if __name__ == '__main__':
17
+
18
+ os.chdir(os.path.dirname(__file__))
19
+
20
+ # Femtet との接続を行います。
21
+ fem = FemtetInterface(
22
+ femprj_path='gal_ex13_parametric.femprj',
23
+ )
24
+
25
+ # 最適化用オブジェクトの設定を行います。
26
+ # ただしこのスクリプトでは最適化ではなく
27
+ # 学習データ作成を行うので、 optuna の
28
+ # ランダムサンプリングクラスを用いて
29
+ # 設計変数の選定を行います。
30
+ opt = OptunaOptimizer(
31
+ sampler_class=RandomSampler,
32
+ )
33
+
34
+ # FEMOpt オブジェクトを設定します。
35
+ # 最適化スクリプトで history_path を参照するため、
36
+ # わかりやすい csv ファイル名を指定します。
37
+ femopt = FEMOpt(
38
+ fem=fem,
39
+ opt=opt,
40
+ history_path='training_data.csv'
41
+ )
42
+
43
+ # 設計変数を設定します。
44
+ femopt.add_parameter('length', 0.1, 0.02, 0.2)
45
+ femopt.add_parameter('width', 0.01, 0.001, 0.02)
46
+ femopt.add_parameter('base_radius', 0.008, 0.006, 0.01)
47
+ # 目的関数を設定します。ランダムサンプリングなので
48
+ # direction は指定してもサンプリングに影響しません。
49
+ femopt.add_objective(fun=get_res_freq, name='第一共振周波数(Hz)')
50
+
51
+ # 学習データ作成を行います。
52
+ # 終了条件を指定しない場合、手動で停止するまで
53
+ # 学習データ作成を続けます。
54
+ femopt.set_random_seed(42)
55
+ femopt.optimize(
56
+ # n_trials=100
57
+ )
@@ -0,0 +1,100 @@
1
+ import os
2
+
3
+ from optuna.samplers import TPESampler
4
+
5
+ from pyfemtet.opt import FEMOpt, OptunaOptimizer
6
+ from pyfemtet.opt.interface import PoFBoTorchInterface
7
+
8
+
9
+ def main(target):
10
+
11
+ os.chdir(os.path.dirname(__file__))
12
+
13
+ # Instead of connecting with Femtet, create
14
+ # a surrogate model. Read the CSV file created
15
+ # by the training data creation script to build
16
+ # the surrogate model.
17
+ fem = PoFBoTorchInterface(
18
+ history_path='training_data.csv'
19
+ )
20
+
21
+ # Set up the optimization object.
22
+ opt = OptunaOptimizer(
23
+ sampler_class=TPESampler,
24
+ )
25
+
26
+ # Set up the FEMOpt object.
27
+ femopt = FEMOpt(
28
+ fem=fem,
29
+ opt=opt,
30
+ history_path=f'optimized_result_target_{target}.csv'
31
+ )
32
+
33
+ # Set up the design variables.
34
+ # The upper and lower limits can differ from
35
+ # those in the training data creation script,
36
+ # but please note that extrapolation will
37
+ # occur outside the range that has not been
38
+ # trained, which may reduce the prediction
39
+ # accuracy of the surrogate model.
40
+ femopt.add_parameter('length', 0.1, 0.02, 0.2)
41
+ femopt.add_parameter('width', 0.01, 0.001, 0.02)
42
+
43
+ # If there are parameters that were set as
44
+ # design variables during training and wanted
45
+ # to fix during optimization, specify only the
46
+ # `initial_value` and set the `fix` argument True.
47
+ # You cannot add design variables that were not
48
+ # set during training for optimization.
49
+ femopt.add_parameter('base_radius', 0.008, fix=True)
50
+
51
+ # Specify the objective functions set during
52
+ # training that you want to optimize.
53
+ # You may provide the fun argument, but it will
54
+ # be overwritten during surrogate model creation,
55
+ # so it will be ignored.
56
+ # You cannot use objective functions that were
57
+ # not set during training for optimization.
58
+ obj_name = 'First Resonant Frequency (Hz)'
59
+ femopt.add_objective(
60
+ name=obj_name,
61
+ direction=target,
62
+ )
63
+
64
+ # Execute the optimization.
65
+ femopt.set_random_seed(42)
66
+ df = femopt.optimize(
67
+ n_trials=50,
68
+ confirm_before_exit=False
69
+ )
70
+
71
+ # Display the optimal solution.
72
+ prm_names = femopt.history.prm_names
73
+ obj_names = femopt.history.obj_names
74
+ prm_values = df[df['non_domi'] == True][prm_names].values[0]
75
+ obj_values = df[df['non_domi'] == True][obj_names].values[0]
76
+
77
+ message = f'''
78
+ ===== Optimization Results =====
79
+ Target Value: {target}
80
+ Prediction by Surrogate Model:
81
+ '''
82
+ for name, value in zip(prm_names, prm_values):
83
+ message += f' {name}: {value}\n'
84
+ for name, value in zip(obj_names, obj_values):
85
+ message += f' {name}: {value}\n'
86
+
87
+ return message
88
+
89
+
90
+ if __name__ == '__main__':
91
+ # Using the surrogate model created from the training data,
92
+ # we will find a design that results in a resonant frequency of 1000.
93
+ message_1000 = main(target=1000)
94
+
95
+ # Next, using the same surrogate model,
96
+ # we will find a design that results in a resonant frequency of 2000.
97
+ message_2000 = main(target=2000)
98
+
99
+ print(message_1000)
100
+ print(message_2000)
@@ -0,0 +1,90 @@
1
+ import os
2
+
3
+ from optuna.samplers import TPESampler
4
+
5
+ from pyfemtet.opt import FEMOpt, OptunaOptimizer
6
+ from pyfemtet.opt.interface import PoFBoTorchInterface
7
+
8
+
9
+ def main(target):
10
+
11
+ os.chdir(os.path.dirname(__file__))
12
+
13
+ # Femtet との接続の代わりに、サロゲートモデルを作成します。
14
+ # 学習データ作成スクリプトで作成した csv ファイルを読み込んで
15
+ # サロゲートモデルを作成します。
16
+ fem = PoFBoTorchInterface(
17
+ history_path='training_data.csv'
18
+ )
19
+
20
+ # 最適化用オブジェクトの設定を行います。
21
+ opt = OptunaOptimizer(
22
+ sampler_class=TPESampler,
23
+ )
24
+
25
+ # FEMOpt オブジェクトの設定を行います。
26
+ femopt = FEMOpt(
27
+ fem=fem,
28
+ opt=opt,
29
+ history_path=f'optimized_result_target_{target}.csv'
30
+ )
31
+
32
+ # 設計変数の設定を行います。
33
+ # 上下限は学習データ作成スクリプトと異なっても良いですが、
34
+ # 学習していない範囲は外挿となりサロゲートモデルによる
35
+ # 予測精度が低下することに注意してください。
36
+ femopt.add_parameter('length', 0.1, 0.02, 0.2)
37
+ femopt.add_parameter('width', 0.01, 0.001, 0.02)
38
+
39
+ # 学習時は設計変数としていたが最適化時に固定したいパラメータがある場合
40
+ # initial_value のみを指定して fix 引数を True にしてください。
41
+ # 学習時に設定しなかった設計変数を最適化時に追加することはできません。
42
+ femopt.add_parameter('base_radius', 0.008, fix=True)
43
+
44
+ # 学習時に設定した目的関数のうち
45
+ # 最適化したいものを指定します。
46
+ # fun 引数は与えてもいいですが、サロゲートモデル作成時に上書きされるため無視されます。
47
+ # 学習時に設定しなかった目的関数を最適化時に使用することはできません。
48
+ obj_name = '第一共振周波数(Hz)'
49
+ femopt.add_objective(
50
+ name=obj_name,
51
+ direction=target,
52
+ )
53
+
54
+ # 最適化を実行します。
55
+ femopt.set_random_seed(42)
56
+ df = femopt.optimize(
57
+ n_trials=50,
58
+ confirm_before_exit=False
59
+ )
60
+
61
+ # 最適解を表示します。
62
+ prm_names = femopt.history.prm_names
63
+ obj_names = femopt.history.obj_names
64
+ prm_values = df[df['non_domi'] == True][prm_names].values[0]
65
+ obj_values = df[df['non_domi'] == True][obj_names].values[0]
66
+
67
+ message = f'''
68
+ ===== 最適化結果 =====
69
+ ターゲット値: {target}
70
+ サロゲートモデルによる予測:
71
+ '''
72
+ for name, value in zip(prm_names, prm_values):
73
+ message += f' {name}: {value}\n'
74
+ for name, value in zip(obj_names, obj_values):
75
+ message += f' {name}: {value}\n'
76
+
77
+ return message
78
+
79
+
80
+ if __name__ == '__main__':
81
+ # 学習データから作成したサロゲートモデルで
82
+ # 共振周波数が 1000 になる設計を見つけます。
83
+ message_1000 = main(target=1000)
84
+
85
+ # 続いて、同じサロゲートモデルで
86
+ # 共振周波数が 2000 になる設計を見つけます。
87
+ message_2000 = main(target=2000)
88
+
89
+ print(message_1000)
90
+ print(message_2000)
@@ -3,6 +3,7 @@ from pyfemtet.opt.interface._base import NoFEM
3
3
  from pyfemtet.opt.interface._femtet import FemtetInterface
4
4
  from pyfemtet.opt.interface._femtet_with_sldworks import FemtetWithSolidworksInterface
5
5
  from pyfemtet.opt.interface._femtet_with_nx import FemtetWithNXInterface
6
+ from pyfemtet.opt.interface._surrogate import PoFBoTorchInterface
6
7
 
7
8
 
8
9
  __all__ = [
@@ -11,4 +12,5 @@ __all__ = [
11
12
  'FemtetInterface',
12
13
  'FemtetWithNXInterface',
13
14
  'FemtetWithSolidworksInterface',
15
+ 'PoFBoTorchInterface',
14
16
  ]
@@ -55,6 +55,9 @@ class FEMInterface(ABC):
55
55
  def load_objective(self, opt) -> None: # opt: AbstractOptimizer
56
56
  raise NotImplementedError()
57
57
 
58
+ def load_constraint(self, opt) -> None: # opt: AbstractOptimizer
59
+ raise NotImplementedError()
60
+
58
61
  def _setup_before_parallel(self, client) -> None:
59
62
  """Preprocessing before launching a dask worker (if implemented in concrete class).
60
63