pyfemtet 0.9.4__py3-none-any.whl → 1.0.0a0__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 -19
- pyfemtet/opt/exceptions.py +45 -0
- pyfemtet/opt/femopt.py +602 -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} +490 -348
- 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/_base.py +0 -129
- pyfemtet/opt/interface/_surrogate_model_interface/__init__.py +8 -0
- pyfemtet/opt/interface/_surrogate_model_interface/base_surrogate_interface.py +59 -0
- pyfemtet/opt/interface/_surrogate_model_interface/botorch_interface.py +271 -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 +876 -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.4.dist-info → pyfemtet-1.0.0a0.dist-info}/METADATA +22 -24
- pyfemtet-1.0.0a0.dist-info/RECORD +173 -0
- pyfemtet-1.0.0a0.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/_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.4.dist-info/RECORD +0 -158
- pyfemtet-0.9.4.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.4.dist-info → pyfemtet-1.0.0a0.dist-info}/LICENSE +0 -0
- {pyfemtet-0.9.4.dist-info → pyfemtet-1.0.0a0.dist-info}/LICENSE_THIRD_PARTY.txt +0 -0
- {pyfemtet-0.9.4.dist-info → pyfemtet-1.0.0a0.dist-info}/WHEEL +0 -0
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
import os
|
|
5
6
|
import sys
|
|
6
|
-
|
|
7
|
-
import winreg
|
|
7
|
+
import warnings
|
|
8
8
|
import subprocess
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import psutil
|
|
12
|
-
import shutil
|
|
13
|
-
from dask.distributed import get_worker
|
|
9
|
+
from time import sleep
|
|
10
|
+
from contextlib import nullcontext
|
|
14
11
|
|
|
15
12
|
# noinspection PyUnresolvedReferences
|
|
16
13
|
from pywintypes import com_error, error
|
|
@@ -20,32 +17,31 @@ from pythoncom import CoInitialize, CoUninitialize
|
|
|
20
17
|
from win32com.client import constants
|
|
21
18
|
import win32con
|
|
22
19
|
import win32gui
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
from pyfemtet.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
from pyfemtet.opt.
|
|
40
|
-
from pyfemtet.
|
|
41
|
-
|
|
42
|
-
from
|
|
43
|
-
|
|
44
|
-
if
|
|
45
|
-
from pyfemtet.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
from pyfemtet.opt.interface._base import logger
|
|
20
|
+
|
|
21
|
+
import pandas as pd
|
|
22
|
+
|
|
23
|
+
from pyfemtet.logger import get_module_logger
|
|
24
|
+
|
|
25
|
+
from pyfemtet._i18n import Msg, _
|
|
26
|
+
from pyfemtet._util.helper import *
|
|
27
|
+
from pyfemtet._util.dask_util import *
|
|
28
|
+
from pyfemtet._util.femtet_exit import *
|
|
29
|
+
from pyfemtet._util.process_util import *
|
|
30
|
+
from pyfemtet._util.femtet_version import *
|
|
31
|
+
from pyfemtet._util.femtet_autosave import *
|
|
32
|
+
from pyfemtet._util.femtet_access_inspection import *
|
|
33
|
+
|
|
34
|
+
from pyfemtet.dispatch_extensions import *
|
|
35
|
+
from pyfemtet.opt.interface._base_interface import COMInterface
|
|
36
|
+
from pyfemtet.opt.exceptions import *
|
|
37
|
+
from pyfemtet.opt.problem.variable_manager import SupportedVariableTypes
|
|
38
|
+
|
|
39
|
+
from ._femtet_parametric import *
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from pyfemtet.opt.optimizer import AbstractOptimizer
|
|
43
|
+
|
|
44
|
+
logger = get_module_logger('opt.interface', False)
|
|
49
45
|
|
|
50
46
|
|
|
51
47
|
def _post_activate_message(hwnd):
|
|
@@ -56,10 +52,7 @@ class FailedToPostProcess(Exception):
|
|
|
56
52
|
pass
|
|
57
53
|
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
class FemtetInterface(FEMInterface):
|
|
55
|
+
class FemtetInterface(COMInterface):
|
|
63
56
|
"""Control Femtet from optimizer.
|
|
64
57
|
|
|
65
58
|
Args:
|
|
@@ -125,24 +118,25 @@ class FemtetInterface(FEMInterface):
|
|
|
125
118
|
|
|
126
119
|
"""
|
|
127
120
|
|
|
121
|
+
com_members = {'Femtet': 'FemtetMacro.Femtet'}
|
|
122
|
+
|
|
128
123
|
def __init__(
|
|
129
124
|
self,
|
|
130
125
|
femprj_path: str = None,
|
|
131
126
|
model_name: str = None,
|
|
132
|
-
connect_method: str =
|
|
133
|
-
save_pdt: str =
|
|
127
|
+
connect_method: str = "auto", # dask worker では __init__ の中で 'new' にする
|
|
128
|
+
save_pdt: str = "all", # 'all', 'none' or 'optimal'
|
|
134
129
|
strictly_pid_specify: bool = True, # dask worker では True にしたいので super() の引数にしない。
|
|
135
130
|
allow_without_project: bool = False, # main でのみ True を許容したいので super() の引数にしない。
|
|
136
131
|
open_result_with_gui: bool = True,
|
|
137
|
-
parametric_output_indexes_use_as_objective: dict[int, str or float] = None,
|
|
138
|
-
|
|
132
|
+
parametric_output_indexes_use_as_objective: dict[int, str or float] = None, # TODO: Remove this
|
|
133
|
+
always_open_copy=False,
|
|
139
134
|
):
|
|
140
135
|
# warning
|
|
141
136
|
if parametric_output_indexes_use_as_objective is not None:
|
|
142
|
-
warnings.warn(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
CoInitialize()
|
|
137
|
+
warnings.warn(
|
|
138
|
+
"解析モデルに設定された既存のスイープテーブルは削除されます。"
|
|
139
|
+
)
|
|
146
140
|
|
|
147
141
|
# 引数の処理
|
|
148
142
|
if femprj_path is None:
|
|
@@ -152,72 +146,110 @@ class FemtetInterface(FEMInterface):
|
|
|
152
146
|
self.model_name = model_name
|
|
153
147
|
self.connect_method = connect_method
|
|
154
148
|
self.allow_without_project = allow_without_project
|
|
155
|
-
self.
|
|
149
|
+
self._original_femprj_path = self.femprj_path
|
|
156
150
|
self.open_result_with_gui = open_result_with_gui
|
|
157
151
|
self.save_pdt = save_pdt
|
|
152
|
+
self._always_open_copy = always_open_copy
|
|
158
153
|
|
|
159
154
|
# その他のメンバーの宣言や初期化
|
|
160
155
|
self.Femtet = None
|
|
161
156
|
self.femtet_pid = 0
|
|
162
157
|
self.quit_when_destruct = False
|
|
163
|
-
self.connected_method =
|
|
164
|
-
self.parameters = None
|
|
158
|
+
self.connected_method = "unconnected"
|
|
165
159
|
self.max_api_retry = 3
|
|
166
160
|
self.strictly_pid_specify = strictly_pid_specify
|
|
167
161
|
self.parametric_output_indexes_use_as_objective = parametric_output_indexes_use_as_objective
|
|
162
|
+
self._load_problem_from_fem = self.parametric_output_indexes_use_as_objective is not None
|
|
168
163
|
self._original_autosave_enabled = _get_autosave_enabled()
|
|
169
164
|
_set_autosave_enabled(False)
|
|
165
|
+
self._warn_if_undefined_variable = True
|
|
166
|
+
self.api_response_warning_time = 10 # mesh, solve, re-execute を除くマクロ実行警告時間
|
|
170
167
|
|
|
171
|
-
#
|
|
172
|
-
try:
|
|
173
|
-
worker = get_worker()
|
|
174
|
-
space = worker.local_directory
|
|
175
|
-
# worker なら femprj_path が None でないはず
|
|
176
|
-
self.femprj_path = os.path.join(space, os.path.basename(self.femprj_path))
|
|
177
|
-
self.connect_method = 'new'
|
|
178
|
-
self.strictly_pid_specify = False
|
|
179
|
-
except ValueError: # get_worker に失敗した場合
|
|
180
|
-
pass
|
|
181
|
-
|
|
182
|
-
# femprj_path と model に基づいて Femtet を開き、
|
|
183
|
-
# 開かれたモデルに応じて femprj_path と model を更新する
|
|
168
|
+
# connect to Femtet
|
|
184
169
|
self._connect_and_open_femtet()
|
|
170
|
+
assert self.connected_method != 'unconnected'
|
|
171
|
+
|
|
172
|
+
if self._always_open_copy:
|
|
173
|
+
# 現時点でFemtet に model を close する機能がない
|
|
174
|
+
# + executor でも CAD 連携等でモデルに
|
|
175
|
+
# わかりにくい変更が入らないように
|
|
176
|
+
# _tmp_dir のファイルを開くようにしたため
|
|
177
|
+
# _tmp_dir 削除時の permission error を
|
|
178
|
+
# 避けるために Femtet を強制 close する
|
|
179
|
+
# Femtet で model が close できるようになれば
|
|
180
|
+
# この条件分岐は不要になる
|
|
181
|
+
self.quit_when_destruct = True
|
|
185
182
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
# dask worker でなければ original のはず
|
|
190
|
-
try:
|
|
191
|
-
_ = get_worker()
|
|
192
|
-
except ValueError:
|
|
193
|
-
self.original_femprj_path = self.femprj_path
|
|
194
|
-
|
|
195
|
-
# 接続した Femtet の種類に応じて del 時に quit するかどうか決める
|
|
196
|
-
self.quit_when_destruct = self.connected_method == 'new'
|
|
183
|
+
else:
|
|
184
|
+
# 接続した Femtet の種類に応じて del 時に quit するかどうか決める
|
|
185
|
+
self.quit_when_destruct = self.connected_method == "new"
|
|
197
186
|
|
|
198
|
-
|
|
199
|
-
# パスなどは connect_and_open_femtet での処理結果を反映し
|
|
200
|
-
# メインで開いた解析モデルが確実に開かれるようにする
|
|
201
|
-
FEMInterface.__init__(
|
|
202
|
-
self,
|
|
203
|
-
femprj_path=self.femprj_path,
|
|
204
|
-
model_name=self.model_name,
|
|
205
|
-
open_result_with_gui=self.open_result_with_gui,
|
|
206
|
-
parametric_output_indexes_use_as_objective=self.parametric_output_indexes_use_as_objective,
|
|
207
|
-
save_pdt=self.save_pdt,
|
|
208
|
-
**kwargs
|
|
209
|
-
)
|
|
187
|
+
# ===== system =====
|
|
210
188
|
|
|
211
189
|
@property
|
|
212
|
-
def
|
|
190
|
+
def object_pass_to_fun(self):
|
|
191
|
+
"""The object pass to the first argument of user-defined objective functions.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Femtet (CDispatch): COM object of Femtet.
|
|
195
|
+
"""
|
|
213
196
|
return self.Femtet
|
|
214
197
|
|
|
215
|
-
def
|
|
198
|
+
def _setup_before_parallel(self):
|
|
199
|
+
self._distribute_files([self.femprj_path])
|
|
200
|
+
|
|
201
|
+
def _setup_after_parallel(self, opt: AbstractOptimizer = None):
|
|
202
|
+
|
|
203
|
+
# main worker かつ always_open_copy でないときのみ
|
|
204
|
+
# femprj_path を切り替えない
|
|
205
|
+
if (get_worker() is None) and not self._always_open_copy:
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
# worker space の femprj に切り替える
|
|
209
|
+
else:
|
|
210
|
+
suffix = self._get_worker_index_from_optimizer(opt)
|
|
211
|
+
self.femprj_path = self._rename_and_get_path_on_worker_space(self._original_femprj_path, suffix)
|
|
212
|
+
|
|
213
|
+
# dask process ならば Femtet を起動
|
|
214
|
+
worker = get_worker()
|
|
215
|
+
if worker is not None:
|
|
216
|
+
CoInitialize()
|
|
217
|
+
self.connect_femtet(connect_method='new')
|
|
218
|
+
self.quit_when_destruct = True
|
|
219
|
+
|
|
220
|
+
# femprj を開く
|
|
221
|
+
self.open(self.femprj_path, self.model_name)
|
|
222
|
+
|
|
223
|
+
def close(self, timeout=15, force=True): # 12 秒程度
|
|
224
|
+
"""Force to terminate connected Femtet."""
|
|
225
|
+
|
|
226
|
+
_set_autosave_enabled(self._original_autosave_enabled)
|
|
227
|
+
|
|
228
|
+
if not hasattr(self, 'Femtet'):
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
if self.Femtet is None:
|
|
232
|
+
return
|
|
233
|
+
|
|
234
|
+
if self.quit_when_destruct:
|
|
235
|
+
logger.info(_('Closing Femtet (pid = {pid}) ...', pid=self.femtet_pid))
|
|
236
|
+
succeeded = _exit_or_force_terminate(
|
|
237
|
+
timeout=timeout, Femtet=self.Femtet, force=force)
|
|
238
|
+
if succeeded:
|
|
239
|
+
logger.info(_('Femtet is closed.'))
|
|
240
|
+
else:
|
|
241
|
+
logger.warning(_('Failed to close Femtet.'))
|
|
242
|
+
|
|
243
|
+
def use_parametric_output_as_objective(
|
|
244
|
+
self, number: int, direction: str | float = "minimize"
|
|
245
|
+
) -> None:
|
|
216
246
|
"""Use output setting of Femtet parametric analysis as an objective function.
|
|
217
247
|
|
|
218
248
|
Args:
|
|
219
249
|
number (int): The index of output settings tab in parametric analysis dialog of Femtet. Starts at 1.
|
|
220
|
-
direction (str | float): Objective direction.
|
|
250
|
+
direction (str | float): Objective direction.
|
|
251
|
+
Valid input is one of 'minimize', 'maximize' or a specific value.
|
|
252
|
+
Defaults to 'minimize'.
|
|
221
253
|
|
|
222
254
|
Returns:
|
|
223
255
|
None
|
|
@@ -225,13 +257,17 @@ class FemtetInterface(FEMInterface):
|
|
|
225
257
|
"""
|
|
226
258
|
# check
|
|
227
259
|
if isinstance(direction, str):
|
|
228
|
-
if direction not in (
|
|
229
|
-
raise ValueError(
|
|
260
|
+
if direction not in ("minimize", "maximize"):
|
|
261
|
+
raise ValueError(
|
|
262
|
+
f'direction must be one of "minimize", "maximize" or a specific value. Passed value is {direction}'
|
|
263
|
+
)
|
|
230
264
|
else:
|
|
231
265
|
try:
|
|
232
266
|
direction = float(direction)
|
|
233
267
|
except (TypeError, ValueError):
|
|
234
|
-
raise ValueError(
|
|
268
|
+
raise ValueError(
|
|
269
|
+
f'direction must be one of "minimize", "maximize" or a specific value. Passed value is {direction}'
|
|
270
|
+
)
|
|
235
271
|
|
|
236
272
|
index = {number - 1: direction}
|
|
237
273
|
|
|
@@ -241,35 +277,44 @@ class FemtetInterface(FEMInterface):
|
|
|
241
277
|
else:
|
|
242
278
|
self.parametric_output_indexes_use_as_objective.update(index)
|
|
243
279
|
|
|
244
|
-
|
|
245
|
-
|
|
280
|
+
self._load_problem_from_fem = True
|
|
281
|
+
|
|
282
|
+
def load_objectives(self, opt: AbstractOptimizer):
|
|
283
|
+
indexes = list(self.parametric_output_indexes_use_as_objective.keys())
|
|
284
|
+
directions = list(self.parametric_output_indexes_use_as_objective.values())
|
|
285
|
+
add_parametric_results_as_objectives(
|
|
286
|
+
opt, self.Femtet, indexes, directions
|
|
287
|
+
)
|
|
246
288
|
|
|
289
|
+
def _check_using_fem(self, fun: callable):
|
|
290
|
+
return _is_access_femtet(fun)
|
|
247
291
|
|
|
248
|
-
|
|
249
|
-
self.quit()
|
|
250
|
-
# CoUninitialize() # Win32 exception occurred releasing IUnknown at 0x0000022427692748
|
|
292
|
+
# ===== connect_femtet =====
|
|
251
293
|
|
|
252
294
|
def _connect_new_femtet(self):
|
|
253
|
-
logger.info(
|
|
295
|
+
logger.info("└ Try to launch and connect new Femtet process.")
|
|
254
296
|
|
|
255
|
-
self.Femtet, self.femtet_pid = launch_and_dispatch_femtet(
|
|
297
|
+
self.Femtet, self.femtet_pid = launch_and_dispatch_femtet(
|
|
298
|
+
strictly_pid_specify=self.strictly_pid_specify
|
|
299
|
+
)
|
|
256
300
|
|
|
257
|
-
self.connected_method =
|
|
301
|
+
self.connected_method = "new"
|
|
258
302
|
|
|
259
303
|
def _connect_existing_femtet(self, pid: int or None = None):
|
|
260
|
-
logger.info(
|
|
304
|
+
logger.info("└ Try to connect existing Femtet process.")
|
|
261
305
|
# 既存の Femtet を探して Dispatch する。
|
|
262
306
|
if pid is None:
|
|
263
307
|
self.Femtet, self.femtet_pid = dispatch_femtet(timeout=5)
|
|
264
308
|
else:
|
|
265
309
|
self.Femtet, self.femtet_pid = dispatch_specific_femtet(pid, timeout=5)
|
|
266
|
-
self.connected_method =
|
|
310
|
+
self.connected_method = "existing"
|
|
267
311
|
|
|
268
|
-
def connect_femtet(self, connect_method: str =
|
|
312
|
+
def connect_femtet(self, connect_method: str = "auto", pid: int or None = None):
|
|
269
313
|
"""Connects to a Femtet process.
|
|
270
314
|
|
|
271
315
|
Args:
|
|
272
|
-
connect_method (str, optional): The connection method.
|
|
316
|
+
connect_method (str, optional): The connection method.
|
|
317
|
+
Can be 'new', 'existing', or 'auto'. Defaults to 'auto'.
|
|
273
318
|
pid (int or None, optional): The process ID of an existing Femtet process and wanted to connect.
|
|
274
319
|
|
|
275
320
|
Note:
|
|
@@ -289,33 +334,136 @@ class FemtetInterface(FEMInterface):
|
|
|
289
334
|
|
|
290
335
|
"""
|
|
291
336
|
|
|
292
|
-
if connect_method ==
|
|
337
|
+
if connect_method == "new":
|
|
293
338
|
self._connect_new_femtet()
|
|
294
339
|
|
|
295
|
-
elif connect_method ==
|
|
340
|
+
elif connect_method == "existing":
|
|
296
341
|
self._connect_existing_femtet(pid)
|
|
297
342
|
|
|
298
|
-
elif connect_method ==
|
|
343
|
+
elif connect_method == "auto":
|
|
299
344
|
try:
|
|
300
345
|
self._connect_existing_femtet(pid)
|
|
301
346
|
except DispatchExtensionException:
|
|
302
347
|
self._connect_new_femtet()
|
|
303
348
|
|
|
304
349
|
else:
|
|
305
|
-
raise Exception(f
|
|
350
|
+
raise Exception(f"{connect_method} は定義されていない接続方法です")
|
|
306
351
|
|
|
307
352
|
# ensure makepy
|
|
308
|
-
if not hasattr(constants,
|
|
309
|
-
cmd = f
|
|
353
|
+
if not hasattr(constants, "STATIC_C"):
|
|
354
|
+
cmd = f"{sys.executable} -m win32com.client.makepy FemtetMacro"
|
|
310
355
|
subprocess.run(cmd, shell=True)
|
|
311
|
-
|
|
312
|
-
|
|
356
|
+
|
|
357
|
+
message = _(
|
|
358
|
+
en_message='It was detected that the configuration of '
|
|
359
|
+
'Femtet python macro constants has not been '
|
|
360
|
+
'completed. The configuration was done '
|
|
361
|
+
'automatically '
|
|
362
|
+
'(python -m win32com.client.makepy FemtetMacro). '
|
|
363
|
+
'Please restart the program. '
|
|
364
|
+
'If the error persists, please run '
|
|
365
|
+
'"py -m win32com.client.makepy FemtetMacro" '
|
|
366
|
+
'or "python -m win32com.client.makepy FemtetMacro" '
|
|
367
|
+
'on the command prompt.',
|
|
368
|
+
jp_message='Femtet Pythonマクロ定数の設定が完了していない'
|
|
369
|
+
'ことが検出されました。設定は自動で行われました'
|
|
370
|
+
'(py -m win32com.client.makepy FemtetMacro)。 '
|
|
371
|
+
'プログラムを再起動してください。'
|
|
372
|
+
'エラーが解消されない場合は、'
|
|
373
|
+
'"py -m win32com.client.makepy FemtetMacro" か '
|
|
374
|
+
'"python -m win32com.client.makepy FemtetMacro" '
|
|
375
|
+
'コマンドをコマンドプロンプトで実行してください。'
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
logger.error("================")
|
|
313
379
|
logger.error(message)
|
|
314
|
-
logger.error(
|
|
380
|
+
logger.error("================")
|
|
315
381
|
raise RuntimeError(message)
|
|
316
382
|
|
|
317
383
|
if self.Femtet is None:
|
|
318
|
-
raise RuntimeError(
|
|
384
|
+
raise RuntimeError(_(
|
|
385
|
+
en_message='Failed to connect to Femtet.',
|
|
386
|
+
jp_message='Femtet への接続に失敗しました。',
|
|
387
|
+
))
|
|
388
|
+
|
|
389
|
+
def open(self, femprj_path: str, model_name: str or None = None) -> None:
|
|
390
|
+
"""Open specific analysis model with connected Femtet."""
|
|
391
|
+
|
|
392
|
+
# 引数の処理
|
|
393
|
+
self.femprj_path = os.path.abspath(femprj_path)
|
|
394
|
+
self.model_name = model_name
|
|
395
|
+
# 開く
|
|
396
|
+
if self.model_name is None:
|
|
397
|
+
result = self.Femtet.LoadProject(self.femprj_path, True)
|
|
398
|
+
else:
|
|
399
|
+
result = self.Femtet.LoadProjectAndAnalysisModel(
|
|
400
|
+
self.femprj_path, self.model_name, True
|
|
401
|
+
)
|
|
402
|
+
if not result:
|
|
403
|
+
self.Femtet.ShowLastError()
|
|
404
|
+
|
|
405
|
+
def _connect_and_open_femtet(self):
|
|
406
|
+
"""Connects to a Femtet process and open the femprj.
|
|
407
|
+
|
|
408
|
+
This function is for establishing a connection with Femtet and opening the specified femprj file.
|
|
409
|
+
|
|
410
|
+
At the beginning of the function, we check if femprj_path is specified.
|
|
411
|
+
|
|
412
|
+
If femprj_path is specified, first connect to Femtet using the specified connection method. Then, if the project path of the connected Femtet is different from the specified femprj_path, open the project using the open function. Also, if model_name is specified, the project will be opened using the open function even if the Femtet analysis model name is different from the specified model_name.
|
|
413
|
+
|
|
414
|
+
On the other hand, if femprj_path is not specified, an error message will be displayed stating that femprj_path must be specified in order to use the "new" connection method. If the connection method is not "new", it will try to connect to an existing Femtet instance. If the connection is successful, the project path and analysis model name of the Femtet instance will be stored as femprj_path and model_name.
|
|
415
|
+
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
logger.info(f'Try to connect Femtet (method: "{self.connect_method}").')
|
|
419
|
+
logger.info(
|
|
420
|
+
f'│ femprj: {self.femprj_path if self.femprj_path is not None else "not specified."}'
|
|
421
|
+
)
|
|
422
|
+
logger.info(
|
|
423
|
+
f'│ model: {self.model_name if self.femprj_path is not None else "not specified."}'
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
# femprj が指定されている
|
|
427
|
+
if self.femprj_path is not None:
|
|
428
|
+
# 指定された方法で接続してみて
|
|
429
|
+
# 接続した Femtet と指定された femprj 及び model が異なれば
|
|
430
|
+
# 接続した Femtet で指定された femprj 及び model を開く
|
|
431
|
+
self.connect_femtet(self.connect_method)
|
|
432
|
+
|
|
433
|
+
# プロジェクトの相違をチェック
|
|
434
|
+
if self.Femtet.ProjectPath != self.femprj_path:
|
|
435
|
+
self.open(self.femprj_path, self.model_name)
|
|
436
|
+
|
|
437
|
+
# モデルが指定されていればその相違もチェック
|
|
438
|
+
if self.model_name is not None:
|
|
439
|
+
if self.Femtet.AnalysisModelName != self.model_name:
|
|
440
|
+
self.open(self.femprj_path, self.model_name)
|
|
441
|
+
|
|
442
|
+
# femprj が指定されていない
|
|
443
|
+
else:
|
|
444
|
+
# かつ new だと解析すべき femprj がわからないのでエラー
|
|
445
|
+
if (self.connect_method == "new") and (not self.allow_without_project):
|
|
446
|
+
raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
|
|
447
|
+
|
|
448
|
+
# さらに auto の場合は Femtet が存在しなければ new と同じ挙動になるので同様の処理
|
|
449
|
+
if (
|
|
450
|
+
(self.connect_method == "auto")
|
|
451
|
+
and (len(_get_pids(process_name="Femtet.exe")) == 0)
|
|
452
|
+
and (not self.allow_without_project)
|
|
453
|
+
):
|
|
454
|
+
raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
|
|
455
|
+
self.connect_femtet(self.connect_method)
|
|
456
|
+
|
|
457
|
+
# 最終的に接続した Femtet の femprj_path と model を インスタンスに戻す
|
|
458
|
+
self.femprj_path = self.Femtet.Project
|
|
459
|
+
self.model_name = self.Femtet.AnalysisModelName
|
|
460
|
+
|
|
461
|
+
# femprj が指定されていなければこの時点でのパスをオリジナルとする
|
|
462
|
+
if self._original_femprj_path is None:
|
|
463
|
+
assert get_worker() is None
|
|
464
|
+
self._original_femprj_path = self.femprj_path
|
|
465
|
+
|
|
466
|
+
# ===== call femtet API =====
|
|
319
467
|
|
|
320
468
|
def _check_gaudi_accessible(self) -> bool:
|
|
321
469
|
try:
|
|
@@ -326,12 +474,12 @@ class FemtetInterface(FEMInterface):
|
|
|
326
474
|
return True
|
|
327
475
|
|
|
328
476
|
# noinspection PyMethodMayBeStatic
|
|
329
|
-
def _construct_femtet_api(self, string): # static にしてはいけない
|
|
477
|
+
def _construct_femtet_api(self, string: str | callable): # static にしてはいけない
|
|
330
478
|
if isinstance(string, str):
|
|
331
|
-
if string.startswith(
|
|
479
|
+
if string.startswith("self."):
|
|
332
480
|
return eval(string)
|
|
333
481
|
else:
|
|
334
|
-
return eval(
|
|
482
|
+
return eval("self." + string)
|
|
335
483
|
else:
|
|
336
484
|
return string # Callable
|
|
337
485
|
|
|
@@ -348,6 +496,72 @@ class FemtetInterface(FEMInterface):
|
|
|
348
496
|
recourse_depth=0,
|
|
349
497
|
print_indent=0,
|
|
350
498
|
):
|
|
499
|
+
|
|
500
|
+
context = None
|
|
501
|
+
|
|
502
|
+
# Solve, Mesh, ReExecute は時間計測しない
|
|
503
|
+
if callable(fun):
|
|
504
|
+
name = fun.__name__
|
|
505
|
+
if fun.__name__ == 'Solve':
|
|
506
|
+
context = nullcontext()
|
|
507
|
+
|
|
508
|
+
elif isinstance(fun, str):
|
|
509
|
+
|
|
510
|
+
if fun in ('self.Femtet.Gaudi.ReExecute', 'self.Femtet.Gaudi.Mesh'):
|
|
511
|
+
context = nullcontext()
|
|
512
|
+
name = fun.split('.')[-1]
|
|
513
|
+
|
|
514
|
+
else:
|
|
515
|
+
raise NotImplementedError
|
|
516
|
+
|
|
517
|
+
if context is None:
|
|
518
|
+
warning_time_sec = self.api_response_warning_time
|
|
519
|
+
context = time_counting(
|
|
520
|
+
name=name,
|
|
521
|
+
warning_time_sec=warning_time_sec,
|
|
522
|
+
warning_fun=lambda: logger.warning(
|
|
523
|
+
_(
|
|
524
|
+
'{name} does not finish in {warning_time_sec} seconds. '
|
|
525
|
+
'If the optimization is hanging, the most reason is '
|
|
526
|
+
'a dialog is opening in Femtet and it waits for your '
|
|
527
|
+
'input. Please confirm there is no dialog in Femtet.',
|
|
528
|
+
'{name} の実行に {warning_time_sec} 以上かかっています。'
|
|
529
|
+
'もし最適化がハングしているならば、考えられる理由として、'
|
|
530
|
+
'Femtet で予期せずダイアログが開いてユーザーの入力待ちをしている場合があります。'
|
|
531
|
+
'もし Femtet でダイアログが開いていれば、閉じてください。',
|
|
532
|
+
name=name,
|
|
533
|
+
warning_time_sec=warning_time_sec,
|
|
534
|
+
)
|
|
535
|
+
),
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
with context:
|
|
539
|
+
return self._call_femtet_api_core(
|
|
540
|
+
fun,
|
|
541
|
+
return_value_if_failed,
|
|
542
|
+
if_error,
|
|
543
|
+
error_message,
|
|
544
|
+
is_Gaudi_method,
|
|
545
|
+
ret_for_check_idx,
|
|
546
|
+
args,
|
|
547
|
+
kwargs,
|
|
548
|
+
recourse_depth,
|
|
549
|
+
print_indent,
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
def _call_femtet_api_core(
|
|
553
|
+
self,
|
|
554
|
+
fun,
|
|
555
|
+
return_value_if_failed,
|
|
556
|
+
if_error,
|
|
557
|
+
error_message,
|
|
558
|
+
is_Gaudi_method=False,
|
|
559
|
+
ret_for_check_idx=None,
|
|
560
|
+
args=None,
|
|
561
|
+
kwargs=None,
|
|
562
|
+
recourse_depth=0,
|
|
563
|
+
print_indent=0,
|
|
564
|
+
):
|
|
351
565
|
"""Internal method. Call Femtet API with error handling.
|
|
352
566
|
|
|
353
567
|
Parameters
|
|
@@ -390,26 +604,33 @@ class FemtetInterface(FEMInterface):
|
|
|
390
604
|
|
|
391
605
|
# 実行する API をデバッグ出力
|
|
392
606
|
if isinstance(fun, str):
|
|
393
|
-
logger.debug(
|
|
607
|
+
logger.debug(
|
|
608
|
+
" " * print_indent + f"Femtet API:{fun}, args:{args}, kwargs:{kwargs}"
|
|
609
|
+
)
|
|
394
610
|
else:
|
|
395
|
-
logger.debug(
|
|
611
|
+
logger.debug(
|
|
612
|
+
" " * print_indent
|
|
613
|
+
+ f"Femtet API:{fun.__name__}, args:{args}, kwargs:{kwargs}"
|
|
614
|
+
)
|
|
396
615
|
|
|
397
616
|
# Gaudi コマンドなら Gaudi.Activate する
|
|
398
|
-
if
|
|
617
|
+
if (
|
|
618
|
+
is_Gaudi_method
|
|
619
|
+
): # Optimizer は Gogh に触らないので全部にこれをつけてもいい気がする
|
|
399
620
|
try:
|
|
400
621
|
# まず Gaudi にアクセスできるか
|
|
401
622
|
gaudi_accessible = self._check_gaudi_accessible()
|
|
402
623
|
if gaudi_accessible:
|
|
403
624
|
# Gaudi にアクセスできるなら Gaudi を Activate する
|
|
404
|
-
fun = self._construct_femtet_api(fun) #
|
|
405
|
-
if fun.__name__ !=
|
|
625
|
+
fun = self._construct_femtet_api(fun) # str | callable -> callable
|
|
626
|
+
if fun.__name__ != "Activate":
|
|
406
627
|
# 再帰ループにならないように
|
|
407
628
|
self._call_femtet_api(
|
|
408
629
|
self.Femtet.Gaudi.Activate,
|
|
409
630
|
False, # None 以外なら何でもいい
|
|
410
631
|
Exception,
|
|
411
|
-
'Gaudi
|
|
412
|
-
print_indent=print_indent + 1
|
|
632
|
+
'Failed to Femtet.Gaudi.Activate()',
|
|
633
|
+
print_indent=print_indent + 1,
|
|
413
634
|
)
|
|
414
635
|
|
|
415
636
|
else:
|
|
@@ -427,18 +648,25 @@ class FemtetInterface(FEMInterface):
|
|
|
427
648
|
|
|
428
649
|
# gaudi_accessible なので関数が何であろうが安全にアクセスはできる
|
|
429
650
|
if isinstance(fun, str):
|
|
430
|
-
fun = self._construct_femtet_api(fun) #
|
|
651
|
+
fun = self._construct_femtet_api(fun) # str | callable -> callable
|
|
431
652
|
|
|
432
653
|
# 解析結果を開いた状態で Gaudi.Activate して ReExecute する場合、ReExecute の前後にアクティブ化イベントが必要
|
|
433
654
|
# さらに、プロジェクトツリーが開いていないとアクティブ化イベントも意味がないらしい。
|
|
434
|
-
if fun.__name__ ==
|
|
435
|
-
if
|
|
655
|
+
if fun.__name__ == "ReExecute":
|
|
656
|
+
if (
|
|
657
|
+
self.open_result_with_gui
|
|
658
|
+
or self.parametric_output_indexes_use_as_objective
|
|
659
|
+
):
|
|
436
660
|
_post_activate_message(self.Femtet.hWnd)
|
|
437
661
|
# API を実行
|
|
438
662
|
returns = fun(*args, **kwargs) # can raise pywintypes.error
|
|
439
|
-
if
|
|
663
|
+
if (
|
|
664
|
+
self.open_result_with_gui
|
|
665
|
+
or self.parametric_output_indexes_use_as_objective
|
|
666
|
+
):
|
|
440
667
|
_post_activate_message(self.Femtet.hWnd)
|
|
441
668
|
else:
|
|
669
|
+
import sys
|
|
442
670
|
returns = fun(*args, **kwargs)
|
|
443
671
|
|
|
444
672
|
# API の実行に失敗
|
|
@@ -449,7 +677,7 @@ class FemtetInterface(FEMInterface):
|
|
|
449
677
|
returns = return_value_if_failed
|
|
450
678
|
else:
|
|
451
679
|
returns = [return_value_if_failed] * (ret_for_check_idx + 1)
|
|
452
|
-
logger.debug(
|
|
680
|
+
logger.debug(" " * print_indent + f"Femtet API result:{returns}")
|
|
453
681
|
|
|
454
682
|
# チェックすべき値の抽出
|
|
455
683
|
if ret_for_check_idx is None:
|
|
@@ -468,25 +696,37 @@ class FemtetInterface(FEMInterface):
|
|
|
468
696
|
if self.femtet_is_alive():
|
|
469
697
|
# 生きていてもここにきているなら
|
|
470
698
|
# 指定された Exception を送出する
|
|
471
|
-
logger.debug(
|
|
699
|
+
logger.debug(" " * print_indent + error_message)
|
|
472
700
|
raise if_error(error_message)
|
|
473
701
|
|
|
474
702
|
# 死んでいるなら再起動
|
|
475
703
|
else:
|
|
476
704
|
# 再起動試行回数の上限に達していたら諦める
|
|
477
|
-
logger.debug(
|
|
705
|
+
logger.debug(
|
|
706
|
+
" " * print_indent + f"現在の Femtet 再起動回数: {recourse_depth}"
|
|
707
|
+
)
|
|
478
708
|
if recourse_depth >= self.max_api_retry:
|
|
479
|
-
raise Exception(
|
|
709
|
+
raise Exception(
|
|
710
|
+
Msg.F_ERR_FEMTET_CRASHED_AND_RESTART_FAILED(
|
|
711
|
+
fun.__name__
|
|
712
|
+
)
|
|
713
|
+
)
|
|
480
714
|
|
|
481
715
|
# 再起動
|
|
482
|
-
logger.
|
|
716
|
+
logger.warning(
|
|
717
|
+
" " * print_indent + Msg.F_WARN_FEMTET_CRASHED_AND_TRY_RESTART(
|
|
718
|
+
fun.__name__
|
|
719
|
+
)
|
|
720
|
+
)
|
|
483
721
|
CoInitialize()
|
|
484
|
-
self.connect_femtet(connect_method=
|
|
722
|
+
self.connect_femtet(connect_method="new")
|
|
485
723
|
self.open(self.femprj_path, self.model_name)
|
|
486
724
|
|
|
487
725
|
# 状態を復元するために一度変数を渡して解析を行う(fun.__name__がSolveなら2度手間だが)
|
|
488
|
-
logger.info(
|
|
489
|
-
|
|
726
|
+
logger.info(" " * print_indent + Msg.INFO_FEMTET_CRASHED_AND_RESTARTED)
|
|
727
|
+
|
|
728
|
+
self.update_parameter(self.current_prm_values)
|
|
729
|
+
self.update()
|
|
490
730
|
|
|
491
731
|
# 与えられた API の再帰的再試行
|
|
492
732
|
return self._call_femtet_api(
|
|
@@ -499,90 +739,27 @@ class FemtetInterface(FEMInterface):
|
|
|
499
739
|
args,
|
|
500
740
|
kwargs,
|
|
501
741
|
recourse_depth + 1,
|
|
502
|
-
print_indent + 1
|
|
742
|
+
print_indent + 1,
|
|
503
743
|
)
|
|
504
744
|
|
|
505
745
|
def femtet_is_alive(self) -> bool:
|
|
506
746
|
"""Returns connected femtet process is existing or not."""
|
|
507
|
-
return _get_pid(self.Femtet.hWnd) > 0 # hWnd の値はすでに Femtet が終了している場合は 0
|
|
508
|
-
|
|
509
|
-
def open(self, femprj_path: str, model_name: str or None = None) -> None:
|
|
510
|
-
"""Open specific analysis model with connected Femtet."""
|
|
511
747
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if self.model_name is None:
|
|
517
|
-
result = self.Femtet.LoadProject(
|
|
518
|
-
self.femprj_path,
|
|
519
|
-
True
|
|
520
|
-
)
|
|
521
|
-
else:
|
|
522
|
-
result = self.Femtet.LoadProjectAndAnalysisModel(
|
|
523
|
-
self.femprj_path,
|
|
524
|
-
self.model_name,
|
|
525
|
-
True
|
|
526
|
-
)
|
|
527
|
-
if not result:
|
|
528
|
-
self.Femtet.ShowLastError()
|
|
529
|
-
|
|
530
|
-
def _connect_and_open_femtet(self):
|
|
531
|
-
"""Connects to a Femtet process and open the femprj.
|
|
532
|
-
|
|
533
|
-
This function is for establishing a connection with Femtet and opening the specified femprj file.
|
|
534
|
-
|
|
535
|
-
At the beginning of the function, we check if femprj_path is specified.
|
|
536
|
-
|
|
537
|
-
If femprj_path is specified, first connect to Femtet using the specified connection method. Then, if the project path of the connected Femtet is different from the specified femprj_path, open the project using the open function. Also, if model_name is specified, the project will be opened using the open function even if the Femtet analysis model name is different from the specified model_name.
|
|
538
|
-
|
|
539
|
-
On the other hand, if femprj_path is not specified, an error message will be displayed stating that femprj_path must be specified in order to use the "new" connection method. If the connection method is not "new", it will try to connect to an existing Femtet instance. If the connection is successful, the project path and analysis model name of the Femtet instance will be stored as femprj_path and model_name.
|
|
540
|
-
|
|
541
|
-
"""
|
|
542
|
-
|
|
543
|
-
logger.info(f'Try to connect Femtet (method: "{self.connect_method}").')
|
|
544
|
-
logger.info(f'│ femprj: {self.femprj_path if self.femprj_path is not None else "not specified."}')
|
|
545
|
-
logger.info(f'│ model: {self.model_name if self.femprj_path is not None else "not specified."}')
|
|
546
|
-
|
|
547
|
-
# femprj が指定されている
|
|
548
|
-
if self.femprj_path is not None:
|
|
549
|
-
# 指定された方法で接続してみて
|
|
550
|
-
# 接続した Femtet と指定された femprj 及び model が異なれば
|
|
551
|
-
# 接続した Femtet で指定された femprj 及び model を開く
|
|
552
|
-
self.connect_femtet(self.connect_method)
|
|
553
|
-
|
|
554
|
-
# プロジェクトの相違をチェック
|
|
555
|
-
if self.Femtet.ProjectPath != self.femprj_path:
|
|
556
|
-
self.open(self.femprj_path, self.model_name)
|
|
748
|
+
try:
|
|
749
|
+
hwnd = self.Femtet.hWnd
|
|
750
|
+
except (com_error, AttributeError):
|
|
751
|
+
return False
|
|
557
752
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if self.Femtet.AnalysisModelName != self.model_name:
|
|
561
|
-
self.open(self.femprj_path, self.model_name)
|
|
753
|
+
if hwnd == 0:
|
|
754
|
+
return False
|
|
562
755
|
|
|
563
|
-
|
|
564
|
-
else:
|
|
565
|
-
# かつ new だと解析すべき femprj がわからないのでエラー
|
|
566
|
-
if (
|
|
567
|
-
(self.connect_method == 'new')
|
|
568
|
-
and (not self.allow_without_project)
|
|
569
|
-
):
|
|
570
|
-
raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
|
|
756
|
+
pid = _get_pid(hwnd)
|
|
571
757
|
|
|
572
|
-
|
|
573
|
-
if (
|
|
574
|
-
(self.connect_method == 'auto')
|
|
575
|
-
and (len(_get_pids(process_name='Femtet.exe')) == 0)
|
|
576
|
-
and (not self.allow_without_project)
|
|
577
|
-
):
|
|
578
|
-
raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
|
|
579
|
-
self.connect_femtet(self.connect_method)
|
|
758
|
+
return pid > 0
|
|
580
759
|
|
|
581
|
-
|
|
582
|
-
self.femprj_path = self.Femtet.Project
|
|
583
|
-
self.model_name = self.Femtet.AnalysisModelName
|
|
760
|
+
# ===== model check and solve =====
|
|
584
761
|
|
|
585
|
-
def
|
|
762
|
+
def _check_param_and_raise(self, param_name) -> None:
|
|
586
763
|
"""Check param_name is set in femprj file or not.
|
|
587
764
|
|
|
588
765
|
Note:
|
|
@@ -595,45 +772,53 @@ class FemtetInterface(FEMInterface):
|
|
|
595
772
|
try:
|
|
596
773
|
variable_names = self.Femtet.GetVariableNames_py()
|
|
597
774
|
except AttributeError as e:
|
|
598
|
-
logger.error(
|
|
599
|
-
logger.error(Msg.ERR_CANNOT_ACCESS_API +
|
|
775
|
+
logger.error("================")
|
|
776
|
+
logger.error(Msg.ERR_CANNOT_ACCESS_API + "GetVariableNames_py")
|
|
600
777
|
logger.error(Msg.CERTIFY_MACRO_VERSION)
|
|
601
|
-
logger.error(
|
|
778
|
+
logger.error("================")
|
|
602
779
|
raise e
|
|
603
|
-
|
|
780
|
+
|
|
604
781
|
if variable_names is not None:
|
|
605
782
|
if param_name in variable_names:
|
|
606
783
|
return self.Femtet.GetVariableValue(param_name)
|
|
607
784
|
message = Msg.ERR_NO_SUCH_PARAMETER_IN_FEMTET
|
|
608
|
-
logger.error(
|
|
785
|
+
logger.error("================")
|
|
609
786
|
logger.error(message)
|
|
610
|
-
logger.error(f
|
|
611
|
-
logger.error(
|
|
787
|
+
logger.error(f"`{param_name}` not in {variable_names}")
|
|
788
|
+
logger.error("================")
|
|
612
789
|
raise RuntimeError(message)
|
|
613
790
|
else:
|
|
614
791
|
return None
|
|
615
792
|
|
|
616
|
-
def update_parameter(self,
|
|
793
|
+
def update_parameter(self, x: dict[str, SupportedVariableTypes], with_warning=False) -> None | list[str]:
|
|
617
794
|
"""Update parameter of femprj."""
|
|
618
|
-
self
|
|
795
|
+
COMInterface.update_parameter(self, x)
|
|
619
796
|
|
|
620
|
-
#
|
|
797
|
+
# Gaudi.Activate()
|
|
621
798
|
sleep(0.1) # Gaudi がおかしくなる時がある対策
|
|
622
799
|
self._call_femtet_api(
|
|
623
|
-
|
|
800
|
+
"self.Femtet.Gaudi.Activate",
|
|
624
801
|
True, # 戻り値を持たないのでここは無意味で None 以外なら何でもいい
|
|
625
802
|
Exception, # 生きてるのに開けない場合
|
|
626
803
|
error_message=Msg.NO_ANALYSIS_MODEL_IS_OPEN,
|
|
627
804
|
)
|
|
628
805
|
|
|
806
|
+
# Version check
|
|
629
807
|
major, minor, bugfix = 2023, 1, 1
|
|
808
|
+
|
|
809
|
+
# 変数一覧を取得する関数がある
|
|
630
810
|
if self._version() >= _version(major, minor, bugfix):
|
|
631
|
-
|
|
811
|
+
|
|
812
|
+
# Femtet で定義されている変数の取得
|
|
813
|
+
# (2023.1.1 以降でマクロだけ古い場合は
|
|
814
|
+
# check_param_value で引っかかっている
|
|
815
|
+
# はずなのでここは AttributeError を
|
|
816
|
+
# チェックしない)
|
|
632
817
|
existing_variable_names = self._call_femtet_api(
|
|
633
818
|
fun=self.Femtet.GetVariableNames_py,
|
|
634
819
|
return_value_if_failed=False, # 意味がない
|
|
635
820
|
if_error=ModelError, # 生きてるのに失敗した場合
|
|
636
|
-
error_message=f
|
|
821
|
+
error_message=f"GetVariableNames_py failed.",
|
|
637
822
|
is_Gaudi_method=True,
|
|
638
823
|
)
|
|
639
824
|
|
|
@@ -644,57 +829,62 @@ class FemtetInterface(FEMInterface):
|
|
|
644
829
|
else:
|
|
645
830
|
return None
|
|
646
831
|
|
|
647
|
-
#
|
|
648
|
-
|
|
649
|
-
for
|
|
650
|
-
|
|
651
|
-
|
|
832
|
+
# 変数を更新
|
|
833
|
+
warning_messages = []
|
|
834
|
+
for name, value in self.current_prm_values.items():
|
|
835
|
+
|
|
836
|
+
# 渡された変数がちゃんと Femtet に定義されている
|
|
652
837
|
if name in existing_variable_names:
|
|
838
|
+
|
|
839
|
+
# Femtet.UpdateVariable
|
|
653
840
|
self._call_femtet_api(
|
|
654
841
|
fun=self.Femtet.UpdateVariable,
|
|
655
842
|
return_value_if_failed=False,
|
|
656
843
|
if_error=ModelError, # 生きてるのに失敗した場合
|
|
657
|
-
error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE
|
|
844
|
+
error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE
|
|
845
|
+
+ f"{value} -> {name}",
|
|
658
846
|
is_Gaudi_method=True,
|
|
659
847
|
args=(name, value),
|
|
660
848
|
)
|
|
849
|
+
|
|
850
|
+
# 渡された変数が Femtet で定義されていない
|
|
661
851
|
else:
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
852
|
+
if self._warn_if_undefined_variable:
|
|
853
|
+
msg = (
|
|
854
|
+
f"{name} not in {self.model_name}: "
|
|
855
|
+
+ Msg.WARN_IGNORE_PARAMETER_NOT_CONTAINED
|
|
856
|
+
)
|
|
857
|
+
warning_messages.append(msg)
|
|
858
|
+
logger.warning(msg)
|
|
665
859
|
|
|
860
|
+
# 変数一覧を取得する関数がない(チェックしない)
|
|
666
861
|
else:
|
|
862
|
+
|
|
667
863
|
# update without parameter check
|
|
668
|
-
|
|
669
|
-
for
|
|
670
|
-
name = row['name']
|
|
671
|
-
value = row['value']
|
|
864
|
+
warning_messages = []
|
|
865
|
+
for name, value in self.current_prm_values.items():
|
|
672
866
|
self._call_femtet_api(
|
|
673
867
|
fun=self.Femtet.UpdateVariable,
|
|
674
868
|
return_value_if_failed=False,
|
|
675
869
|
if_error=ModelError, # 生きてるのに失敗した場合
|
|
676
|
-
error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE
|
|
870
|
+
error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE
|
|
871
|
+
+ f"{value} -> {name}",
|
|
677
872
|
is_Gaudi_method=True,
|
|
678
873
|
args=(name, value),
|
|
679
874
|
)
|
|
680
875
|
|
|
681
876
|
# ここでは ReExecute しない
|
|
682
877
|
if with_warning:
|
|
683
|
-
return
|
|
878
|
+
return warning_messages
|
|
684
879
|
else:
|
|
685
880
|
return None
|
|
686
881
|
|
|
687
|
-
def update_model(self
|
|
882
|
+
def update_model(self) -> None:
|
|
688
883
|
"""Updates the analysis model only."""
|
|
689
884
|
|
|
690
|
-
self.parameters = parameters.copy()
|
|
691
|
-
|
|
692
|
-
# 変数の更新
|
|
693
|
-
warnings = self.update_parameter(parameters, with_warning)
|
|
694
|
-
|
|
695
885
|
# 設計変数に従ってモデルを再構築
|
|
696
886
|
self._call_femtet_api(
|
|
697
|
-
|
|
887
|
+
"self.Femtet.Gaudi.ReExecute",
|
|
698
888
|
False,
|
|
699
889
|
ModelError, # 生きてるのに失敗した場合
|
|
700
890
|
error_message=Msg.ERR_RE_EXECUTE_MODEL_FAILED,
|
|
@@ -710,14 +900,12 @@ class FemtetInterface(FEMInterface):
|
|
|
710
900
|
is_Gaudi_method=True,
|
|
711
901
|
)
|
|
712
902
|
|
|
713
|
-
if with_warning:
|
|
714
|
-
return warnings or []
|
|
715
|
-
|
|
716
903
|
def solve(self) -> None:
|
|
717
904
|
"""Execute FEM analysis."""
|
|
718
|
-
|
|
905
|
+
|
|
906
|
+
# メッシュを切る
|
|
719
907
|
self._call_femtet_api(
|
|
720
|
-
|
|
908
|
+
"self.Femtet.Gaudi.Mesh",
|
|
721
909
|
0,
|
|
722
910
|
MeshError,
|
|
723
911
|
Msg.ERR_MODEL_MESH_FAILED,
|
|
@@ -725,9 +913,9 @@ class FemtetInterface(FEMInterface):
|
|
|
725
913
|
)
|
|
726
914
|
|
|
727
915
|
if self.parametric_output_indexes_use_as_objective is not None:
|
|
728
|
-
from pyfemtet.opt.interface._femtet_parametric import solve_via_parametric_dll
|
|
729
916
|
|
|
730
|
-
|
|
917
|
+
# PyFemtet で保存させる pdt パスを決定する
|
|
918
|
+
pdt_path = self.Femtet.ResultFilePath + ".pdt"
|
|
731
919
|
|
|
732
920
|
# 前のものが残っているとややこしいので消しておく
|
|
733
921
|
if os.path.exists(pdt_path):
|
|
@@ -767,7 +955,8 @@ class FemtetInterface(FEMInterface):
|
|
|
767
955
|
is_Gaudi_method=True,
|
|
768
956
|
)
|
|
769
957
|
|
|
770
|
-
#
|
|
958
|
+
# 次に呼ばれるはずのユーザー定義コスト関数の
|
|
959
|
+
# 記述を簡単にするため先に解析結果を開いておく
|
|
771
960
|
self._call_femtet_api(
|
|
772
961
|
self.Femtet.OpenCurrentResult,
|
|
773
962
|
False,
|
|
@@ -777,14 +966,6 @@ class FemtetInterface(FEMInterface):
|
|
|
777
966
|
args=(self.open_result_with_gui,),
|
|
778
967
|
)
|
|
779
968
|
|
|
780
|
-
def update(self, parameters: 'pd.DataFrame') -> None:
|
|
781
|
-
"""See :func:`FEMInterface.update`"""
|
|
782
|
-
self.parameters = parameters.copy()
|
|
783
|
-
self.update_model(parameters)
|
|
784
|
-
self.preprocess(self.Femtet)
|
|
785
|
-
self.solve()
|
|
786
|
-
self.postprocess(self.Femtet)
|
|
787
|
-
|
|
788
969
|
def preprocess(self, Femtet):
|
|
789
970
|
"""A method called just before :func:`solve`.
|
|
790
971
|
|
|
@@ -807,22 +988,14 @@ class FemtetInterface(FEMInterface):
|
|
|
807
988
|
"""
|
|
808
989
|
pass
|
|
809
990
|
|
|
810
|
-
def
|
|
811
|
-
"""
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
_exit_or_force_terminate(timeout=timeout, Femtet=self.Femtet, force=True)
|
|
817
|
-
|
|
818
|
-
def _setup_before_parallel(self, client):
|
|
819
|
-
client.upload_file(
|
|
820
|
-
self.kwargs['femprj_path'],
|
|
821
|
-
False
|
|
822
|
-
)
|
|
991
|
+
def update(self) -> None:
|
|
992
|
+
"""See :func:`FEMInterface.update`"""
|
|
993
|
+
self.update_model()
|
|
994
|
+
self.preprocess(self.Femtet)
|
|
995
|
+
self.solve()
|
|
996
|
+
self.postprocess(self.Femtet)
|
|
823
997
|
|
|
824
|
-
|
|
825
|
-
return _version(Femtet=self.Femtet)
|
|
998
|
+
# ===== postprocess after recording =====
|
|
826
999
|
|
|
827
1000
|
def _create_postprocess_args(self):
|
|
828
1001
|
try:
|
|
@@ -836,7 +1009,7 @@ class FemtetInterface(FEMInterface):
|
|
|
836
1009
|
jpg_content = None
|
|
837
1010
|
|
|
838
1011
|
out = dict(
|
|
839
|
-
original_femprj_path=self.
|
|
1012
|
+
original_femprj_path=self._original_femprj_path,
|
|
840
1013
|
model_name=self.model_name,
|
|
841
1014
|
pdt_file_content=file_content,
|
|
842
1015
|
jpg_file_content=jpg_content,
|
|
@@ -845,55 +1018,60 @@ class FemtetInterface(FEMInterface):
|
|
|
845
1018
|
return out
|
|
846
1019
|
|
|
847
1020
|
@staticmethod
|
|
848
|
-
def
|
|
849
|
-
result_dir = femprj_path.replace(
|
|
850
|
-
|
|
1021
|
+
def _create_path(femprj_path, model_name, trial_name, ext):
|
|
1022
|
+
result_dir = femprj_path.replace(".femprj", ".Results")
|
|
1023
|
+
ext = ext.removeprefix('.')
|
|
1024
|
+
pdt_path = os.path.join(result_dir, model_name + f"_{trial_name}.{ext}")
|
|
851
1025
|
return pdt_path
|
|
852
1026
|
|
|
853
1027
|
# noinspection PyMethodOverriding
|
|
854
1028
|
@staticmethod
|
|
855
|
-
def
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1029
|
+
def _postprocess_after_recording(
|
|
1030
|
+
dask_scheduler, # must for run_on_scheduler
|
|
1031
|
+
trial_name: str,
|
|
1032
|
+
df: pd.DataFrame,
|
|
1033
|
+
*,
|
|
1034
|
+
original_femprj_path: str,
|
|
1035
|
+
save_results: str,
|
|
1036
|
+
model_name: str,
|
|
1037
|
+
pdt_file_content=None,
|
|
1038
|
+
jpg_file_content=None,
|
|
864
1039
|
):
|
|
1040
|
+
# FIXME: サブサンプリングの場合の処理
|
|
865
1041
|
|
|
866
1042
|
# none なら何もしない
|
|
1043
|
+
# all or optimal ならいったん保存する
|
|
867
1044
|
if save_results.lower() == 'none':
|
|
868
1045
|
return
|
|
869
1046
|
|
|
870
|
-
# all or optimal ならいったん保存する
|
|
871
|
-
result_dir = original_femprj_path.replace('.femprj', '.Results')
|
|
872
1047
|
if pdt_file_content is not None:
|
|
873
|
-
pdt_path = FemtetInterface.
|
|
874
|
-
|
|
1048
|
+
pdt_path = FemtetInterface._create_path(
|
|
1049
|
+
original_femprj_path, model_name, trial_name, ext='pdt')
|
|
1050
|
+
with open(pdt_path, "wb") as f:
|
|
875
1051
|
f.write(pdt_file_content)
|
|
876
1052
|
|
|
877
1053
|
if jpg_file_content is not None:
|
|
878
|
-
jpg_path =
|
|
879
|
-
|
|
1054
|
+
jpg_path = FemtetInterface._create_path(
|
|
1055
|
+
original_femprj_path, model_name, trial_name, ext='jpg')
|
|
1056
|
+
with open(jpg_path, "wb") as f:
|
|
880
1057
|
f.write(jpg_file_content)
|
|
881
1058
|
|
|
882
1059
|
# optimal なら不要ファイルの削除を実行する
|
|
883
1060
|
if save_results.lower() == 'optimal':
|
|
884
1061
|
for i, row in df.iterrows():
|
|
885
|
-
if not bool(row['
|
|
1062
|
+
if not bool(row['optimality']):
|
|
886
1063
|
trial_to_remove = int(row['trial'])
|
|
887
|
-
pdt_path_to_remove = FemtetInterface.
|
|
1064
|
+
pdt_path_to_remove = FemtetInterface._create_path(
|
|
1065
|
+
original_femprj_path, model_name, trial_to_remove, ext='pdt')
|
|
888
1066
|
if os.path.isfile(pdt_path_to_remove):
|
|
889
1067
|
os.remove(pdt_path_to_remove)
|
|
890
1068
|
|
|
891
1069
|
def _create_result_file_content(self):
|
|
892
1070
|
"""Called after solve"""
|
|
893
|
-
if self.save_pdt
|
|
1071
|
+
if self.save_pdt.lower() in ['all', 'optimal']:
|
|
894
1072
|
# save to worker space
|
|
895
|
-
result_dir = self.femprj_path.replace(
|
|
896
|
-
pdt_path = os.path.join(result_dir, self.model_name +
|
|
1073
|
+
result_dir = self.femprj_path.replace(".femprj", ".Results")
|
|
1074
|
+
pdt_path = os.path.join(result_dir, self.model_name + ".pdt")
|
|
897
1075
|
|
|
898
1076
|
self._call_femtet_api(
|
|
899
1077
|
fun=self.Femtet.SavePDT,
|
|
@@ -905,7 +1083,7 @@ class FemtetInterface(FEMInterface):
|
|
|
905
1083
|
)
|
|
906
1084
|
|
|
907
1085
|
# convert .pdt to ByteIO and return it
|
|
908
|
-
with open(pdt_path,
|
|
1086
|
+
with open(pdt_path, "rb") as f:
|
|
909
1087
|
content = f.read()
|
|
910
1088
|
return content
|
|
911
1089
|
|
|
@@ -913,8 +1091,8 @@ class FemtetInterface(FEMInterface):
|
|
|
913
1091
|
return None
|
|
914
1092
|
|
|
915
1093
|
def _create_jpg_content(self):
|
|
916
|
-
result_dir = self.femprj_path.replace(
|
|
917
|
-
jpg_path = os.path.join(result_dir, self.model_name +
|
|
1094
|
+
result_dir = self.femprj_path.replace(".femprj", ".Results")
|
|
1095
|
+
jpg_path = os.path.join(result_dir, self.model_name + ".jpg")
|
|
918
1096
|
|
|
919
1097
|
# モデル表示画面の設定
|
|
920
1098
|
self.Femtet.SetWindowSize(600, 600)
|
|
@@ -932,54 +1110,18 @@ class FemtetInterface(FEMInterface):
|
|
|
932
1110
|
if not os.path.exists(jpg_path):
|
|
933
1111
|
raise FailedToPostProcess(Msg.ERR_JPG_NOT_FOUND)
|
|
934
1112
|
|
|
935
|
-
with open(jpg_path,
|
|
1113
|
+
with open(jpg_path, "rb") as f:
|
|
936
1114
|
content = f.read()
|
|
937
1115
|
|
|
938
1116
|
return content
|
|
939
1117
|
|
|
1118
|
+
# ===== others =====
|
|
940
1119
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
original_femprj_path = 'dummy'
|
|
948
|
-
model_name = 'dummy'
|
|
949
|
-
parametric_output_indexes_use_as_objective = None
|
|
950
|
-
kwargs = dict()
|
|
951
|
-
Femtet = None
|
|
952
|
-
quit_when_destruct = False
|
|
953
|
-
|
|
954
|
-
# noinspection PyMissingConstructor
|
|
955
|
-
def __init__(self):
|
|
956
|
-
CoInitialize()
|
|
957
|
-
self.unpicklable_member = Dispatch('FemtetMacro.Femtet')
|
|
958
|
-
self.cns = constants
|
|
959
|
-
|
|
960
|
-
def _setup_before_parallel(self, *args, **kwargs):
|
|
961
|
-
pass
|
|
962
|
-
|
|
963
|
-
def check_param_value(self, *args, **kwargs):
|
|
964
|
-
pass
|
|
965
|
-
|
|
966
|
-
def update_parameter(self, *args, **kwargs):
|
|
967
|
-
pass
|
|
968
|
-
|
|
969
|
-
def update(self, *args, **kwargs):
|
|
970
|
-
pass
|
|
971
|
-
|
|
972
|
-
def create_result_file_content(self):
|
|
973
|
-
"""Called after solve"""
|
|
974
|
-
|
|
975
|
-
# save to worker space
|
|
976
|
-
with open(__file__, 'rb') as f:
|
|
977
|
-
content = f.read()
|
|
978
|
-
|
|
979
|
-
return content
|
|
1120
|
+
def _get_additional_data(self) -> dict:
|
|
1121
|
+
return dict(
|
|
1122
|
+
femprj_path=self._original_femprj_path,
|
|
1123
|
+
model_name=self.model_name,
|
|
1124
|
+
)
|
|
980
1125
|
|
|
981
|
-
def
|
|
982
|
-
|
|
983
|
-
here = os.path.dirname(__file__)
|
|
984
|
-
pdt_path = os.path.join(here, f'trial{trial}.pdt')
|
|
985
|
-
return pdt_path
|
|
1126
|
+
def _version(self):
|
|
1127
|
+
return _version(Femtet=self.Femtet)
|