pyfemtet 0.9.5__py3-none-any.whl → 1.0.0b0__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.
- pyfemtet/__init__.py +6 -1
- pyfemtet/_i18n/1. make_pot_and_update_po.bat +8 -0
- pyfemtet/_i18n/2. build_mo.bat +5 -0
- pyfemtet/_i18n/__init__.py +4 -0
- pyfemtet/_i18n/babel.cfg +2 -0
- pyfemtet/_i18n/i18n.py +37 -0
- pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.mo +0 -0
- pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.po +1020 -0
- pyfemtet/_i18n/locales/messages.pot +987 -0
- pyfemtet/{_message → _i18n}/messages.py +128 -41
- pyfemtet/_util/closing.py +19 -0
- pyfemtet/_util/dask_util.py +89 -7
- pyfemtet/_util/df_util.py +29 -0
- pyfemtet/_util/excel_macro_util.py +8 -3
- pyfemtet/_util/excel_parse_util.py +43 -23
- pyfemtet/_util/femtet_access_inspection.py +120 -0
- pyfemtet/{_femtet_config_util/autosave.py → _util/femtet_autosave.py} +7 -0
- pyfemtet/_util/femtet_exit.py +105 -0
- pyfemtet/_util/femtet_version.py +20 -0
- pyfemtet/_util/helper.py +94 -0
- pyfemtet/_util/process_util.py +107 -0
- pyfemtet/_util/str_enum.py +44 -0
- pyfemtet/core.py +15 -47
- pyfemtet/dispatch_extensions/__init__.py +8 -11
- pyfemtet/dispatch_extensions/_impl.py +42 -198
- pyfemtet/logger/__init__.py +8 -1
- pyfemtet/logger/_impl.py +5 -6
- pyfemtet/opt/__init__.py +3 -17
- pyfemtet/opt/exceptions.py +45 -0
- pyfemtet/opt/femopt.py +608 -0
- pyfemtet/opt/history/__init__.py +11 -0
- pyfemtet/opt/history/_history.py +1404 -0
- pyfemtet/opt/history/_hypervolume.py +169 -0
- pyfemtet/opt/history/_optimality.py +79 -0
- pyfemtet/opt/interface/__init__.py +17 -24
- pyfemtet/opt/interface/_base_interface.py +222 -0
- pyfemtet/opt/interface/_excel_interface/__init__.py +3 -0
- pyfemtet/opt/interface/_excel_interface/debug-excel-interface.xlsm +0 -0
- pyfemtet/opt/interface/_excel_interface/excel_interface.py +999 -0
- pyfemtet/opt/interface/_femtet_interface/__init__.py +3 -0
- pyfemtet/opt/interface/{_femtet_parametric.py → _femtet_interface/_femtet_parametric.py} +20 -12
- pyfemtet/opt/interface/{_femtet.py → _femtet_interface/femtet_interface.py} +505 -349
- pyfemtet/opt/interface/_femtet_with_nx_interface/__init__.py +5 -0
- pyfemtet/opt/interface/_femtet_with_nx_interface/femtet_with_nx_interface.py +230 -0
- pyfemtet/opt/interface/_femtet_with_nx_interface/model1.prt +0 -0
- pyfemtet/opt/interface/_femtet_with_nx_interface/model1.x_t +98 -0
- pyfemtet/opt/interface/{_femtet_with_nx → _femtet_with_nx_interface}/update_model.py +1 -3
- pyfemtet/opt/interface/_femtet_with_solidworks/__init__.py +5 -0
- pyfemtet/opt/interface/_femtet_with_solidworks/femtet_with_solidworks_interface.py +122 -0
- pyfemtet/opt/interface/_solidworks_interface/__init__.py +5 -0
- pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py +206 -0
- pyfemtet/opt/interface/_surrogate_model_interface/__init__.py +8 -0
- pyfemtet/opt/interface/_surrogate_model_interface/base_surrogate_interface.py +150 -0
- pyfemtet/opt/interface/_surrogate_model_interface/botorch_interface.py +298 -0
- pyfemtet/opt/interface/_surrogate_model_interface/debug-pof-botorch.reccsv +18 -0
- pyfemtet/opt/interface/_with_excel_settings/__init__.py +61 -0
- pyfemtet/opt/interface/_with_excel_settings/with_excel_settings.py +134 -0
- pyfemtet/opt/meta_script/YAML_Generator.xlsm +0 -0
- pyfemtet/opt/meta_script/__main__.py +58 -36
- pyfemtet/opt/optimizer/__init__.py +7 -9
- pyfemtet/opt/optimizer/_base_optimizer.py +885 -0
- pyfemtet/opt/optimizer/optuna_optimizer/__init__.py +9 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_optuna_attribute.py +73 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_optuna_optimizer.py +678 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/__init__.py +7 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/debug-pof-botorch.reccsv +18 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/enable_nonlinear_constraint.py +244 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/pof_botorch_sampler.py +1249 -0
- pyfemtet/opt/optimizer/optuna_optimizer/wat_ex14_parametric_jp.femprj +0 -0
- pyfemtet/opt/optimizer/scipy_optimizer/__init__.py +1 -0
- pyfemtet/opt/optimizer/scipy_optimizer/_scipy_optimizer.py +364 -0
- pyfemtet/opt/prediction/__init__.py +7 -0
- pyfemtet/opt/prediction/_botorch_utils.py +133 -0
- pyfemtet/opt/prediction/_gpytorch_modules_extension.py +142 -0
- pyfemtet/opt/prediction/_helper.py +155 -0
- pyfemtet/opt/prediction/_model.py +118 -0
- pyfemtet/opt/problem/problem.py +304 -0
- pyfemtet/opt/problem/variable_manager/__init__.py +20 -0
- pyfemtet/opt/problem/variable_manager/_string_as_expression.py +115 -0
- pyfemtet/opt/problem/variable_manager/_variable_manager.py +295 -0
- pyfemtet/opt/visualization/history_viewer/__main__.py +5 -0
- pyfemtet/opt/visualization/{_base.py → history_viewer/_base_application.py} +18 -13
- pyfemtet/opt/visualization/history_viewer/_common_pages.py +150 -0
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/alert_region.py +10 -5
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/control_femtet.py +16 -13
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/main_graph.py +117 -47
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/pm_graph.py +159 -138
- pyfemtet/opt/visualization/history_viewer/_process_monitor/_application.py +173 -0
- pyfemtet/opt/visualization/history_viewer/_process_monitor/_pages.py +291 -0
- pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/dbc.py +1 -1
- pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/dcc.py +1 -1
- pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/html.py +1 -1
- pyfemtet/opt/visualization/history_viewer/result_viewer/__main__.py +5 -0
- pyfemtet/opt/visualization/{result_viewer/application.py → history_viewer/result_viewer/_application.py} +6 -6
- pyfemtet/opt/visualization/{result_viewer/pages.py → history_viewer/result_viewer/_pages.py} +106 -82
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08.csv +18 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08.db +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8.log +45 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_1.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_1.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_10.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_10.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_11.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_11.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_12.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_12.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_13.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_13.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_14.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_14.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_15.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_15.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_16.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_16.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_17.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_17.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_18.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_18.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_19.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_19.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_2.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_2.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_20.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_20.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_3.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_3.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.bgr +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.bnd +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.btr +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.mtl +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.prm +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_5.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_5.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_6.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_6.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_7.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_7.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_8.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_8.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_9.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_9.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.femprj +0 -0
- pyfemtet/opt/visualization/plotter/main_figure_creator.py +536 -0
- pyfemtet/opt/visualization/plotter/pm_graph_creator.py +359 -0
- pyfemtet/opt/worker_status.py +120 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/METADATA +23 -24
- pyfemtet-1.0.0b0.dist-info/RECORD +172 -0
- pyfemtet-1.0.0b0.dist-info/entry_points.txt +3 -0
- pyfemtet/_femtet_config_util/exit.py +0 -59
- pyfemtet/_message/1. make_pot.bat +0 -11
- pyfemtet/_message/2. make_mo.bat +0 -6
- pyfemtet/_message/__init__.py +0 -5
- pyfemtet/_message/babel.cfg +0 -2
- pyfemtet/_message/locales/ja/LC_MESSAGES/messages.mo +0 -0
- pyfemtet/_message/locales/ja/LC_MESSAGES/messages.po +0 -570
- pyfemtet/_message/locales/messages.pot +0 -551
- pyfemtet/_warning.py +0 -87
- pyfemtet/brep/_impl.py +0 -18
- pyfemtet/opt/_femopt.py +0 -1007
- pyfemtet/opt/_femopt_core.py +0 -1169
- pyfemtet/opt/_test_utils/control_femtet.py +0 -39
- pyfemtet/opt/_test_utils/hyper_sphere.py +0 -24
- pyfemtet/opt/_test_utils/record_history.py +0 -130
- pyfemtet/opt/advanced_samples/excel_ui/(ref) original_project.femprj +0 -0
- pyfemtet/opt/advanced_samples/excel_ui/femtet-macro.xlsm +0 -0
- pyfemtet/opt/advanced_samples/excel_ui/pyfemtet-core.py +0 -291
- pyfemtet/opt/advanced_samples/excel_ui/test-pyfemtet-core.cmd +0 -22
- pyfemtet/opt/advanced_samples/restart/gal_ex13_parametric.femprj +0 -0
- pyfemtet/opt/advanced_samples/restart/gal_ex13_parametric_restart.py +0 -99
- pyfemtet/opt/advanced_samples/restart/gal_ex13_parametric_restart_jp.py +0 -102
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_create_training_data.py +0 -60
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_create_training_data_jp.py +0 -57
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate.py +0 -100
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate_jp.py +0 -90
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_parametric.femprj +0 -0
- pyfemtet/opt/interface/_base.py +0 -101
- pyfemtet/opt/interface/_excel_interface.py +0 -984
- pyfemtet/opt/interface/_femtet_excel.py +0 -141
- pyfemtet/opt/interface/_femtet_with_nx/__init__.py +0 -3
- pyfemtet/opt/interface/_femtet_with_nx/_interface.py +0 -178
- pyfemtet/opt/interface/_femtet_with_sldworks.py +0 -298
- pyfemtet/opt/interface/_surrogate/__init__.py +0 -5
- pyfemtet/opt/interface/_surrogate/_base.py +0 -129
- pyfemtet/opt/interface/_surrogate/_chaospy.py +0 -71
- pyfemtet/opt/interface/_surrogate/_singletaskgp.py +0 -71
- pyfemtet/opt/interface/_surrogate_excel.py +0 -102
- pyfemtet/opt/optimizer/_base.py +0 -376
- pyfemtet/opt/optimizer/_optuna/_botorch_patch/enable_nonlinear_constraint.py +0 -220
- pyfemtet/opt/optimizer/_optuna/_optuna.py +0 -434
- pyfemtet/opt/optimizer/_optuna/_pof_botorch.py +0 -1914
- pyfemtet/opt/optimizer/_scipy.py +0 -159
- pyfemtet/opt/optimizer/_scipy_scalar.py +0 -127
- pyfemtet/opt/optimizer/parameter.py +0 -113
- pyfemtet/opt/prediction/_base.py +0 -61
- pyfemtet/opt/prediction/single_task_gp.py +0 -119
- pyfemtet/opt/samples/femprj_sample/ParametricIF.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/ParametricIF.py +0 -29
- pyfemtet/opt/samples/femprj_sample/ParametricIF_test_result.reccsv +0 -13
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.prt +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.py +0 -135
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX_test_result.reccsv +0 -23
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.SLDPRT +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.py +0 -131
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW_test_result.reccsv +0 -23
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +0 -96
- pyfemtet/opt/samples/femprj_sample/constrained_pipe_test_result.reccsv +0 -13
- pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.py +0 -74
- pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric_test_result.reccsv +0 -13
- pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric.py +0 -58
- pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric_test_result.reccsv +0 -23
- pyfemtet/opt/samples/femprj_sample/gau_ex12_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/gau_ex12_parametric.py +0 -52
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.py +0 -138
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric_test_result.reccsv +0 -18
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric.py +0 -60
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric_parallel.py +0 -61
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric_test_result.reccsv +0 -18
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric.py +0 -58
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric_parallel.py +0 -58
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric_test_result.reccsv +0 -18
- pyfemtet/opt/samples/femprj_sample_jp/ParametricIF_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/ParametricIF_jp.py +0 -29
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_NX_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_NX_jp.py +0 -129
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_SW_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_SW_jp.py +0 -125
- pyfemtet/opt/samples/femprj_sample_jp/constrained_pipe_jp.py +0 -93
- pyfemtet/opt/samples/femprj_sample_jp/gal_ex58_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/gal_ex58_parametric_jp.py +0 -70
- pyfemtet/opt/samples/femprj_sample_jp/gau_ex08_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/gau_ex08_parametric_jp.py +0 -57
- pyfemtet/opt/samples/femprj_sample_jp/gau_ex12_parametric_jp.py +0 -52
- pyfemtet/opt/samples/femprj_sample_jp/her_ex40_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/her_ex40_parametric_jp.py +0 -138
- pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_jp.py +0 -58
- pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_parallel_jp.py +0 -59
- pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.py +0 -56
- pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py +0 -56
- pyfemtet/opt/visualization/_complex_components/main_figure_creator.py +0 -332
- pyfemtet/opt/visualization/_complex_components/pm_graph_creator.py +0 -201
- pyfemtet/opt/visualization/_process_monitor/application.py +0 -226
- pyfemtet/opt/visualization/_process_monitor/pages.py +0 -406
- pyfemtet/opt/visualization/_wrapped_components/__init__.py +0 -0
- pyfemtet/opt/visualization/result_viewer/__init__.py +0 -0
- pyfemtet-0.9.5.dist-info/RECORD +0 -158
- pyfemtet-0.9.5.dist-info/entry_points.txt +0 -3
- /pyfemtet/{_femtet_config_util → opt/problem}/__init__.py +0 -0
- /pyfemtet/{brep → opt/visualization/history_viewer}/__init__.py +0 -0
- /pyfemtet/opt/{_test_utils → visualization/history_viewer/_complex_components}/__init__.py +0 -0
- /pyfemtet/opt/{optimizer/_optuna → visualization/history_viewer/_process_monitor}/__init__.py +0 -0
- /pyfemtet/opt/{optimizer/_optuna/_botorch_patch → visualization/history_viewer/_wrapped_components}/__init__.py +0 -0
- /pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/str_enum.py +0 -0
- /pyfemtet/opt/visualization/{result_viewer → history_viewer/result_viewer}/.gitignore +0 -0
- /pyfemtet/opt/visualization/{_complex_components → history_viewer/result_viewer}/__init__.py +0 -0
- /pyfemtet/opt/visualization/{_process_monitor → plotter}/__init__.py +0 -0
- /pyfemtet/opt/{samples/femprj_sample_jp/wat_ex14_parametric_jp.femprj → wat_ex14_parametric_jp.femprj} +0 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/LICENSE +0 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/LICENSE_THIRD_PARTY.txt +0 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/WHEEL +0 -0
pyfemtet/opt/_femopt.py
DELETED
|
@@ -1,1007 +0,0 @@
|
|
|
1
|
-
# built-in
|
|
2
|
-
import inspect
|
|
3
|
-
import warnings
|
|
4
|
-
from typing import Optional, Any, Callable, List, Sequence, SupportsFloat
|
|
5
|
-
import os
|
|
6
|
-
import datetime
|
|
7
|
-
from time import time, sleep
|
|
8
|
-
from threading import Thread
|
|
9
|
-
import json
|
|
10
|
-
from traceback import print_exception
|
|
11
|
-
|
|
12
|
-
# 3rd-party
|
|
13
|
-
import numpy as np
|
|
14
|
-
import pandas as pd
|
|
15
|
-
from dask.distributed import LocalCluster, Client, get_worker, Nanny
|
|
16
|
-
|
|
17
|
-
# pyfemtet relative
|
|
18
|
-
from pyfemtet.opt.interface import FEMInterface, FemtetInterface
|
|
19
|
-
from pyfemtet.opt.optimizer import AbstractOptimizer, OptunaOptimizer
|
|
20
|
-
from pyfemtet.opt.visualization._process_monitor.application import main as process_monitor_main
|
|
21
|
-
from pyfemtet.opt._femopt_core import (
|
|
22
|
-
_check_bound,
|
|
23
|
-
_is_access_gogh,
|
|
24
|
-
_is_access_femtet,
|
|
25
|
-
Objective,
|
|
26
|
-
Constraint,
|
|
27
|
-
History,
|
|
28
|
-
OptimizationStatus,
|
|
29
|
-
logger,
|
|
30
|
-
MonitorHostRecord,
|
|
31
|
-
)
|
|
32
|
-
from pyfemtet._message import Msg, encoding
|
|
33
|
-
from pyfemtet.opt.optimizer.parameter import Parameter, Expression
|
|
34
|
-
from pyfemtet._warning import experimental_feature
|
|
35
|
-
|
|
36
|
-
from dask import config as cfg
|
|
37
|
-
cfg.set({'distributed.scheduler.worker-ttl': None})
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def add_worker(client, worker_name, n_workers=1):
|
|
41
|
-
import sys
|
|
42
|
-
from subprocess import Popen, DEVNULL, PIPE
|
|
43
|
-
|
|
44
|
-
current_n_workers = len(client.nthreads().keys())
|
|
45
|
-
|
|
46
|
-
Popen(
|
|
47
|
-
f'{sys.executable} -m dask worker '
|
|
48
|
-
f'{client.scheduler.address} '
|
|
49
|
-
f'--nthreads 1 '
|
|
50
|
-
f'--nworkers {n_workers} '
|
|
51
|
-
f'--name {worker_name} ', # A unique name for this worker like ‘worker-1’. If used with -nworkers then the process number will be appended like name-0, name-1, name-2, …
|
|
52
|
-
# --no-nanny option は --nworkers と併用できない
|
|
53
|
-
shell=True,
|
|
54
|
-
stderr=DEVNULL,
|
|
55
|
-
stdout=DEVNULL,
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
# worker が増えるまで待つ
|
|
59
|
-
client.wait_for_workers(n_workers=current_n_workers + n_workers)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
class FEMOpt:
|
|
63
|
-
"""Class to control FEM interface and optimizer.
|
|
64
|
-
|
|
65
|
-
Args:
|
|
66
|
-
fem (FEMInterface, optional):
|
|
67
|
-
The FEM software interface.
|
|
68
|
-
Defaults to None (automatically set to :class:`FemtetInterface`).
|
|
69
|
-
|
|
70
|
-
opt (AbstractOptimizer, optional):
|
|
71
|
-
The numerical optimizer object.
|
|
72
|
-
Defaults to None (automatically set to :class:`OptunaOptimizer`
|
|
73
|
-
with :class:`optuna.samplers.TPESampler`).
|
|
74
|
-
|
|
75
|
-
history_path (str, optional):
|
|
76
|
-
The path to the history file.
|
|
77
|
-
Defaults to None.
|
|
78
|
-
If None, '%Y_%m_%d_%H_%M_%S.csv' is created in current directory.
|
|
79
|
-
|
|
80
|
-
scheduler_address (str, optional):
|
|
81
|
-
When performing cluster computing, please specify the address
|
|
82
|
-
of the scheduler computer here.
|
|
83
|
-
|
|
84
|
-
See Also:
|
|
85
|
-
https://pyfemtet.readthedocs.io/en/stable/pages/usage_pages/how_to_deploy_cluster.html
|
|
86
|
-
|
|
87
|
-
.. Example の中について、reST ではリストだと改行できないので、リストにしない
|
|
88
|
-
|
|
89
|
-
Examples:
|
|
90
|
-
|
|
91
|
-
When specifying and opening a femprj and model, we write
|
|
92
|
-
|
|
93
|
-
>>> from pyfemtet.opt import FEMOpt, FemtetInterface # doctest: +SKIP
|
|
94
|
-
>>> fem = FemtetInterface(femprj_path='path/to/project.femprj', model_name='NewModel') # doctest: +SKIP
|
|
95
|
-
>>> femopt = FEMOpt(fem=fem) # doctest: +SKIP
|
|
96
|
-
|
|
97
|
-
When specifying optimization algorithm, we write
|
|
98
|
-
|
|
99
|
-
>>> from optuna.samplers import TPESampler # doctest: +SKIP
|
|
100
|
-
>>> from pyfemtet.opt import FEMOpt, OptunaOptimizer # doctest: +SKIP
|
|
101
|
-
>>> opt = OptunaOptimizer(sampler_class=TPESampler, sampler_kwargs=dict(n_startup_trials=10)) # doctest: +SKIP
|
|
102
|
-
>>> femopt = FEMOpt(opt=opt) # doctest: +SKIP
|
|
103
|
-
|
|
104
|
-
"""
|
|
105
|
-
|
|
106
|
-
def __init__(
|
|
107
|
-
self,
|
|
108
|
-
fem: FEMInterface = None,
|
|
109
|
-
opt: AbstractOptimizer = None,
|
|
110
|
-
history_path: str = None,
|
|
111
|
-
scheduler_address: str = None
|
|
112
|
-
):
|
|
113
|
-
logger.info('Initialize FEMOpt')
|
|
114
|
-
|
|
115
|
-
# 引数の処理
|
|
116
|
-
if history_path is None:
|
|
117
|
-
history_path = datetime.datetime.now().strftime('%Y%m%d_%H%M%S.csv')
|
|
118
|
-
self.history_path = os.path.abspath(history_path)
|
|
119
|
-
self.scheduler_address = scheduler_address
|
|
120
|
-
|
|
121
|
-
if fem is None:
|
|
122
|
-
self.fem = FemtetInterface()
|
|
123
|
-
else:
|
|
124
|
-
self.fem = fem
|
|
125
|
-
|
|
126
|
-
if opt is None:
|
|
127
|
-
self.opt: AbstractOptimizer = OptunaOptimizer()
|
|
128
|
-
else:
|
|
129
|
-
self.opt: AbstractOptimizer = opt
|
|
130
|
-
|
|
131
|
-
# メンバーの宣言
|
|
132
|
-
self.client = None
|
|
133
|
-
self.status = None # actor
|
|
134
|
-
self.history: History = None
|
|
135
|
-
self.worker_status_list = None # [actor]
|
|
136
|
-
self.monitor_process_future = None
|
|
137
|
-
self.monitor_server_kwargs = dict()
|
|
138
|
-
self.monitor_process_worker_name = None
|
|
139
|
-
self.monitor_host_record = None
|
|
140
|
-
self._hv_reference = None
|
|
141
|
-
self._extra_space_dir = None
|
|
142
|
-
self._opt_exceptions = []
|
|
143
|
-
|
|
144
|
-
# multiprocess 時に pickle できないオブジェクト参照の削除
|
|
145
|
-
def __getstate__(self):
|
|
146
|
-
state = self.__dict__.copy()
|
|
147
|
-
del state['fem']
|
|
148
|
-
return state
|
|
149
|
-
|
|
150
|
-
def __setstate__(self, state):
|
|
151
|
-
self.__dict__.update(state)
|
|
152
|
-
|
|
153
|
-
def set_random_seed(self, seed: int):
|
|
154
|
-
"""Sets the random seed for reproducibility.
|
|
155
|
-
|
|
156
|
-
Args:
|
|
157
|
-
seed (int): The random seed value to be set.
|
|
158
|
-
|
|
159
|
-
"""
|
|
160
|
-
self.opt.seed = seed
|
|
161
|
-
|
|
162
|
-
def add_parameter(
|
|
163
|
-
self,
|
|
164
|
-
name: str,
|
|
165
|
-
initial_value: float = None,
|
|
166
|
-
lower_bound: float = None,
|
|
167
|
-
upper_bound: float = None,
|
|
168
|
-
step: float = None,
|
|
169
|
-
properties: dict[str, str or float] = None,
|
|
170
|
-
pass_to_fem: bool = True,
|
|
171
|
-
fix: bool = False,
|
|
172
|
-
):
|
|
173
|
-
# noinspection PyUnresolvedReferences
|
|
174
|
-
"""Adds a parameter to the optimization problem.
|
|
175
|
-
|
|
176
|
-
Args:
|
|
177
|
-
name (str): The name of the parameter.
|
|
178
|
-
initial_value (float, optional): The initial value of the parameter. Defaults to None. If None, try to get initial value from FEMInterface.
|
|
179
|
-
lower_bound (float, optional): The lower bound of the parameter. Defaults to None. Some optimization algorithms require this.
|
|
180
|
-
upper_bound (float or None, optional): The upper bound of the parameter. Defaults to None. Some optimization algorithms require this.
|
|
181
|
-
step (float, optional): The step of parameter. If specified, parameter is used as discrete. Defaults to None.
|
|
182
|
-
properties (dict[str, str or float], optional): Additional information about the parameter. Defaults to None.
|
|
183
|
-
pass_to_fem (bool, optional): If this variable is used directly in FEM model update or not. If False, this parameter can be just used as inpt of expressions. Defaults to True.
|
|
184
|
-
fix (bool, optiona):
|
|
185
|
-
パラメータを initial_value で固定します。
|
|
186
|
-
開発時にパラメータを振るか振らないかを
|
|
187
|
-
簡単に変更するための便利引数です。
|
|
188
|
-
True のとき、lower_bound, upper_bound, step, properties の
|
|
189
|
-
値は、有効かどうかのチェックには使われますが、最適化では
|
|
190
|
-
使われなくなります。
|
|
191
|
-
デフォルトは False です。
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
Raises:
|
|
195
|
-
ValueError: If initial_value is not specified and the value for the given name is also not specified in FEM.
|
|
196
|
-
|
|
197
|
-
Examples:
|
|
198
|
-
|
|
199
|
-
When adding parameter a (-1 <= a <= 1; initial value is 0), we write
|
|
200
|
-
|
|
201
|
-
>>> femopt.add_parameter('parameter_a', 0, -1, 1) # doctest: +SKIP
|
|
202
|
-
|
|
203
|
-
Note that the ```note``` argument can be set any name in this case.
|
|
204
|
-
|
|
205
|
-
When adding discrete parameter a (-1 <= a <= 1; initial value is 0,
|
|
206
|
-
step 0.5), we write
|
|
207
|
-
|
|
208
|
-
>>> femopt.add_parameter('parameter a', 0, -1, 1, 0.5) # doctest: +SKIP
|
|
209
|
-
|
|
210
|
-
"""
|
|
211
|
-
|
|
212
|
-
_check_bound(lower_bound, upper_bound, name)
|
|
213
|
-
|
|
214
|
-
if pass_to_fem:
|
|
215
|
-
value = self.fem.check_param_value(name)
|
|
216
|
-
if initial_value is None:
|
|
217
|
-
if value is not None:
|
|
218
|
-
initial_value = value
|
|
219
|
-
else:
|
|
220
|
-
raise ValueError('initial_value を指定してください.')
|
|
221
|
-
else:
|
|
222
|
-
if initial_value is None:
|
|
223
|
-
raise ValueError('initial_value を指定してください.')
|
|
224
|
-
|
|
225
|
-
if not fix:
|
|
226
|
-
prm = Parameter(
|
|
227
|
-
name=name,
|
|
228
|
-
value=float(initial_value),
|
|
229
|
-
lower_bound=float(lower_bound) if lower_bound is not None else None,
|
|
230
|
-
upper_bound=float(upper_bound) if upper_bound is not None else None,
|
|
231
|
-
step=float(step) if step is not None else None,
|
|
232
|
-
pass_to_fem=pass_to_fem,
|
|
233
|
-
properties=properties,
|
|
234
|
-
)
|
|
235
|
-
self.opt.variables.add_parameter(prm)
|
|
236
|
-
|
|
237
|
-
else:
|
|
238
|
-
warnings.filterwarnings('ignore', category=UserWarning, message="The function 'add_expression' is experimental")
|
|
239
|
-
self.add_expression(
|
|
240
|
-
name=name,
|
|
241
|
-
fun=lambda: initial_value,
|
|
242
|
-
pass_to_fem=pass_to_fem,
|
|
243
|
-
properties=properties,
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
@experimental_feature
|
|
248
|
-
def add_expression(
|
|
249
|
-
self,
|
|
250
|
-
name: str,
|
|
251
|
-
fun: Callable[[Any], float],
|
|
252
|
-
properties: dict[str, str or float] = None,
|
|
253
|
-
kwargs: Optional[dict] = None,
|
|
254
|
-
pass_to_fem=True,
|
|
255
|
-
):
|
|
256
|
-
# noinspection PyUnresolvedReferences
|
|
257
|
-
"""Add expression to the optimization problem.
|
|
258
|
-
|
|
259
|
-
Warnings:
|
|
260
|
-
This feature is highly experimental and
|
|
261
|
-
may change in the future.
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
name (str): The name of the variable.
|
|
265
|
-
fun (Callable[[Any], float]): An expression function. The arguments that you want to use as input variables must be the same with ``name`` of Variable objects added by ``add_parameter()`` or ``add_expression()``. If you use other objects as argument of the function, you must specify ``kwargs``.
|
|
266
|
-
properties (dict[str, str or float], optional): Additional information about the parameter. Defaults to None.
|
|
267
|
-
kwargs (Optional[dict], optional): Remaining arguments of ``fun``. Defaults to None.
|
|
268
|
-
pass_to_fem (bool, optional): If this variable is used directly in FEM model update or not. If False, this variable can be just used as inpt of other expressions. Defaults to True.
|
|
269
|
-
|
|
270
|
-
Examples:
|
|
271
|
-
|
|
272
|
-
When adding variable a and b; a is not directly included as model
|
|
273
|
-
variables but an optimization parameter, b is not a parameter but
|
|
274
|
-
a model variable and the relationship of these 2 variables is
|
|
275
|
-
```b = a ** 2```, we write:
|
|
276
|
-
|
|
277
|
-
>>> def calc_b(parameter_a): # doctest: +SKIP
|
|
278
|
-
... return parameter_a ** 2 # doctest: +SKIP
|
|
279
|
-
...
|
|
280
|
-
>>> femopt.add_parameter('parameter_a', 0, -1, 1, pass_to_fem=False) # doctest: +SKIP
|
|
281
|
-
>>> femopt.add_expression('variable_b', calc_b) # doctest: +SKIP
|
|
282
|
-
|
|
283
|
-
Notes:
|
|
284
|
-
The argument names of function to calculate variable
|
|
285
|
-
must match the ```name``` of the parameter.
|
|
286
|
-
|
|
287
|
-
Notes:
|
|
288
|
-
In this case, only strings that can be used as Python variables are valid
|
|
289
|
-
for ```name``` argument of :func:`FEMOpt.add_parameter`.
|
|
290
|
-
|
|
291
|
-
When adding variable r, theta and x, y; r, theta is an optimization
|
|
292
|
-
parameter and x, y is an intermediate variable to calculate constraint
|
|
293
|
-
function, we write
|
|
294
|
-
|
|
295
|
-
>>> def calc_x(r, theta): # doctest: +SKIP
|
|
296
|
-
... return r * cos(theta) # doctest: +SKIP
|
|
297
|
-
...
|
|
298
|
-
>>> def calc_y(r, theta): # doctest: +SKIP
|
|
299
|
-
... return r * cos(theta) # doctest: +SKIP
|
|
300
|
-
...
|
|
301
|
-
>>> def constraint(Femtet, opt: AbstractOptimizer): # doctest: +SKIP
|
|
302
|
-
... d = opt.variables.get_variables() # doctest: +SKIP
|
|
303
|
-
... x, y = d['x'], d['y'] # doctest: +SKIP
|
|
304
|
-
... return min(x, y) # doctest: +SKIP
|
|
305
|
-
...
|
|
306
|
-
>>> femopt.add_parameter('r', 0, 0, 1) # doctest: +SKIP
|
|
307
|
-
>>> femopt.add_parameter('theta', 0, 0, 2*pi) # doctest: +SKIP
|
|
308
|
-
>>> femopt.add_expression('x', calc_x, pass_to_fem=False) # doctest: +SKIP
|
|
309
|
-
>>> femopt.add_expression('y', calc_y, pass_to_fem=False) # doctest: +SKIP
|
|
310
|
-
>>> femopt.add_constraint(constraint, lower_bound=0.5, args=(femopt.opt,)) # doctest: +SKIP
|
|
311
|
-
|
|
312
|
-
"""
|
|
313
|
-
|
|
314
|
-
exp = Expression(
|
|
315
|
-
name=name,
|
|
316
|
-
value=None,
|
|
317
|
-
properties=properties,
|
|
318
|
-
fun=fun,
|
|
319
|
-
kwargs=kwargs if kwargs else {},
|
|
320
|
-
pass_to_fem=pass_to_fem,
|
|
321
|
-
)
|
|
322
|
-
self.opt.variables.add_expression(exp)
|
|
323
|
-
|
|
324
|
-
def add_objective(
|
|
325
|
-
self,
|
|
326
|
-
fun: callable or None = None,
|
|
327
|
-
name: str or None = None,
|
|
328
|
-
direction: str or float = 'minimize',
|
|
329
|
-
args: tuple or None = None,
|
|
330
|
-
kwargs: dict or None = None
|
|
331
|
-
):
|
|
332
|
-
# noinspection PyUnresolvedReferences
|
|
333
|
-
"""Adds an objective to the optimization problem.
|
|
334
|
-
|
|
335
|
-
Args:
|
|
336
|
-
fun (callable or None, optional): The objective function. This argument is optional but
|
|
337
|
-
name (str or None, optional): The name of the objective. Defaults to None.
|
|
338
|
-
direction (str or float, optional): The optimization direction. Varid values are 'maximize', 'minimize' or a float value. Defaults to 'minimize'.
|
|
339
|
-
args (tuple or None, optional): Additional arguments for the objective function. Defaults to None.
|
|
340
|
-
kwargs (dict or None, optional): Additional keyword arguments for the objective function. Defaults to None.
|
|
341
|
-
|
|
342
|
-
Note:
|
|
343
|
-
If the FEMInterface is FemtetInterface, the 1st argument of fun should be Femtet (IPyDispatch) object.
|
|
344
|
-
|
|
345
|
-
Examples:
|
|
346
|
-
|
|
347
|
-
When add a complex objective (for example, want to dynamically set body
|
|
348
|
-
to calculate temperature and use product of the temperature and one of
|
|
349
|
-
the parameters as objective) , we write
|
|
350
|
-
|
|
351
|
-
>>> class MyClass: # doctest: +SKIP
|
|
352
|
-
... def get_body_name(self): # doctest: +SKIP
|
|
353
|
-
... ... # process something and detect body name # doctest: +SKIP
|
|
354
|
-
... return body_name # doctest: +SKIP
|
|
355
|
-
...
|
|
356
|
-
>>> def complex_objective(Femtet, opt, some_object): # doctest: +SKIP
|
|
357
|
-
... body_name = some_object.get_body_name() # dynamically get body name to calculate temperature # doctest: +SKIP
|
|
358
|
-
... temp, _, _ = Femtet.Gogh.Watt.GetTemp(body_name) # calculate temperature # doctest: +SKIP
|
|
359
|
-
... some_param = opt.get_parameter()['some_param'] # get ome parameter # doctest: +SKIP
|
|
360
|
-
... return temp * some_param # calculate something and return it # doctest: +SKIP
|
|
361
|
-
...
|
|
362
|
-
>>> my_obj = MyClass() # doctest: +SKIP
|
|
363
|
-
>>> femopt.add_objective(complex_objective, args=(femopt.opt, my_obj,)) # doctest: +SKIP
|
|
364
|
-
|
|
365
|
-
Tip:
|
|
366
|
-
If name is None, name is a string with the prefix `"obj_"` followed by a sequential number.
|
|
367
|
-
|
|
368
|
-
"""
|
|
369
|
-
|
|
370
|
-
# ===== warning for v1.0 =====
|
|
371
|
-
if name is None:
|
|
372
|
-
logger.warning('From version 1.0, `name` will be the first required argument. '
|
|
373
|
-
'For more details, please see https://pyfemtet.readthedocs.io/en/stable/pages/migration_to_v1.html. '
|
|
374
|
-
'(日本語版サイト; https://pyfemtet.readthedocs.io/ja/stable/pages/migration_to_v1.html)')
|
|
375
|
-
|
|
376
|
-
# 引数の処理
|
|
377
|
-
if fun is None:
|
|
378
|
-
from pyfemtet.opt.interface import SurrogateModelInterfaceBase
|
|
379
|
-
if not isinstance(self.fem, SurrogateModelInterfaceBase):
|
|
380
|
-
raise ValueError('`fun` argument is not specified.')
|
|
381
|
-
if args is None:
|
|
382
|
-
args = tuple()
|
|
383
|
-
elif not isinstance(args, tuple):
|
|
384
|
-
args = (args,)
|
|
385
|
-
if kwargs is None:
|
|
386
|
-
kwargs = dict()
|
|
387
|
-
if name is None:
|
|
388
|
-
prefix = Objective.default_name
|
|
389
|
-
i = 0
|
|
390
|
-
while True:
|
|
391
|
-
candidate = f'{prefix}_{str(int(i))}'
|
|
392
|
-
is_existing = candidate in list(self.opt.objectives.keys())
|
|
393
|
-
if not is_existing:
|
|
394
|
-
break
|
|
395
|
-
else:
|
|
396
|
-
i += 1
|
|
397
|
-
name = candidate
|
|
398
|
-
|
|
399
|
-
self.opt.objectives[name] = Objective(fun, name, direction, args, kwargs)
|
|
400
|
-
|
|
401
|
-
def add_objectives(
|
|
402
|
-
self,
|
|
403
|
-
fun: Callable[[Any], Sequence[SupportsFloat]],
|
|
404
|
-
n_return: int,
|
|
405
|
-
names: str or Sequence[str] or None = None,
|
|
406
|
-
directions: str or Sequence[str] or None = None,
|
|
407
|
-
args: tuple or None = None,
|
|
408
|
-
kwargs: dict or None = None,
|
|
409
|
-
):
|
|
410
|
-
|
|
411
|
-
# ===== warning for v1.0 =====
|
|
412
|
-
if names is None:
|
|
413
|
-
logger.warning('From version 1.0, `names` will be the first required argument. '
|
|
414
|
-
'For more details, please see https://pyfemtet.readthedocs.io/en/stable/pages/migration_to_v1.html. '
|
|
415
|
-
'(日本語版サイト; https://pyfemtet.readthedocs.io/ja/stable/pages/migration_to_v1.html)')
|
|
416
|
-
|
|
417
|
-
from pyfemtet.opt._femopt_core import ObjectivesFunc
|
|
418
|
-
components = ObjectivesFunc(fun, n_return)
|
|
419
|
-
|
|
420
|
-
if names is not None:
|
|
421
|
-
if isinstance(names, str):
|
|
422
|
-
names = [f'{names}_{i}' for i in range(n_return)]
|
|
423
|
-
else:
|
|
424
|
-
# names = names
|
|
425
|
-
pass
|
|
426
|
-
else:
|
|
427
|
-
names = [None for _ in range(n_return)]
|
|
428
|
-
|
|
429
|
-
if directions is not None:
|
|
430
|
-
if isinstance(directions, str):
|
|
431
|
-
directions = [directions for _ in range(n_return)]
|
|
432
|
-
else:
|
|
433
|
-
# directions = directions
|
|
434
|
-
pass
|
|
435
|
-
else:
|
|
436
|
-
directions = ['minimize' for _ in range(n_return)]
|
|
437
|
-
|
|
438
|
-
for name, component, direction in zip(names, components, directions):
|
|
439
|
-
self.add_objective(
|
|
440
|
-
fun=component,
|
|
441
|
-
name=name,
|
|
442
|
-
direction=direction,
|
|
443
|
-
args=args,
|
|
444
|
-
kwargs=kwargs,
|
|
445
|
-
)
|
|
446
|
-
|
|
447
|
-
def add_constraint(
|
|
448
|
-
self,
|
|
449
|
-
fun,
|
|
450
|
-
name: str or None = None,
|
|
451
|
-
lower_bound: float or None = None,
|
|
452
|
-
upper_bound: float or None = None,
|
|
453
|
-
strict: bool = True,
|
|
454
|
-
args: tuple or None = None,
|
|
455
|
-
kwargs: dict or None = None,
|
|
456
|
-
using_fem: bool = None,
|
|
457
|
-
):
|
|
458
|
-
# noinspection PyUnresolvedReferences
|
|
459
|
-
"""Adds a constraint to the optimization problem.
|
|
460
|
-
|
|
461
|
-
Args:
|
|
462
|
-
fun (callable): The constraint function.
|
|
463
|
-
name (str or None, optional): The name of the constraint. Defaults to None.
|
|
464
|
-
lower_bound (float or Non, optional): The lower bound of the constraint. Defaults to None.
|
|
465
|
-
upper_bound (float or Non, optional): The upper bound of the constraint. Defaults to None.
|
|
466
|
-
strict (bool, optional): Flag indicating if it is a strict constraint. Defaults to True.
|
|
467
|
-
args (tuple or None, optional): Additional arguments for the constraint function. Defaults to None.
|
|
468
|
-
kwargs (dict): Additional arguments for the constraint function. Defaults to None.
|
|
469
|
-
using_fem (bool, optional): Using FEM or not in the constraint function. It may make the processing time in strict constraints in BoTorchSampler. Defaults to None. If None, PyFemtet checks the access to Femtet and estimate using Femtet or not automatically.
|
|
470
|
-
|
|
471
|
-
Warnings:
|
|
472
|
-
|
|
473
|
-
When ```strict``` == True and using OptunaOptimizer along with :class:`PoFBoTorchSampler`,
|
|
474
|
-
PyFemtet will solve an optimization subproblem to propose new variables.
|
|
475
|
-
During this process, the constraint function ```fun``` will be executed at each
|
|
476
|
-
iteration of the subproblem, which may include time-consuming operations such
|
|
477
|
-
as retrieving 3D model information via FEMInterface.
|
|
478
|
-
As a result, it may not be feasible to complete the overall optimization within
|
|
479
|
-
a realistic timeframe.
|
|
480
|
-
|
|
481
|
-
Examples:
|
|
482
|
-
For example, in a case where the bottom area of the model is constrained,
|
|
483
|
-
the following approach may require a very long time.
|
|
484
|
-
|
|
485
|
-
>>> def bottom_area(Femtet, opt): # doctest: +SKIP
|
|
486
|
-
... w = Femtet.GetVariableValue('width') # doctest: +SKIP
|
|
487
|
-
... d = Femtet.GetVariableValue('depth') # doctest: +SKIP
|
|
488
|
-
... return w * d # doctest: +SKIP
|
|
489
|
-
...
|
|
490
|
-
>>> femopt.add_constraint(constraint, lower_bound=5) # doctest: +SKIP
|
|
491
|
-
|
|
492
|
-
Instead, please do the following.
|
|
493
|
-
|
|
494
|
-
>>> def bottom_area(_, opt): # Not to access the 1st argument. # doctest: +SKIP
|
|
495
|
-
... params = opt.get_parameter() # doctest: +SKIP
|
|
496
|
-
... w, d = params['width'], params['depth'] # doctest: +SKIP
|
|
497
|
-
... return w * d # doctest: +SKIP
|
|
498
|
-
...
|
|
499
|
-
>>> femopt.add_constraint(constraint, lower_bound=5, args=(femopt.opt,)) # doctest: +SKIP
|
|
500
|
-
|
|
501
|
-
Note:
|
|
502
|
-
If the FEMInterface is FemtetInterface, the 1st argument of fun should be Femtet (IPyDispatch) object.
|
|
503
|
-
|
|
504
|
-
Tip:
|
|
505
|
-
If name is None, name is a string with the prefix `"cns_"` followed by a sequential number.
|
|
506
|
-
|
|
507
|
-
"""
|
|
508
|
-
|
|
509
|
-
# ===== warning for v1.0 =====
|
|
510
|
-
if name is None:
|
|
511
|
-
logger.warning('From version 1.0, `name` will be the first required argument. '
|
|
512
|
-
'For more details, please see https://pyfemtet.readthedocs.io/en/stable/pages/migration_to_v1.html. '
|
|
513
|
-
'(日本語版サイト; https://pyfemtet.readthedocs.io/ja/stable/pages/migration_to_v1.html)')
|
|
514
|
-
|
|
515
|
-
# 引数の処理
|
|
516
|
-
if args is None:
|
|
517
|
-
args = tuple()
|
|
518
|
-
elif not isinstance(args, tuple):
|
|
519
|
-
args = (args,)
|
|
520
|
-
if kwargs is None:
|
|
521
|
-
kwargs = dict()
|
|
522
|
-
if name is None:
|
|
523
|
-
prefix = Constraint.default_name
|
|
524
|
-
i = 0
|
|
525
|
-
while True:
|
|
526
|
-
candidate = f'{prefix}_{str(int(i))}'
|
|
527
|
-
is_existing = candidate in list(self.opt.constraints.keys())
|
|
528
|
-
if not is_existing:
|
|
529
|
-
break
|
|
530
|
-
else:
|
|
531
|
-
i += 1
|
|
532
|
-
name = candidate
|
|
533
|
-
if using_fem is None:
|
|
534
|
-
# 自動推定機能は Femtet 特有の処理とする
|
|
535
|
-
if isinstance(self.fem, FemtetInterface):
|
|
536
|
-
using_fem = _is_access_femtet(fun)
|
|
537
|
-
else:
|
|
538
|
-
using_fem = False
|
|
539
|
-
|
|
540
|
-
# strict constraint の場合、solve 前に評価したいので Gogh へのアクセスを禁ずる
|
|
541
|
-
if strict and isinstance(self.fem, FemtetInterface):
|
|
542
|
-
if _is_access_gogh(fun):
|
|
543
|
-
message = Msg.ERR_CONTAIN_GOGH_ACCESS_IN_STRICT_CONSTRAINT
|
|
544
|
-
raise Exception(message)
|
|
545
|
-
|
|
546
|
-
# strict constraint かつ BoTorchSampler の場合、
|
|
547
|
-
# 最適化実行時に monkey patch を実行するフラグを立てる。
|
|
548
|
-
# ただし using_fem が True ならば非常に低速なので警告を出す。
|
|
549
|
-
if strict and isinstance(self.opt, OptunaOptimizer):
|
|
550
|
-
self.opt: OptunaOptimizer
|
|
551
|
-
from optuna_integration import BoTorchSampler
|
|
552
|
-
if issubclass(self.opt.sampler_class, BoTorchSampler):
|
|
553
|
-
# パッチ実行フラグ
|
|
554
|
-
self.opt._do_monkey_patch = True
|
|
555
|
-
# 警告
|
|
556
|
-
if using_fem:
|
|
557
|
-
logger.warning(Msg.WARN_UPDATE_FEM_PARAMETER_TOOK_A_LONG_TIME)
|
|
558
|
-
|
|
559
|
-
self.opt.constraints[name] = Constraint(fun, name, lower_bound, upper_bound, strict, args, kwargs, using_fem)
|
|
560
|
-
|
|
561
|
-
def get_parameter(self, format='dict'):
|
|
562
|
-
"""Deprecated method.
|
|
563
|
-
|
|
564
|
-
Planed to remove in future version. Use FEMOpt.opt.get_parameter() instead.
|
|
565
|
-
"""
|
|
566
|
-
raise DeprecationWarning('FEMOpt.get_parameter() was deprecated. Use FEMOpt.opt.get_parameter() instead.')
|
|
567
|
-
|
|
568
|
-
def set_monitor_host(self, host=None, port=None):
|
|
569
|
-
"""Sets the host IP address and the port of the process monitor.
|
|
570
|
-
|
|
571
|
-
Args:
|
|
572
|
-
host (str):
|
|
573
|
-
The hostname or IP address of the monitor server.
|
|
574
|
-
port (int, optional):
|
|
575
|
-
The port number of the monitor server.
|
|
576
|
-
If None, ``8080`` will be used.
|
|
577
|
-
Defaults to None.
|
|
578
|
-
|
|
579
|
-
Tip:
|
|
580
|
-
Specifying host ``0.0.0.0`` allows viewing monitor
|
|
581
|
-
from all computers on the local network.
|
|
582
|
-
|
|
583
|
-
If no hostname is specified, the monitor server
|
|
584
|
-
will be hosted on ``localhost``.
|
|
585
|
-
|
|
586
|
-
We can access process monitor by accessing
|
|
587
|
-
```localhost:8080``` on our browser by default.
|
|
588
|
-
|
|
589
|
-
"""
|
|
590
|
-
self.monitor_server_kwargs = dict(
|
|
591
|
-
host=host,
|
|
592
|
-
port=port
|
|
593
|
-
)
|
|
594
|
-
|
|
595
|
-
def optimize(
|
|
596
|
-
self,
|
|
597
|
-
n_trials: int = None,
|
|
598
|
-
n_parallel: int = 1,
|
|
599
|
-
timeout: float = None,
|
|
600
|
-
wait_setup: bool = True,
|
|
601
|
-
confirm_before_exit: bool = True,
|
|
602
|
-
):
|
|
603
|
-
"""Runs the main optimization process.
|
|
604
|
-
|
|
605
|
-
Args:
|
|
606
|
-
n_trials (int, optional):
|
|
607
|
-
The number of trials.
|
|
608
|
-
Defaults to None.
|
|
609
|
-
n_parallel (int, optional):
|
|
610
|
-
The number of parallel processes.
|
|
611
|
-
Defaults to 1.
|
|
612
|
-
Note that even if this argument is 1,
|
|
613
|
-
:class:`FEMOpt` makes some child processes
|
|
614
|
-
to run process monitor, status monitor, etc.
|
|
615
|
-
timeout (float, optional):
|
|
616
|
-
The maximum amount of time in seconds
|
|
617
|
-
that each trial can run.
|
|
618
|
-
Defaults to None.
|
|
619
|
-
wait_setup (bool, optional):
|
|
620
|
-
Wait for all workers launching FEM system.
|
|
621
|
-
Defaults to True.
|
|
622
|
-
confirm_before_exit (bool, optional):
|
|
623
|
-
Insert stop before exit to continue to
|
|
624
|
-
show process monitor.
|
|
625
|
-
|
|
626
|
-
Tip:
|
|
627
|
-
If set_monitor_host() is not executed,
|
|
628
|
-
a local server for monitoring will be
|
|
629
|
-
started at localhost:8080.
|
|
630
|
-
|
|
631
|
-
See Also:
|
|
632
|
-
:func:`FEMOpt.set_monitor_host`
|
|
633
|
-
|
|
634
|
-
Note:
|
|
635
|
-
If ``n_trials`` and ``timeout`` are both None,
|
|
636
|
-
it runs forever until interrupting by the user.
|
|
637
|
-
|
|
638
|
-
Note:
|
|
639
|
-
If ``n_parallel`` >= 2, depending on the end timing,
|
|
640
|
-
``n_trials`` may be exceeded by up to ``n_parallel-1`` times.
|
|
641
|
-
|
|
642
|
-
Warning:
|
|
643
|
-
If ``n_parallel`` >= 2 and ``fem`` is a subclass of
|
|
644
|
-
``FemtetInterface``, the ``strictly_pid_specify`` of
|
|
645
|
-
subprocess is set to ``False``.
|
|
646
|
-
So **it is recommended to close all other Femtet processes
|
|
647
|
-
before running.**
|
|
648
|
-
|
|
649
|
-
"""
|
|
650
|
-
|
|
651
|
-
# ===== opt の設定 =====
|
|
652
|
-
|
|
653
|
-
# Interface から設定を読む場合の処理
|
|
654
|
-
# 設定ファイルから設定を読む場合は最適化問題が
|
|
655
|
-
# この時点で不定なので actor 等の設定をする前に
|
|
656
|
-
# ここで確定する必要がある。
|
|
657
|
-
if hasattr(self.fem, '_load_problem_from_me'):
|
|
658
|
-
if self.fem._load_problem_from_me:
|
|
659
|
-
self.fem.load_parameter(self.opt)
|
|
660
|
-
self.fem.load_objective(self.opt)
|
|
661
|
-
self.fem.load_constraint(self.opt)
|
|
662
|
-
|
|
663
|
-
# resolve expression dependencies
|
|
664
|
-
self.opt.variables.resolve()
|
|
665
|
-
self.opt.variables.evaluate()
|
|
666
|
-
|
|
667
|
-
# opt の共通引数
|
|
668
|
-
self.opt.n_trials = n_trials
|
|
669
|
-
self.opt.timeout = timeout
|
|
670
|
-
|
|
671
|
-
# method checker
|
|
672
|
-
if n_parallel > 1:
|
|
673
|
-
self.opt.method_checker.check_parallel()
|
|
674
|
-
|
|
675
|
-
if timeout is not None:
|
|
676
|
-
self.opt.method_checker.check_timeout()
|
|
677
|
-
|
|
678
|
-
if len(self.opt.objectives) > 1:
|
|
679
|
-
self.opt.method_checker.check_multi_objective()
|
|
680
|
-
|
|
681
|
-
if len(self.opt.constraints) > 0:
|
|
682
|
-
self.opt.method_checker.check_constraint()
|
|
683
|
-
|
|
684
|
-
for key, value in self.opt.constraints.items():
|
|
685
|
-
if value.strict:
|
|
686
|
-
self.opt.method_checker.check_strict_constraint()
|
|
687
|
-
break
|
|
688
|
-
|
|
689
|
-
if self.opt.seed is not None:
|
|
690
|
-
self.opt.method_checker.check_seed()
|
|
691
|
-
|
|
692
|
-
is_incomplete_bounds = False
|
|
693
|
-
prm: Parameter = None
|
|
694
|
-
for prm in self.opt.variables.parameters.values():
|
|
695
|
-
lb, ub = prm.lower_bound, prm.upper_bound
|
|
696
|
-
is_incomplete_bounds = is_incomplete_bounds + (lb is None) + (ub is None)
|
|
697
|
-
if is_incomplete_bounds:
|
|
698
|
-
self.opt.method_checker.check_incomplete_bounds()
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
# ===== fem の設定 ==--=
|
|
702
|
-
|
|
703
|
-
# Femtet 特有の処理
|
|
704
|
-
extra_data = dict()
|
|
705
|
-
if isinstance(self.fem, FemtetInterface):
|
|
706
|
-
|
|
707
|
-
# 結果 csv に記載する femprj に関する情報の作成
|
|
708
|
-
extra_data.update(
|
|
709
|
-
dict(
|
|
710
|
-
femprj_path=self.fem.original_femprj_path,
|
|
711
|
-
model_name=self.fem.model_name
|
|
712
|
-
)
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
# Femtet の parametric 設定を目的関数に用いるかどうか
|
|
716
|
-
if self.fem.parametric_output_indexes_use_as_objective is not None:
|
|
717
|
-
from pyfemtet.opt.interface._femtet_parametric import add_parametric_results_as_objectives
|
|
718
|
-
indexes = list(self.fem.parametric_output_indexes_use_as_objective.keys())
|
|
719
|
-
directions = list(self.fem.parametric_output_indexes_use_as_objective.values())
|
|
720
|
-
add_parametric_results_as_objectives(
|
|
721
|
-
self,
|
|
722
|
-
indexes,
|
|
723
|
-
directions,
|
|
724
|
-
)
|
|
725
|
-
|
|
726
|
-
logger.info('Femtet loaded successfully.')
|
|
727
|
-
|
|
728
|
-
# クラスターの設定
|
|
729
|
-
self.opt.is_cluster = self.scheduler_address is not None
|
|
730
|
-
if self.opt.is_cluster:
|
|
731
|
-
# 既存のクラスターに接続
|
|
732
|
-
logger.info('Connecting to existing cluster.')
|
|
733
|
-
self.client = Client(self.scheduler_address)
|
|
734
|
-
|
|
735
|
-
# 最適化タスクを振り分ける worker を指定
|
|
736
|
-
subprocess_indices = list(range(n_parallel))
|
|
737
|
-
worker_addresses = list(self.client.nthreads().keys())
|
|
738
|
-
|
|
739
|
-
# worker が足りない場合はエラー
|
|
740
|
-
if n_parallel > len(worker_addresses):
|
|
741
|
-
raise RuntimeError(f'n_parallel({n_parallel}) > n_workers({len(worker_addresses)}). There are insufficient number of workers.')
|
|
742
|
-
|
|
743
|
-
# worker が多い場合は閉じる
|
|
744
|
-
if n_parallel < len(worker_addresses):
|
|
745
|
-
used_worker_addresses = worker_addresses[:n_parallel] # 前から順番に選ぶ:CPU の早い / メモリの多い順に並べることが望ましい
|
|
746
|
-
unused_worker_addresses = worker_addresses[n_parallel:]
|
|
747
|
-
self.client.retire_workers(unused_worker_addresses, close_workers=True)
|
|
748
|
-
worker_addresses = used_worker_addresses
|
|
749
|
-
|
|
750
|
-
# monitor worker の設定
|
|
751
|
-
logger.info('Launching monitor server. This may take a few seconds.')
|
|
752
|
-
self.monitor_process_worker_name = datetime.datetime.now().strftime("Monitor%Y%m%d%H%M%S")
|
|
753
|
-
add_worker(self.client, self.monitor_process_worker_name)
|
|
754
|
-
|
|
755
|
-
else:
|
|
756
|
-
# ローカルクラスターを構築
|
|
757
|
-
logger.info('Launching single machine cluster... This may take tens of seconds.')
|
|
758
|
-
|
|
759
|
-
# Fixed:
|
|
760
|
-
# Nanny の管理機能は必要ないが、Python API では worker_class を Worker にすると
|
|
761
|
-
# processes 引数が無視されて Thread worker が立てられる。
|
|
762
|
-
# これは CLI の --no-nanny オプションも同様らしい。
|
|
763
|
-
|
|
764
|
-
# クラスターの構築
|
|
765
|
-
# noinspection PyTypeChecker
|
|
766
|
-
cluster = LocalCluster(
|
|
767
|
-
processes=True,
|
|
768
|
-
n_workers=n_parallel,
|
|
769
|
-
threads_per_worker=1,
|
|
770
|
-
worker_class=Nanny,
|
|
771
|
-
)
|
|
772
|
-
logger.info('LocalCluster launched successfully.')
|
|
773
|
-
|
|
774
|
-
self.client = Client(
|
|
775
|
-
cluster,
|
|
776
|
-
direct_to_workers=False,
|
|
777
|
-
)
|
|
778
|
-
logger.info('Client launched successfully.')
|
|
779
|
-
|
|
780
|
-
self.scheduler_address = self.client.scheduler.address
|
|
781
|
-
|
|
782
|
-
# worker address を取得
|
|
783
|
-
nannies_dict: dict[Any, Nanny] = self.client.cluster.workers
|
|
784
|
-
nannies = tuple(nannies_dict.values())
|
|
785
|
-
|
|
786
|
-
# ひとつの Nanny を選んで monitor 用にしつつ
|
|
787
|
-
# その space は main process に使わせるために記憶する
|
|
788
|
-
self.monitor_process_worker_name = nannies[0].worker_address
|
|
789
|
-
self._extra_space_dir = nannies[0].worker_dir
|
|
790
|
-
|
|
791
|
-
# 名前と address がごちゃごちゃになっていて可読性が悪いが
|
|
792
|
-
# 選んだ以外の Nanny は計算を割り当てる用にする
|
|
793
|
-
worker_addresses = ['Main']
|
|
794
|
-
worker_addresses.extend([n.worker_address for n in nannies[1:]])
|
|
795
|
-
subprocess_indices = list(range(n_parallel))[1:]
|
|
796
|
-
|
|
797
|
-
with self.client.cluster as _cluster, self.client as _client:
|
|
798
|
-
|
|
799
|
-
# ===== status actor の設定 =====
|
|
800
|
-
self.status = OptimizationStatus(_client, worker_address=self.monitor_process_worker_name)
|
|
801
|
-
self.worker_status_list = [OptimizationStatus(_client, worker_address=self.monitor_process_worker_name, name=name) for name in worker_addresses] # tqdm 検討
|
|
802
|
-
self.status.set(OptimizationStatus.SETTING_UP)
|
|
803
|
-
self.monitor_host_record = MonitorHostRecord(_client, self.monitor_process_worker_name)
|
|
804
|
-
logger.info('Status Actor initialized successfully.')
|
|
805
|
-
|
|
806
|
-
# ===== initialize history =====
|
|
807
|
-
self.history = History(
|
|
808
|
-
self.history_path,
|
|
809
|
-
self.opt.variables.get_parameter_names(),
|
|
810
|
-
list(self.opt.objectives.keys()),
|
|
811
|
-
list(self.opt.constraints.keys()),
|
|
812
|
-
_client,
|
|
813
|
-
self._hv_reference
|
|
814
|
-
)
|
|
815
|
-
|
|
816
|
-
# ===== launch monitor =====
|
|
817
|
-
# launch monitor
|
|
818
|
-
self.monitor_process_future = _client.submit(
|
|
819
|
-
# func
|
|
820
|
-
_start_monitor_server,
|
|
821
|
-
# args
|
|
822
|
-
self.history,
|
|
823
|
-
self.status,
|
|
824
|
-
worker_addresses,
|
|
825
|
-
self.worker_status_list,
|
|
826
|
-
self.monitor_host_record,
|
|
827
|
-
# kwargs
|
|
828
|
-
**self.monitor_server_kwargs,
|
|
829
|
-
# kwargs of submit
|
|
830
|
-
workers=self.monitor_process_worker_name,
|
|
831
|
-
allow_other_workers=False
|
|
832
|
-
)
|
|
833
|
-
logger.info('Process monitor initialized successfully.')
|
|
834
|
-
|
|
835
|
-
# update extra_data of history to notify
|
|
836
|
-
# how to emit interruption signal by
|
|
837
|
-
# external processes
|
|
838
|
-
start = time()
|
|
839
|
-
while len(self.monitor_host_record.get()) == 0:
|
|
840
|
-
sleep(0.1)
|
|
841
|
-
extra_data.update(self.monitor_host_record.get())
|
|
842
|
-
self.history.extra_data.update(extra_data)
|
|
843
|
-
|
|
844
|
-
# ===== setup fem and opt before parallelization =====
|
|
845
|
-
# fem
|
|
846
|
-
self.fem._setup_before_parallel(_client)
|
|
847
|
-
|
|
848
|
-
# opt
|
|
849
|
-
self.opt.fem_class = type(self.fem)
|
|
850
|
-
self.opt.fem_kwargs = self.fem.kwargs
|
|
851
|
-
self.opt.entire_status = self.status
|
|
852
|
-
self.opt.history = self.history
|
|
853
|
-
self.opt._setup_before_parallel()
|
|
854
|
-
|
|
855
|
-
# ===== 最適化ループ開始 =====
|
|
856
|
-
# opt から non-serializable な com を
|
|
857
|
-
# 有している可能性のある fem を削除
|
|
858
|
-
# ただし main process の sub thread では
|
|
859
|
-
# これをそのまま使うので buff に退避
|
|
860
|
-
buff = self.opt.fem
|
|
861
|
-
del self.opt.fem
|
|
862
|
-
|
|
863
|
-
# クラスターでの計算開始
|
|
864
|
-
self.status.set(OptimizationStatus.LAUNCHING_FEM)
|
|
865
|
-
start = time()
|
|
866
|
-
calc_futures = _client.map(
|
|
867
|
-
self.opt._run,
|
|
868
|
-
subprocess_indices,
|
|
869
|
-
[self.worker_status_list] * len(subprocess_indices),
|
|
870
|
-
[wait_setup] * len(subprocess_indices),
|
|
871
|
-
workers=worker_addresses if self.opt.is_cluster else worker_addresses[1:],
|
|
872
|
-
allow_other_workers=False,
|
|
873
|
-
)
|
|
874
|
-
|
|
875
|
-
# 退避した fem を戻す
|
|
876
|
-
self.opt.fem = buff
|
|
877
|
-
|
|
878
|
-
# リモートクラスタではない場合
|
|
879
|
-
# main process の sub thread で
|
|
880
|
-
# 計算開始
|
|
881
|
-
t_main = None
|
|
882
|
-
if not self.opt.is_cluster:
|
|
883
|
-
# ローカルプロセスでの計算(opt._run 相当の処理)
|
|
884
|
-
subprocess_idx = 0
|
|
885
|
-
|
|
886
|
-
# set_fem
|
|
887
|
-
self.opt.fem = self.fem
|
|
888
|
-
|
|
889
|
-
# fem の _setup_after_parallel はこの場合も呼ばれる
|
|
890
|
-
t_main = Thread(
|
|
891
|
-
target=self.opt._run,
|
|
892
|
-
args=(
|
|
893
|
-
subprocess_idx,
|
|
894
|
-
self.worker_status_list,
|
|
895
|
-
wait_setup,
|
|
896
|
-
),
|
|
897
|
-
kwargs=dict(
|
|
898
|
-
skip_reconstruct=True,
|
|
899
|
-
space_dir=self._extra_space_dir,
|
|
900
|
-
)
|
|
901
|
-
)
|
|
902
|
-
t_main.start()
|
|
903
|
-
|
|
904
|
-
# ===== save history during optimization =====
|
|
905
|
-
def save_history():
|
|
906
|
-
while True:
|
|
907
|
-
sleep(2)
|
|
908
|
-
try:
|
|
909
|
-
self.history.save()
|
|
910
|
-
except PermissionError:
|
|
911
|
-
logger.warning(Msg.WARN_HISTORY_CSV_NOT_ACCESSIBLE)
|
|
912
|
-
if self.status.get() >= OptimizationStatus.TERMINATED:
|
|
913
|
-
break
|
|
914
|
-
|
|
915
|
-
t_save_history = Thread(target=save_history)
|
|
916
|
-
t_save_history.start()
|
|
917
|
-
|
|
918
|
-
# ===== 終了 =====
|
|
919
|
-
# クラスターの Unexpected Exception のリストを取得
|
|
920
|
-
opt_exceptions: list[Exception or None] = _client.gather(calc_futures) # gather() で終了待ちも兼ねる
|
|
921
|
-
|
|
922
|
-
# ローカルの opt で計算している場合、その Exception も取得
|
|
923
|
-
local_opt_exception: Exception or None = None
|
|
924
|
-
if not self.opt.is_cluster:
|
|
925
|
-
if t_main is not None:
|
|
926
|
-
t_main.join() # 終了待ち
|
|
927
|
-
local_opt_exception = self.opt._exception # Exception を取得
|
|
928
|
-
opt_exceptions.append(local_opt_exception)
|
|
929
|
-
|
|
930
|
-
# 終了シグナルを送る
|
|
931
|
-
self.status.set(OptimizationStatus.TERMINATED)
|
|
932
|
-
end = time()
|
|
933
|
-
|
|
934
|
-
# 一応
|
|
935
|
-
t_save_history.join()
|
|
936
|
-
|
|
937
|
-
# 結果通知
|
|
938
|
-
logger.info(Msg.OPTIMIZATION_FINISHED)
|
|
939
|
-
logger.info(self.history.path)
|
|
940
|
-
|
|
941
|
-
# monitor worker を終了する準備
|
|
942
|
-
# 実際の終了は monitor worker の終了時
|
|
943
|
-
self.status.set(OptimizationStatus.TERMINATE_ALL)
|
|
944
|
-
logger.info(self.monitor_process_future.result())
|
|
945
|
-
sleep(1) # monitor が terminated 状態で少なくとも一度更新されなければ running のまま固まる
|
|
946
|
-
|
|
947
|
-
# 全ての Exception を再表示
|
|
948
|
-
self._opt_exceptions = opt_exceptions
|
|
949
|
-
for i, opt_exception in enumerate(opt_exceptions):
|
|
950
|
-
if opt_exception is not None:
|
|
951
|
-
print()
|
|
952
|
-
print(f'===== unexpected exception raised on worker {i} =====')
|
|
953
|
-
print_exception(opt_exception)
|
|
954
|
-
print()
|
|
955
|
-
|
|
956
|
-
# monitor worker を残してユーザーが結果を確認できるようにする
|
|
957
|
-
# with 文を抜けると monitor worker が終了して
|
|
958
|
-
# daemon thread である run_forever が終了する
|
|
959
|
-
if confirm_before_exit:
|
|
960
|
-
print()
|
|
961
|
-
print('='*len(Msg.CONFIRM_BEFORE_EXIT))
|
|
962
|
-
print(Msg.CONFIRM_BEFORE_EXIT)
|
|
963
|
-
print('='*len(Msg.CONFIRM_BEFORE_EXIT))
|
|
964
|
-
input()
|
|
965
|
-
|
|
966
|
-
df = self.history.get_df() # with 文を抜けると actor は消えるが .copy() はこの段階では不要
|
|
967
|
-
|
|
968
|
-
return df
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
@staticmethod
|
|
972
|
-
def terminate_all():
|
|
973
|
-
"""Deprecated method. We plan to remove this in future version.
|
|
974
|
-
|
|
975
|
-
In current version, the termination processes are
|
|
976
|
-
automatically execute in the last of :func:`FEMOpt.optimize`.
|
|
977
|
-
"""
|
|
978
|
-
warnings.warn(
|
|
979
|
-
"terminate_all() is deprecated and will be removed in a future version. "
|
|
980
|
-
"In current and later versions, the equivalent of terminate_all() will be executed when optimize() finishes. "
|
|
981
|
-
"Therefore, you can simply remove terminate_all() from your code. "
|
|
982
|
-
"If you want to stop program before terminating monitor process, "
|
|
983
|
-
"use ``confirm_before_exit`` argument like ``FEMOpt.optimize(confirm_before_exit=True)``",
|
|
984
|
-
DeprecationWarning,
|
|
985
|
-
stacklevel=2
|
|
986
|
-
)
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
def _start_monitor_server(
|
|
990
|
-
history,
|
|
991
|
-
status,
|
|
992
|
-
worker_addresses,
|
|
993
|
-
worker_status_list,
|
|
994
|
-
host_record,
|
|
995
|
-
host=None,
|
|
996
|
-
port=None,
|
|
997
|
-
):
|
|
998
|
-
process_monitor_main(
|
|
999
|
-
history,
|
|
1000
|
-
status,
|
|
1001
|
-
worker_addresses,
|
|
1002
|
-
worker_status_list,
|
|
1003
|
-
host,
|
|
1004
|
-
port,
|
|
1005
|
-
host_record,
|
|
1006
|
-
)
|
|
1007
|
-
return 'Exit monitor server process gracefully'
|