pyfemtet 0.6.6__tar.gz → 0.7.1__tar.gz
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-0.6.6 → pyfemtet-0.7.1}/PKG-INFO +2 -1
- pyfemtet-0.7.1/pyfemtet/__init__.py +1 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_femtet_config_util/exit.py +3 -2
- pyfemtet-0.7.1/pyfemtet/_util/dask_util.py +10 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_util/excel_macro_util.py +25 -16
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/dispatch_extensions/__init__.py +0 -1
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/dispatch_extensions/_impl.py +2 -5
- pyfemtet-0.7.1/pyfemtet/logger/__init__.py +22 -0
- pyfemtet-0.7.1/pyfemtet/logger/_impl.py +231 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/_femopt.py +27 -17
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/_femopt_core.py +36 -30
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/_test_utils/control_femtet.py +0 -6
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/__init__.py +1 -1
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/_base.py +2 -4
- pyfemtet-0.7.1/pyfemtet/opt/interface/_excel_interface.py +776 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/_femtet.py +14 -21
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/_femtet_parametric.py +1 -1
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/_femtet_with_nx/_interface.py +1 -1
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/_femtet_with_sldworks.py +1 -1
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_base.py +5 -5
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_optuna/_botorch_patch/enable_nonlinear_constraint.py +4 -1
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +0 -1
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_base.py +4 -4
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyproject.toml +3 -1
- pyfemtet-0.6.6/pyfemtet/__init__.py +0 -1
- pyfemtet-0.6.6/pyfemtet/logger/__init__.py +0 -3
- pyfemtet-0.6.6/pyfemtet/logger/_impl.py +0 -107
- pyfemtet-0.6.6/pyfemtet/opt/interface/_excel_interface.py +0 -447
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/LICENSE +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/README.md +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_femtet_config_util/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_femtet_config_util/autosave.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_message/1. make_pot.bat +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_message/2. make_mo.bat +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_message/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_message/babel.cfg +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_message/locales/ja/LC_MESSAGES/messages.po +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_message/locales/messages.pot +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_message/messages.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_util/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/_warning.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/brep/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/brep/_impl.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/core.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/_test_utils/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/_test_utils/hyper_sphere.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/_test_utils/record_history.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/_femtet_with_nx/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/interface/_femtet_with_nx/update_model.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_optuna/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_optuna/_botorch_patch/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_optuna/_optuna.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_optuna/_pof_botorch.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_scipy.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/_scipy_scalar.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/optimizer/parameter.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/prediction/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/prediction/_base.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/prediction/single_task_gp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/ParametricIF.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/ParametricIF.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/ParametricIF_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.prt +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_NX_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.SLDPRT +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/cad_ex01_SW_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/constrained_pipe.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/constrained_pipe_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/her_ex40_parametric_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric_parallel.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric_parallel.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric_test_result.reccsv +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/ParametricIF_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/ParametricIF_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_NX_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_NX_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_SW_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_SW_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/constrained_pipe_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/gal_ex58_parametric_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/gal_ex58_parametric_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/gau_ex08_parametric_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/gau_ex08_parametric_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/her_ex40_parametric_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/her_ex40_parametric_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_parallel_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.femprj +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_complex_components/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_complex_components/alert_region.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_complex_components/control_femtet.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_complex_components/main_figure_creator.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_complex_components/main_graph.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_complex_components/pm_graph.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_complex_components/pm_graph_creator.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_create_wrapped_components.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_process_monitor/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_process_monitor/application.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_process_monitor/pages.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_wrapped_components/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_wrapped_components/dbc.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_wrapped_components/dcc.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_wrapped_components/html.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/_wrapped_components/str_enum.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/result_viewer/.gitignore +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/result_viewer/__init__.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/result_viewer/application.py +0 -0
- {pyfemtet-0.6.6 → pyfemtet-0.7.1}/pyfemtet/opt/visualization/result_viewer/pages.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyfemtet
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: Design parameter optimization using Femtet.
|
|
5
5
|
Home-page: https://github.com/pyfemtet/pyfemtet
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -22,6 +22,7 @@ Requires-Dist: dash-bootstrap-components (>=1.5.0,<2.0.0)
|
|
|
22
22
|
Requires-Dist: dask (>=2023.12.1,<2024.0.0)
|
|
23
23
|
Requires-Dist: distributed (>=2023.12.1,<2024.0.0)
|
|
24
24
|
Requires-Dist: femtetutils (>=1.0.0,<2.0.0)
|
|
25
|
+
Requires-Dist: fire (>=0.6.0,<0.7.0)
|
|
25
26
|
Requires-Dist: numpy (>=1.26.2,<2.0.0)
|
|
26
27
|
Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
|
|
27
28
|
Requires-Dist: optuna (>=3.4.0,<5.0.0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.1"
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from time import time, sleep
|
|
2
|
-
import logging
|
|
3
2
|
|
|
4
3
|
from win32com.client import CDispatch
|
|
5
4
|
from femtetutils import util
|
|
@@ -9,7 +8,9 @@ from pyfemtet.dispatch_extensions._impl import _get_pid
|
|
|
9
8
|
from pyfemtet.core import _version
|
|
10
9
|
from pyfemtet._message import Msg
|
|
11
10
|
|
|
12
|
-
logger
|
|
11
|
+
from pyfemtet.logger import get_module_logger
|
|
12
|
+
|
|
13
|
+
logger = get_module_logger('util.femtet.exit', __name__)
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def _exit_or_force_terminate(timeout, Femtet: CDispatch, force=True):
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
"""Excel のエラーダイアログを補足します。"""
|
|
2
|
-
import sys
|
|
3
2
|
from time import sleep
|
|
4
3
|
from threading import Thread
|
|
5
|
-
import logging
|
|
6
4
|
import asyncio # for timeout
|
|
7
5
|
import win32gui
|
|
8
6
|
import win32con
|
|
9
7
|
import win32api
|
|
8
|
+
import win32process
|
|
9
|
+
|
|
10
|
+
from pyfemtet.logger import get_module_logger
|
|
11
|
+
|
|
12
|
+
logger = get_module_logger('util.excel', __name__)
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
|
|
15
|
+
def _get_pid(hwnd):
|
|
16
|
+
"""Window handle から process ID を取得します."""
|
|
17
|
+
if hwnd > 0:
|
|
18
|
+
_, pid = win32process.GetWindowThreadProcessId(hwnd)
|
|
19
|
+
else:
|
|
20
|
+
pid = 0
|
|
21
|
+
return pid
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
class _ExcelDialogProcessor:
|
|
21
25
|
|
|
22
|
-
def __init__(self, excel_, timeout):
|
|
26
|
+
def __init__(self, excel_, timeout, restore_book=True):
|
|
23
27
|
self.excel = excel_
|
|
28
|
+
self.excel_pid = _get_pid(excel_.hWnd)
|
|
24
29
|
self.__excel_window_title = f' - Excel' # {basename} - Excel
|
|
25
30
|
self.__error_dialog_title = 'Microsoft Visual Basic'
|
|
26
31
|
self.__vbe_window_title = f'Microsoft Visual Basic for Applications - ' # Microsoft Visual Basic for Applications - {basename}
|
|
@@ -31,6 +36,7 @@ class _ExcelDialogProcessor:
|
|
|
31
36
|
self.__error_raised = False
|
|
32
37
|
self.__excel_state_stash = dict()
|
|
33
38
|
self.__watch_thread = None
|
|
39
|
+
self.restore_book = restore_book
|
|
34
40
|
|
|
35
41
|
async def watch(self):
|
|
36
42
|
|
|
@@ -47,6 +53,7 @@ class _ExcelDialogProcessor:
|
|
|
47
53
|
win32gui.EnumWindows(self.enum_callback_to_close_dialog, found)
|
|
48
54
|
await asyncio.sleep(0.5)
|
|
49
55
|
if any(found):
|
|
56
|
+
await asyncio.sleep(1.)
|
|
50
57
|
break
|
|
51
58
|
|
|
52
59
|
logger.debug('ブックを閉じます。')
|
|
@@ -61,7 +68,7 @@ class _ExcelDialogProcessor:
|
|
|
61
68
|
def enum_callback_to_activate(self, hwnd, _):
|
|
62
69
|
title = win32gui.GetWindowText(hwnd)
|
|
63
70
|
# Excel 本体
|
|
64
|
-
if self.__excel_window_title in title:
|
|
71
|
+
if (self.excel_pid == _get_pid(hwnd)) and (self.__excel_window_title in title):
|
|
65
72
|
# Visible == True の際、エラーが発生した際、
|
|
66
73
|
# 一度 Excel ウィンドウをアクティブ化しないと dialog が出てこない
|
|
67
74
|
# が、これだけではダメかも。
|
|
@@ -70,7 +77,7 @@ class _ExcelDialogProcessor:
|
|
|
70
77
|
def enum_callback_to_close_dialog(self, hwnd, found):
|
|
71
78
|
title = win32gui.GetWindowText(hwnd)
|
|
72
79
|
# エラーダイアログ
|
|
73
|
-
if self.__error_dialog_title == title:
|
|
80
|
+
if (self.excel_pid == _get_pid(hwnd)) and (self.__error_dialog_title == title):
|
|
74
81
|
# 何故かこのコマンド以外受け付けず、
|
|
75
82
|
# このコマンドで問答無用でデバッグモードに入る
|
|
76
83
|
logger.debug('エラーダイアログを見つけました。')
|
|
@@ -82,14 +89,14 @@ class _ExcelDialogProcessor:
|
|
|
82
89
|
def enum_callback_to_close_confirm_dialog(self, hwnd, _):
|
|
83
90
|
title = win32gui.GetWindowText(hwnd)
|
|
84
91
|
# 確認ダイアログ
|
|
85
|
-
if "Microsoft Excel" in title:
|
|
92
|
+
if (self.excel_pid == _get_pid(hwnd)) and ("Microsoft Excel" in title):
|
|
86
93
|
# DisplayAlerts が False の場合は不要
|
|
87
94
|
win32gui.SendMessage(hwnd, win32con.WM_SYSCOMMAND, win32con.SC_CLOSE, 0)
|
|
88
95
|
|
|
89
96
|
def enum_callback_to_close_book(self, hwnd, _):
|
|
90
97
|
title = win32gui.GetWindowText(hwnd)
|
|
91
98
|
# VBE
|
|
92
|
-
if self.__vbe_window_title in title:
|
|
99
|
+
if (self.excel_pid == _get_pid(hwnd)) and (self.__vbe_window_title in title):
|
|
93
100
|
# 何故かこれで book 本体が閉じる
|
|
94
101
|
win32gui.SendMessage(hwnd, win32con.WM_CLOSE, 0, 0)
|
|
95
102
|
|
|
@@ -133,15 +140,17 @@ class _ExcelDialogProcessor:
|
|
|
133
140
|
# if exc_type is not None:
|
|
134
141
|
# if issubclass(exc_type, com_error) and self.__error_raised:
|
|
135
142
|
if self.__error_raised:
|
|
143
|
+
if self.restore_book:
|
|
136
144
|
logger.debug('エラーハンドリングの副作用でブックを閉じているので'
|
|
137
145
|
'Excel のブックを開きなおします。')
|
|
138
146
|
for wb_path in self.__workbook_paths:
|
|
139
147
|
self.excel.Workbooks.Open(wb_path)
|
|
140
148
|
|
|
141
149
|
|
|
142
|
-
def watch_excel_macro_error(excel_, timeout):
|
|
150
|
+
def watch_excel_macro_error(excel_, timeout, restore_book=True):
|
|
143
151
|
"""Excel のエラーダイアログの出現を監視し、検出されればブックを閉じます。"""
|
|
144
|
-
return _ExcelDialogProcessor(excel_, timeout)
|
|
152
|
+
return _ExcelDialogProcessor(excel_, timeout, restore_book)
|
|
153
|
+
|
|
145
154
|
|
|
146
155
|
|
|
147
156
|
if __name__ == '__main__':
|
|
@@ -18,14 +18,11 @@ from multiprocessing.context import BaseContext, SpawnProcess, _concrete_context
|
|
|
18
18
|
from multiprocessing.process import _children, _cleanup
|
|
19
19
|
from multiprocessing.managers import SyncManager
|
|
20
20
|
|
|
21
|
-
import logging
|
|
22
|
-
from pyfemtet.logger import get_logger
|
|
23
|
-
|
|
24
21
|
from pyfemtet._message import Msg
|
|
25
22
|
|
|
23
|
+
from pyfemtet.logger import get_module_logger
|
|
26
24
|
|
|
27
|
-
logger =
|
|
28
|
-
logger.setLevel(logging.INFO)
|
|
25
|
+
logger = get_module_logger('dispatch', __name__)
|
|
29
26
|
|
|
30
27
|
|
|
31
28
|
DISPATCH_TIMEOUT = 120
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pyfemtet.logger._impl import (
|
|
3
|
+
get_module_logger,
|
|
4
|
+
add_file_output,
|
|
5
|
+
set_stdout_output,
|
|
6
|
+
remove_file_output,
|
|
7
|
+
remove_stdout_output,
|
|
8
|
+
remove_all_output,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_dask_logger():
|
|
13
|
+
return logging.getLogger('distributed')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_optuna_logger():
|
|
17
|
+
import optuna
|
|
18
|
+
return optuna.logging.get_logger('optuna')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_dash_logger():
|
|
22
|
+
return logging.getLogger('werkzeug')
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import datetime
|
|
5
|
+
import locale
|
|
6
|
+
from threading import Lock
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import platform
|
|
9
|
+
|
|
10
|
+
from colorlog import ColoredFormatter
|
|
11
|
+
from dask.distributed import get_worker
|
|
12
|
+
|
|
13
|
+
LOCALE, LOCALE_ENCODING = locale.getlocale()
|
|
14
|
+
if platform.system() == 'Windows':
|
|
15
|
+
DATEFMT = '%#m/%#d %#H:%M'
|
|
16
|
+
else:
|
|
17
|
+
DATEFMT = '%-m/%-d %-H:%M'
|
|
18
|
+
|
|
19
|
+
__lock = Lock() # thread 並列されたタスクがアクセスする場合に備えて
|
|
20
|
+
|
|
21
|
+
__initialized_root_packages: list[str] = list()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ===== set dask worker prefix to ``ROOT`` logger =====
|
|
25
|
+
|
|
26
|
+
def _get_dask_worker_name():
|
|
27
|
+
name = '(Main)'
|
|
28
|
+
try:
|
|
29
|
+
worker = get_worker()
|
|
30
|
+
if isinstance(worker.name, str): # local なら index, cluster なら tcp address
|
|
31
|
+
name = f'({worker.name})'
|
|
32
|
+
else:
|
|
33
|
+
name = f'(Sub{worker.name})'
|
|
34
|
+
except ValueError:
|
|
35
|
+
pass
|
|
36
|
+
return name
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _DaskLogRecord(logging.LogRecord):
|
|
40
|
+
def getMessage(self):
|
|
41
|
+
msg = str(self.msg)
|
|
42
|
+
if self.args:
|
|
43
|
+
msg = msg % self.args
|
|
44
|
+
msg = _get_dask_worker_name() + ' ' + msg
|
|
45
|
+
return msg
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
logging.setLogRecordFactory(_DaskLogRecord)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ===== format config =====
|
|
52
|
+
|
|
53
|
+
def __create_formatter(colored=True):
|
|
54
|
+
|
|
55
|
+
if colored:
|
|
56
|
+
# colorized
|
|
57
|
+
header = "%(log_color)s" + "[%(name)s %(levelname).4s]" + " %(asctime)s" + "%(reset)s"
|
|
58
|
+
|
|
59
|
+
formatter = ColoredFormatter(
|
|
60
|
+
f"{header} %(message)s",
|
|
61
|
+
datefmt=DATEFMT,
|
|
62
|
+
reset=True,
|
|
63
|
+
log_colors={
|
|
64
|
+
"DEBUG": "purple",
|
|
65
|
+
"INFO": "cyan",
|
|
66
|
+
"WARNING": "yellow",
|
|
67
|
+
"ERROR": "light_red",
|
|
68
|
+
"CRITICAL": "red",
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
else:
|
|
73
|
+
header = "[%(name)s %(levelname).4s]"
|
|
74
|
+
formatter = logging.Formatter(
|
|
75
|
+
f"{header} %(message)s",
|
|
76
|
+
datefmt=DATEFMT,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return formatter
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# ===== handler config =====
|
|
83
|
+
|
|
84
|
+
STDOUT_HANDLER_NAME = 'stdout-handler'
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def __get_stdout_handler():
|
|
88
|
+
stdout_handler = logging.StreamHandler(sys.stdout)
|
|
89
|
+
stdout_handler.set_name(STDOUT_HANDLER_NAME)
|
|
90
|
+
stdout_handler.setFormatter(__create_formatter(colored=True))
|
|
91
|
+
return stdout_handler
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def __has_stdout_handler(logger):
|
|
95
|
+
return any([handler.get_name() != STDOUT_HANDLER_NAME for handler in logger.handlers])
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def set_stdout_output(logger, level=logging.INFO):
|
|
99
|
+
|
|
100
|
+
if not __has_stdout_handler(logger):
|
|
101
|
+
logger.addHandler(__get_stdout_handler())
|
|
102
|
+
|
|
103
|
+
logger.setLevel(level)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def remove_stdout_output(logger):
|
|
107
|
+
if __has_stdout_handler(logger):
|
|
108
|
+
logger.removeHandler(__get_stdout_handler())
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def add_file_output(logger, filepath=None, level=logging.INFO) -> str:
|
|
112
|
+
"""Add FileHandler to the logger.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
str: THe name of the added handler.
|
|
116
|
+
Its format is 'filehandler-{os.path.basename(filepath)}'
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
# certify filepath
|
|
121
|
+
if filepath is None:
|
|
122
|
+
filepath = datetime.datetime.now().strftime('%Y%m%d-%H%M%S') + f'_{logger.name}.log'
|
|
123
|
+
|
|
124
|
+
# add file handler
|
|
125
|
+
file_handler = logging.FileHandler(filename=filepath, encoding=LOCALE_ENCODING)
|
|
126
|
+
file_handler.set_name(f'filehandler-{os.path.basename(filepath)}')
|
|
127
|
+
file_handler.setFormatter(__create_formatter(colored=False))
|
|
128
|
+
logger.addHandler(file_handler)
|
|
129
|
+
|
|
130
|
+
# set (default) log level
|
|
131
|
+
logger.setLevel(level)
|
|
132
|
+
|
|
133
|
+
return file_handler.get_name()
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def remove_file_output(logger, filepath=None):
|
|
137
|
+
"""Removes FileHandler from the logger.
|
|
138
|
+
|
|
139
|
+
If filepath is None, remove all FileHandler.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
if filepath is None:
|
|
143
|
+
for handler in logger.handlers:
|
|
144
|
+
if 'filehandler-' in handler.name:
|
|
145
|
+
logger.removeHandler(handler)
|
|
146
|
+
|
|
147
|
+
else:
|
|
148
|
+
handler_name = f'filehandler-{os.path.basename(filepath)}'
|
|
149
|
+
for handler in logger.handlers:
|
|
150
|
+
if handler_name == handler.name:
|
|
151
|
+
logger.removeHandler(handler)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def remove_all_output(logger):
|
|
155
|
+
for handler in logger.handlers:
|
|
156
|
+
logger.removeHandler(handler)
|
|
157
|
+
|
|
158
|
+
logger.addHandler(logging.NullHandler())
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# ===== root-package logger =====
|
|
162
|
+
|
|
163
|
+
def setup_package_root_logger(package_name):
|
|
164
|
+
global __initialized_root_packages
|
|
165
|
+
if package_name not in __initialized_root_packages:
|
|
166
|
+
with __lock:
|
|
167
|
+
logger = logging.getLogger(package_name)
|
|
168
|
+
logger.propagate = True
|
|
169
|
+
set_stdout_output(logger)
|
|
170
|
+
logger.setLevel(logging.INFO)
|
|
171
|
+
__initialized_root_packages.append(package_name)
|
|
172
|
+
else:
|
|
173
|
+
logger = logging.getLogger(package_name)
|
|
174
|
+
return logger
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# ===== module logger =====
|
|
178
|
+
|
|
179
|
+
def get_module_logger(name: str, __module_name__: str, ) -> logging.Logger:
|
|
180
|
+
"""Return the module-level logger.
|
|
181
|
+
|
|
182
|
+
The format is defined in the package_root_logger.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
name (str): The logger name to want.
|
|
186
|
+
__module_name__ (str): __name__ of the module.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
logging.Logger:
|
|
190
|
+
The logger its name is ``root_package.subpackage.module``.
|
|
191
|
+
child level logger's signal propagates to the parent logger
|
|
192
|
+
and is shown in the parent(s)'s handler(s).
|
|
193
|
+
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
# check root logger initialized
|
|
197
|
+
name_arr = name.split('.')
|
|
198
|
+
if name_arr[0] not in __initialized_root_packages:
|
|
199
|
+
setup_package_root_logger(name_arr[0])
|
|
200
|
+
|
|
201
|
+
# get logger
|
|
202
|
+
logger = logging.getLogger(name)
|
|
203
|
+
|
|
204
|
+
# If not root logger, ensure propagate is True.
|
|
205
|
+
if len(name_arr) > 1:
|
|
206
|
+
logger.propagate = True
|
|
207
|
+
|
|
208
|
+
# If debug mode, set specific level.
|
|
209
|
+
if __module_name__ == '__main__':
|
|
210
|
+
logger.setLevel(logging.DEBUG)
|
|
211
|
+
|
|
212
|
+
return logger
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if __name__ == '__main__':
|
|
216
|
+
|
|
217
|
+
root_logger = setup_package_root_logger('logger')
|
|
218
|
+
optimizer_logger = get_module_logger('logger.optimizer', __name__); optimizer_logger.setLevel(logging.INFO)
|
|
219
|
+
interface_logger = get_module_logger('logger.interface', __name__)
|
|
220
|
+
|
|
221
|
+
root_logger.info("This is root logger's info.")
|
|
222
|
+
optimizer_logger.info("This is optimizer logger's info.")
|
|
223
|
+
|
|
224
|
+
add_file_output(interface_logger, 'test-module-log.log', level=logging.DEBUG)
|
|
225
|
+
interface_logger.debug('debugging...')
|
|
226
|
+
remove_file_output(interface_logger, 'test-module-log.log')
|
|
227
|
+
|
|
228
|
+
interface_logger.debug('debug is finished.')
|
|
229
|
+
root_logger.debug("This message will not be shown "
|
|
230
|
+
"even if the module_logger's level "
|
|
231
|
+
"is logging.DEBUG.")
|
|
@@ -12,7 +12,7 @@ from traceback import print_exception
|
|
|
12
12
|
# 3rd-party
|
|
13
13
|
import numpy as np
|
|
14
14
|
import pandas as pd
|
|
15
|
-
from dask.distributed import LocalCluster, Client
|
|
15
|
+
from dask.distributed import LocalCluster, Client, get_worker, Nanny
|
|
16
16
|
|
|
17
17
|
# pyfemtet relative
|
|
18
18
|
from pyfemtet.opt.interface import FEMInterface, FemtetInterface
|
|
@@ -136,6 +136,7 @@ class FEMOpt:
|
|
|
136
136
|
self.monitor_server_kwargs = dict()
|
|
137
137
|
self.monitor_process_worker_name = None
|
|
138
138
|
self._hv_reference = None
|
|
139
|
+
self._extra_space_dir = None
|
|
139
140
|
|
|
140
141
|
# multiprocess 時に pickle できないオブジェクト参照の削除
|
|
141
142
|
def __getstate__(self):
|
|
@@ -675,10 +676,6 @@ class FEMOpt:
|
|
|
675
676
|
directions,
|
|
676
677
|
)
|
|
677
678
|
|
|
678
|
-
# Femtet の confirm_before_exit のセット
|
|
679
|
-
self.fem.confirm_before_exit = confirm_before_exit
|
|
680
|
-
self.fem.kwargs['confirm_before_exit'] = confirm_before_exit
|
|
681
|
-
|
|
682
679
|
logger.info('Femtet loaded successfully.')
|
|
683
680
|
|
|
684
681
|
# クラスターの設定
|
|
@@ -718,30 +715,43 @@ class FEMOpt:
|
|
|
718
715
|
# これは CLI の --no-nanny オプションも同様らしい。
|
|
719
716
|
|
|
720
717
|
# クラスターの構築
|
|
718
|
+
# noinspection PyTypeChecker
|
|
721
719
|
cluster = LocalCluster(
|
|
722
720
|
processes=True,
|
|
723
721
|
n_workers=n_parallel,
|
|
724
722
|
threads_per_worker=1,
|
|
723
|
+
worker_class=Nanny,
|
|
725
724
|
)
|
|
726
725
|
logger.info('LocalCluster launched successfully.')
|
|
727
726
|
|
|
728
|
-
self.client = Client(
|
|
729
|
-
|
|
727
|
+
self.client = Client(
|
|
728
|
+
cluster,
|
|
729
|
+
direct_to_workers=False,
|
|
730
|
+
)
|
|
730
731
|
logger.info('Client launched successfully.')
|
|
731
732
|
|
|
732
|
-
|
|
733
|
-
subprocess_indices = list(range(n_parallel))[1:]
|
|
734
|
-
worker_addresses = list(self.client.nthreads().keys())
|
|
733
|
+
self.scheduler_address = self.client.scheduler.address
|
|
735
734
|
|
|
736
|
-
#
|
|
737
|
-
|
|
738
|
-
|
|
735
|
+
# worker address を取得
|
|
736
|
+
nannies_dict: dict[Any, Nanny] = self.client.cluster.workers
|
|
737
|
+
nannies = tuple(nannies_dict.values())
|
|
738
|
+
|
|
739
|
+
# ひとつの Nanny を選んで monitor 用にしつつ
|
|
740
|
+
# その space は main process に使わせるために記憶する
|
|
741
|
+
self.monitor_process_worker_name = nannies[0].worker_address
|
|
742
|
+
self._extra_space_dir = nannies[0].worker_dir
|
|
743
|
+
|
|
744
|
+
# 名前と address がごちゃごちゃになっていて可読性が悪いが
|
|
745
|
+
# 選んだ以外の Nanny は計算を割り当てる用にする
|
|
746
|
+
worker_addresses = ['Main']
|
|
747
|
+
worker_addresses.extend([n.worker_address for n in nannies[1:]])
|
|
748
|
+
subprocess_indices = list(range(n_parallel))[1:]
|
|
739
749
|
|
|
740
750
|
with self.client.cluster as _cluster, self.client as _client:
|
|
741
751
|
|
|
742
752
|
# actor の設定
|
|
743
|
-
self.status = OptimizationStatus(_client)
|
|
744
|
-
self.worker_status_list = [OptimizationStatus(_client, name) for name in worker_addresses] # tqdm 検討
|
|
753
|
+
self.status = OptimizationStatus(_client, worker_address=self.monitor_process_worker_name)
|
|
754
|
+
self.worker_status_list = [OptimizationStatus(_client, worker_address=self.monitor_process_worker_name, name=name) for name in worker_addresses] # tqdm 検討
|
|
745
755
|
self.status.set(OptimizationStatus.SETTING_UP)
|
|
746
756
|
self.history = History(
|
|
747
757
|
self.history_path,
|
|
@@ -773,7 +783,6 @@ class FEMOpt:
|
|
|
773
783
|
logger.info('Process monitor initialized successfully.')
|
|
774
784
|
|
|
775
785
|
# fem
|
|
776
|
-
# TODO: n_parallel=1 のときもアップロードしている。これを使うべきか、アップロードしないべき。
|
|
777
786
|
self.fem._setup_before_parallel(_client)
|
|
778
787
|
|
|
779
788
|
# opt
|
|
@@ -794,7 +803,7 @@ class FEMOpt:
|
|
|
794
803
|
subprocess_indices,
|
|
795
804
|
[self.worker_status_list] * len(subprocess_indices),
|
|
796
805
|
[wait_setup] * len(subprocess_indices),
|
|
797
|
-
workers=worker_addresses,
|
|
806
|
+
workers=worker_addresses if self.opt.is_cluster else worker_addresses[1:],
|
|
798
807
|
allow_other_workers=False,
|
|
799
808
|
)
|
|
800
809
|
|
|
@@ -818,6 +827,7 @@ class FEMOpt:
|
|
|
818
827
|
),
|
|
819
828
|
kwargs=dict(
|
|
820
829
|
skip_reconstruct=True,
|
|
830
|
+
space_dir=self._extra_space_dir,
|
|
821
831
|
)
|
|
822
832
|
)
|
|
823
833
|
t_main.start()
|
|
@@ -22,7 +22,7 @@ if version.parse(optuna.version.__version__) < version.parse('4.0.0'):
|
|
|
22
22
|
else:
|
|
23
23
|
from optuna._hypervolume import wfg
|
|
24
24
|
compute_hypervolume = wfg.compute_hypervolume
|
|
25
|
-
from dask.distributed import Lock, get_client
|
|
25
|
+
from dask.distributed import Lock, get_client, Client
|
|
26
26
|
|
|
27
27
|
# win32com
|
|
28
28
|
from win32com.client import constants, Constants
|
|
@@ -32,10 +32,9 @@ from pyfemtet.opt.interface import FEMInterface, FemtetInterface
|
|
|
32
32
|
from pyfemtet._message import encoding, Msg
|
|
33
33
|
|
|
34
34
|
# logger
|
|
35
|
-
import
|
|
36
|
-
|
|
37
|
-
logger =
|
|
38
|
-
logger.setLevel(logging.INFO)
|
|
35
|
+
from pyfemtet.logger import get_module_logger
|
|
36
|
+
|
|
37
|
+
logger = get_module_logger('opt.core', __name__)
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
__all__ = [
|
|
@@ -503,19 +502,6 @@ class ObjectivesFunc:
|
|
|
503
502
|
return f
|
|
504
503
|
|
|
505
504
|
|
|
506
|
-
class _HistoryDfCore:
|
|
507
|
-
"""Class for managing a DataFrame object in a distributed manner."""
|
|
508
|
-
|
|
509
|
-
def __init__(self):
|
|
510
|
-
self.df = pd.DataFrame()
|
|
511
|
-
|
|
512
|
-
def set_df(self, df):
|
|
513
|
-
self.df = df
|
|
514
|
-
|
|
515
|
-
def get_df(self):
|
|
516
|
-
return self.df
|
|
517
|
-
|
|
518
|
-
|
|
519
505
|
class History:
|
|
520
506
|
"""Class for managing the history of optimization results.
|
|
521
507
|
|
|
@@ -543,8 +529,6 @@ class History:
|
|
|
543
529
|
is_restart = False
|
|
544
530
|
is_processing = False
|
|
545
531
|
_df = None # in case without client
|
|
546
|
-
_future = None # in case with client
|
|
547
|
-
_actor_data = None # in case with client
|
|
548
532
|
|
|
549
533
|
def __init__(
|
|
550
534
|
self,
|
|
@@ -565,6 +549,7 @@ class History:
|
|
|
565
549
|
self.obj_names = obj_names
|
|
566
550
|
self.cns_names = cns_names
|
|
567
551
|
self.additional_metadata = additional_metadata or ''
|
|
552
|
+
self.__scheduler_address = client.scheduler.address if client is not None else None
|
|
568
553
|
|
|
569
554
|
# 最適化実行中かどうか
|
|
570
555
|
self.is_processing = client is not None
|
|
@@ -572,10 +557,6 @@ class History:
|
|
|
572
557
|
# 最適化実行中の process monitor である場合
|
|
573
558
|
if self.is_processing:
|
|
574
559
|
|
|
575
|
-
# actor の生成
|
|
576
|
-
self._future = client.submit(_HistoryDfCore, actor=True)
|
|
577
|
-
self._actor_data = self._future.result()
|
|
578
|
-
|
|
579
560
|
# csv が存在すれば続きからモード
|
|
580
561
|
self.is_restart = os.path.isfile(self.path)
|
|
581
562
|
|
|
@@ -641,16 +622,36 @@ class History:
|
|
|
641
622
|
self.set_df(df)
|
|
642
623
|
|
|
643
624
|
def get_df(self) -> pd.DataFrame:
|
|
644
|
-
if self.
|
|
625
|
+
if self.__scheduler_address is None:
|
|
645
626
|
return self._df
|
|
646
627
|
else:
|
|
647
|
-
|
|
628
|
+
# scheduler がまだ存命か確認する
|
|
629
|
+
try:
|
|
630
|
+
with Lock('access-df'):
|
|
631
|
+
client_: 'Client' = get_client(self.__scheduler_address)
|
|
632
|
+
if 'df' in client_.list_datasets():
|
|
633
|
+
return client_.get_dataset('df')
|
|
634
|
+
else:
|
|
635
|
+
logger.debug('Access df of History before it is initialized.')
|
|
636
|
+
return pd.DataFrame()
|
|
637
|
+
except OSError:
|
|
638
|
+
logger.error('Scheduler is already dead. Most frequent reasen to show this message is that the pyfemtet monitor UI is not refreshed even if the main optimization process is terminated.')
|
|
639
|
+
return pd.DataFrame()
|
|
648
640
|
|
|
649
641
|
def set_df(self, df: pd.DataFrame):
|
|
650
|
-
if self.
|
|
642
|
+
if self.__scheduler_address is None:
|
|
651
643
|
self._df = df
|
|
652
644
|
else:
|
|
653
|
-
|
|
645
|
+
try:
|
|
646
|
+
with Lock('access-df'):
|
|
647
|
+
client_: 'Client' = get_client(self.__scheduler_address)
|
|
648
|
+
if 'df' in client_.list_datasets():
|
|
649
|
+
client_.unpublish_dataset('df') # 更新する場合は前もって削除が必要、本来は dask collection をここに入れる使い方をする。
|
|
650
|
+
client_.publish_dataset(**dict(
|
|
651
|
+
df=df
|
|
652
|
+
))
|
|
653
|
+
except OSError:
|
|
654
|
+
logger.error('Scheduler is already dead. Most frequent reasen to show this message is that the pyfemtet monitor UI is not refreshed even if the main optimization process is terminated.')
|
|
654
655
|
|
|
655
656
|
def create_df_columns(self):
|
|
656
657
|
"""Create columns of history."""
|
|
@@ -979,8 +980,13 @@ class OptimizationStatus:
|
|
|
979
980
|
TERMINATE_ALL = 60
|
|
980
981
|
CRASHED = 70
|
|
981
982
|
|
|
982
|
-
def __init__(self, client, name='entire'):
|
|
983
|
-
self._future = client.submit(
|
|
983
|
+
def __init__(self, client, worker_address, name='entire'):
|
|
984
|
+
self._future = client.submit(
|
|
985
|
+
_OptimizationStatusActor,
|
|
986
|
+
actor=True,
|
|
987
|
+
workers=[worker_address],
|
|
988
|
+
allow_other_workers=False,
|
|
989
|
+
)
|
|
984
990
|
self._actor = self._future.result()
|
|
985
991
|
self.name = name
|
|
986
992
|
self.set(self.INITIALIZING)
|
|
@@ -5,12 +5,6 @@ from tqdm import tqdm
|
|
|
5
5
|
from win32com.client import Dispatch
|
|
6
6
|
from femtetutils import util
|
|
7
7
|
|
|
8
|
-
import logging
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger("test")
|
|
12
|
-
logger.setLevel(logging.DEBUG)
|
|
13
|
-
|
|
14
8
|
|
|
15
9
|
def _open_femprj(femprj_path):
|
|
16
10
|
Femtet = Dispatch("FemtetMacro.Femtet")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from pyfemtet.opt.interface._base import FEMInterface
|
|
1
|
+
from pyfemtet.opt.interface._base import FEMInterface
|
|
2
2
|
from pyfemtet.opt.interface._base import NoFEM
|
|
3
3
|
from pyfemtet.opt.interface._femtet import FemtetInterface
|
|
4
4
|
from pyfemtet.opt.interface._femtet_with_sldworks import FemtetWithSolidworksInterface
|