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.

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