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