pyfemtet 0.6.6__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- pyfemtet/__init__.py +1 -1
- pyfemtet/_femtet_config_util/exit.py +3 -2
- pyfemtet/_util/excel_macro_util.py +9 -12
- pyfemtet/dispatch_extensions/__init__.py +0 -1
- pyfemtet/dispatch_extensions/_impl.py +2 -5
- pyfemtet/logger/__init__.py +21 -2
- pyfemtet/logger/_impl.py +189 -65
- pyfemtet/opt/_femopt_core.py +29 -28
- pyfemtet/opt/_test_utils/control_femtet.py +0 -6
- pyfemtet/opt/interface/__init__.py +1 -1
- pyfemtet/opt/interface/_base.py +2 -4
- pyfemtet/opt/interface/_excel_interface.py +194 -54
- pyfemtet/opt/interface/_femtet.py +7 -1
- pyfemtet/opt/interface/_femtet_parametric.py +1 -1
- pyfemtet/opt/interface/_femtet_with_nx/_interface.py +1 -1
- pyfemtet/opt/interface/_femtet_with_sldworks.py +1 -1
- pyfemtet/opt/optimizer/_base.py +3 -4
- pyfemtet/opt/optimizer/_optuna/_botorch_patch/enable_nonlinear_constraint.py +4 -1
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +0 -1
- pyfemtet/opt/visualization/_base.py +4 -4
- {pyfemtet-0.6.6.dist-info → pyfemtet-0.7.0.dist-info}/METADATA +1 -1
- {pyfemtet-0.6.6.dist-info → pyfemtet-0.7.0.dist-info}/RECORD +25 -25
- {pyfemtet-0.6.6.dist-info → pyfemtet-0.7.0.dist-info}/LICENSE +0 -0
- {pyfemtet-0.6.6.dist-info → pyfemtet-0.7.0.dist-info}/WHEEL +0 -0
- {pyfemtet-0.6.6.dist-info → pyfemtet-0.7.0.dist-info}/entry_points.txt +0 -0
pyfemtet/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.7.0"
|
|
@@ -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,25 +1,19 @@
|
|
|
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
|
|
10
8
|
|
|
11
|
-
logger
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
handler = logging.StreamHandler(sys.stdout)
|
|
15
|
-
handler.setFormatter(formatter)
|
|
16
|
-
logger.addHandler(handler)
|
|
17
|
-
logger.setLevel(logging.DEBUG)
|
|
9
|
+
from pyfemtet.logger import get_module_logger
|
|
10
|
+
|
|
11
|
+
logger = get_module_logger('util.excel', __name__)
|
|
18
12
|
|
|
19
13
|
|
|
20
14
|
class _ExcelDialogProcessor:
|
|
21
15
|
|
|
22
|
-
def __init__(self, excel_, timeout):
|
|
16
|
+
def __init__(self, excel_, timeout, restore_book=True):
|
|
23
17
|
self.excel = excel_
|
|
24
18
|
self.__excel_window_title = f' - Excel' # {basename} - Excel
|
|
25
19
|
self.__error_dialog_title = 'Microsoft Visual Basic'
|
|
@@ -31,6 +25,7 @@ class _ExcelDialogProcessor:
|
|
|
31
25
|
self.__error_raised = False
|
|
32
26
|
self.__excel_state_stash = dict()
|
|
33
27
|
self.__watch_thread = None
|
|
28
|
+
self.restore_book = restore_book
|
|
34
29
|
|
|
35
30
|
async def watch(self):
|
|
36
31
|
|
|
@@ -133,15 +128,17 @@ class _ExcelDialogProcessor:
|
|
|
133
128
|
# if exc_type is not None:
|
|
134
129
|
# if issubclass(exc_type, com_error) and self.__error_raised:
|
|
135
130
|
if self.__error_raised:
|
|
131
|
+
if self.restore_book:
|
|
136
132
|
logger.debug('エラーハンドリングの副作用でブックを閉じているので'
|
|
137
133
|
'Excel のブックを開きなおします。')
|
|
138
134
|
for wb_path in self.__workbook_paths:
|
|
139
135
|
self.excel.Workbooks.Open(wb_path)
|
|
140
136
|
|
|
141
137
|
|
|
142
|
-
def watch_excel_macro_error(excel_, timeout):
|
|
138
|
+
def watch_excel_macro_error(excel_, timeout, restore_book=True):
|
|
143
139
|
"""Excel のエラーダイアログの出現を監視し、検出されればブックを閉じます。"""
|
|
144
|
-
return _ExcelDialogProcessor(excel_, timeout)
|
|
140
|
+
return _ExcelDialogProcessor(excel_, timeout, restore_book)
|
|
141
|
+
|
|
145
142
|
|
|
146
143
|
|
|
147
144
|
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
|
pyfemtet/logger/__init__.py
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
-
|
|
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
|
+
)
|
|
2
10
|
|
|
3
|
-
|
|
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')
|
pyfemtet/logger/_impl.py
CHANGED
|
@@ -1,107 +1,231 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
|
-
import
|
|
4
|
+
import datetime
|
|
5
|
+
import locale
|
|
6
|
+
from threading import Lock
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import platform
|
|
9
|
+
|
|
4
10
|
from colorlog import ColoredFormatter
|
|
5
11
|
from dask.distributed import get_worker
|
|
6
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 並列されたタスクがアクセスする場合に備えて
|
|
7
20
|
|
|
8
|
-
|
|
9
|
-
|
|
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)'
|
|
10
28
|
try:
|
|
11
29
|
worker = get_worker()
|
|
12
30
|
if isinstance(worker.name, str): # local なら index, cluster なら tcp address
|
|
13
|
-
name = f'({worker.name})
|
|
31
|
+
name = f'({worker.name})'
|
|
14
32
|
else:
|
|
15
|
-
name = f'(Sub{worker.name})
|
|
33
|
+
name = f'(Sub{worker.name})'
|
|
16
34
|
except ValueError:
|
|
17
35
|
pass
|
|
18
36
|
return name
|
|
19
37
|
|
|
20
38
|
|
|
21
39
|
class _DaskLogRecord(logging.LogRecord):
|
|
22
|
-
"""Generate a log message with dask worker name."""
|
|
23
|
-
|
|
24
|
-
# def __init__(self, *args, **kwargs):
|
|
25
|
-
# super().__init__(*args, **kwargs)
|
|
26
|
-
# self.worker = _get_worker_name_as_prefix()
|
|
27
|
-
|
|
28
40
|
def getMessage(self):
|
|
29
|
-
"""Add worker name to loggin message.
|
|
30
|
-
|
|
31
|
-
This function is originated from logging.LogRecord.
|
|
32
|
-
|
|
33
|
-
# Copyright (C) 2001-2022 Vinay Sajip. All Rights Reserved.
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
41
|
msg = str(self.msg)
|
|
37
42
|
if self.args:
|
|
38
43
|
msg = msg % self.args
|
|
39
|
-
msg =
|
|
44
|
+
msg = _get_dask_worker_name() + ' ' + msg
|
|
40
45
|
return msg
|
|
41
46
|
|
|
42
47
|
|
|
43
|
-
logging.setLogRecordFactory(_DaskLogRecord)
|
|
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):
|
|
44
99
|
|
|
100
|
+
if not __has_stdout_handler(logger):
|
|
101
|
+
logger.addHandler(__get_stdout_handler())
|
|
45
102
|
|
|
46
|
-
|
|
47
|
-
"""Detection of color support.
|
|
103
|
+
logger.setLevel(level)
|
|
48
104
|
|
|
49
|
-
This function is originated from optuna.logging.
|
|
50
105
|
|
|
51
|
-
|
|
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)}'
|
|
52
117
|
|
|
53
118
|
"""
|
|
54
119
|
|
|
55
|
-
#
|
|
56
|
-
if
|
|
57
|
-
|
|
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)
|
|
58
146
|
|
|
59
|
-
if not hasattr(sys.stderr, "isatty") or not sys.stderr.isatty():
|
|
60
|
-
return False
|
|
61
147
|
else:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
datefmt=None,
|
|
74
|
-
reset=True,
|
|
75
|
-
log_colors={
|
|
76
|
-
"DEBUG": "purple",
|
|
77
|
-
"INFO": "cyan",
|
|
78
|
-
"WARNING": "yellow",
|
|
79
|
-
"ERROR": "light_red",
|
|
80
|
-
"CRITICAL": "red",
|
|
81
|
-
},
|
|
82
|
-
)
|
|
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())
|
|
83
159
|
|
|
84
|
-
return formatter
|
|
85
160
|
|
|
161
|
+
# ===== root-package logger =====
|
|
86
162
|
|
|
87
|
-
def
|
|
88
|
-
|
|
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 =====
|
|
89
178
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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).
|
|
96
193
|
|
|
97
194
|
"""
|
|
98
195
|
|
|
99
|
-
|
|
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)
|
|
100
203
|
|
|
101
|
-
logger
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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)
|
|
106
211
|
|
|
107
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.")
|
pyfemtet/opt/_femopt_core.py
CHANGED
|
@@ -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."""
|
|
@@ -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
|
pyfemtet/opt/interface/_base.py
CHANGED
|
@@ -5,11 +5,9 @@ from abc import ABC, abstractmethod
|
|
|
5
5
|
|
|
6
6
|
import pandas as pd
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
from pyfemtet.logger import get_logger
|
|
10
|
-
logger = get_logger('FEM')
|
|
11
|
-
logger.setLevel(logging.INFO)
|
|
8
|
+
from pyfemtet.logger import get_module_logger
|
|
12
9
|
|
|
10
|
+
logger = get_module_logger('opt.interface', __name__)
|
|
13
11
|
|
|
14
12
|
here, me = os.path.split(__file__)
|
|
15
13
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from time import sleep
|
|
4
|
+
import gc
|
|
4
5
|
|
|
5
6
|
import pandas as pd
|
|
6
7
|
import numpy as np
|
|
@@ -29,13 +30,108 @@ from pyfemtet._util.excel_macro_util import watch_excel_macro_error
|
|
|
29
30
|
|
|
30
31
|
from pyfemtet._warning import show_experimental_warning
|
|
31
32
|
|
|
32
|
-
import
|
|
33
|
-
|
|
34
|
-
logger = logging.getLogger(__name__)
|
|
35
|
-
logger.setLevel(logging.INFO)
|
|
33
|
+
from pyfemtet.opt.interface._base import logger
|
|
36
34
|
|
|
37
35
|
|
|
38
36
|
class ExcelInterface(FEMInterface):
|
|
37
|
+
"""Excel を計算コアとして利用するためのクラス。
|
|
38
|
+
|
|
39
|
+
通常の有限要素法を Excel に
|
|
40
|
+
置き換えて使用することが可能です。
|
|
41
|
+
|
|
42
|
+
すでに Excel マクロと Femtet を
|
|
43
|
+
連携させた自動解析システムを
|
|
44
|
+
構築している場合、このクラスは
|
|
45
|
+
それをラップします。これにより、
|
|
46
|
+
PyFemtet を用いた最適化を
|
|
47
|
+
行う際に便利な機能を提供します。
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
input_xlsm_path (str or Path):
|
|
51
|
+
設計変数の定義を含む Excel ファイルのパスを指定
|
|
52
|
+
します。
|
|
53
|
+
|
|
54
|
+
input_sheet_name (str):
|
|
55
|
+
設計変数の定義を含むシートの名前を指定します。
|
|
56
|
+
|
|
57
|
+
output_xlsm_path (str or Path, optional):
|
|
58
|
+
目的関数の定義を含む Excel ファイルのパスを指定
|
|
59
|
+
します。指定しない場合は ``input_xlsm_path`` と
|
|
60
|
+
同じと見做します。
|
|
61
|
+
|
|
62
|
+
output_sheet_name (str, optional):
|
|
63
|
+
目的関数の定義を含む含むシートの名前を指定します。
|
|
64
|
+
指定しない場合は ``input_sheet_name`` と同じと見
|
|
65
|
+
做します。
|
|
66
|
+
|
|
67
|
+
procedure_name (str, optional):
|
|
68
|
+
Excel マクロ関数名を指定します。指定しない場合は
|
|
69
|
+
``FemtetMacro.FemtetMain`` と見做します。
|
|
70
|
+
|
|
71
|
+
procedure_args (list or tuple, optional):
|
|
72
|
+
Excel マクロ関数に渡す引数をリストまたはタプルで
|
|
73
|
+
指定します。
|
|
74
|
+
|
|
75
|
+
connect_method (str, optional):
|
|
76
|
+
Excel との接続方法を指定します。 'auto' または
|
|
77
|
+
'new' が利用可能です。デフォルトは 'auto' です。
|
|
78
|
+
|
|
79
|
+
procedure_timeout (float or None, optional):
|
|
80
|
+
Excel マクロ関数のタイムアウト時間を秒単位で指定
|
|
81
|
+
します。 None の場合はタイムアウトなしとなります。
|
|
82
|
+
|
|
83
|
+
with_call_femtet (bool, optional):
|
|
84
|
+
Femtet を呼び出すかどうかを指定します。
|
|
85
|
+
デフォルトは False です。
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
Attributes:
|
|
89
|
+
input_xlsm_path (Path):
|
|
90
|
+
設計変数の定義を含む Excel ファイルのパス。
|
|
91
|
+
|
|
92
|
+
input_sheet_name (str):
|
|
93
|
+
設計変数の定義を含むシートの名前。
|
|
94
|
+
|
|
95
|
+
output_xlsm_path (Path):
|
|
96
|
+
目的関数の定義を含む Excel ファイルのパス。
|
|
97
|
+
|
|
98
|
+
output_sheet_name (str):
|
|
99
|
+
目的関数の定義を含む含むシートの名前。
|
|
100
|
+
|
|
101
|
+
procedure_name (str):
|
|
102
|
+
実行する Excel マクロ関数名。
|
|
103
|
+
|
|
104
|
+
procedure_args (list or tuple):
|
|
105
|
+
Excel マクロ関数に渡す引数のリストまたはタプル。
|
|
106
|
+
|
|
107
|
+
connect_method (str):
|
|
108
|
+
接続方法。'new' または 'auto'。
|
|
109
|
+
|
|
110
|
+
procedure_timeout (float or None):
|
|
111
|
+
Excel マクロ関数の実行タイムアウト。
|
|
112
|
+
Noneの場合は無制限。
|
|
113
|
+
|
|
114
|
+
terminate_excel_when_quit (bool):
|
|
115
|
+
プログラム終了時に Excel を終了するかどうか。
|
|
116
|
+
connect_method が 'new' の場合 True,
|
|
117
|
+
'auto' の場合 False。
|
|
118
|
+
|
|
119
|
+
excel (CDispatch):
|
|
120
|
+
Excel の COM オブジェクト。
|
|
121
|
+
|
|
122
|
+
input_sheet (CDispatch):
|
|
123
|
+
設計変数を含むシートの COM オブジェクト。
|
|
124
|
+
|
|
125
|
+
output_sheet (CDispatch):
|
|
126
|
+
目的関数を含むシートの COM オブジェクト。
|
|
127
|
+
|
|
128
|
+
input_workbook (CDispatch):
|
|
129
|
+
設計変数を含む xlsm ファイルの COM オブジェクト。
|
|
130
|
+
|
|
131
|
+
output_workbook (CDispatch):
|
|
132
|
+
設計変数を含む xlsm ファイルの COM オブジェクト。
|
|
133
|
+
|
|
134
|
+
"""
|
|
39
135
|
|
|
40
136
|
input_xlsm_path: Path # 操作対象の xlsm パス
|
|
41
137
|
input_sheet_name: str # 変数セルを定義しているシート名
|
|
@@ -55,11 +151,14 @@ class ExcelInterface(FEMInterface):
|
|
|
55
151
|
|
|
56
152
|
visible: bool = False # excel を可視化するかどうか
|
|
57
153
|
display_alerts: bool = False # ダイアログを表示するかどうか
|
|
154
|
+
terminate_excel_when_quit: bool # 終了時に Excel を終了するかどうか
|
|
58
155
|
|
|
59
|
-
_load_problem_from_me: bool = True
|
|
156
|
+
_load_problem_from_me: bool = True
|
|
60
157
|
_excel_pid: int
|
|
61
158
|
_excel_hwnd: int
|
|
62
159
|
_femtet_autosave_buffer: bool # Femtet の自動保存機能の一時退避場所。最適化中はオフにする。
|
|
160
|
+
_with_call_femtet: bool # Femtet を Python から起動するかどうか。Excel から起動できる場合は False でよい。
|
|
161
|
+
|
|
63
162
|
|
|
64
163
|
def __init__(
|
|
65
164
|
self,
|
|
@@ -71,7 +170,9 @@ class ExcelInterface(FEMInterface):
|
|
|
71
170
|
procedure_args: list or tuple = None,
|
|
72
171
|
connect_method: str = 'auto', # or 'new'
|
|
73
172
|
procedure_timeout: float or None = None,
|
|
173
|
+
with_call_femtet: bool = False
|
|
74
174
|
):
|
|
175
|
+
|
|
75
176
|
show_experimental_warning("ExcelInterface")
|
|
76
177
|
|
|
77
178
|
# 初期化
|
|
@@ -85,6 +186,8 @@ class ExcelInterface(FEMInterface):
|
|
|
85
186
|
self.connect_method = connect_method
|
|
86
187
|
self._femtet_autosave_buffer = _get_autosave_enabled()
|
|
87
188
|
self.procedure_timeout = procedure_timeout
|
|
189
|
+
self._with_call_femtet = with_call_femtet
|
|
190
|
+
self.terminate_excel_when_quit = self.connect_method == 'new'
|
|
88
191
|
|
|
89
192
|
# dask サブプロセスのときは space 直下の input_xlsm_path を参照する
|
|
90
193
|
try:
|
|
@@ -101,19 +204,6 @@ class ExcelInterface(FEMInterface):
|
|
|
101
204
|
else:
|
|
102
205
|
self.output_xlsm_path = Path(os.path.abspath(output_xlsm_path)).resolve()
|
|
103
206
|
|
|
104
|
-
# FIXME:
|
|
105
|
-
# そもそも ExcelInterface なので Femtet 関連のことをやらなくていいと思う。
|
|
106
|
-
# FemtetRef が文句なく動けばいいのだが、手元環境ではなぜか動いたり動かなかったりするため
|
|
107
|
-
# 仕方なく Femtet を Python 側から動かしている仮実装。
|
|
108
|
-
# 先に femtet を起動
|
|
109
|
-
util.execute_femtet()
|
|
110
|
-
|
|
111
|
-
# 直後の Excel 起動に間に合わない場合があったため
|
|
112
|
-
# Femtet が Dispatch 可能になるまで捨てプロセスで待つ
|
|
113
|
-
p = _NestableSpawnProcess(target=wait_femtet)
|
|
114
|
-
p.start()
|
|
115
|
-
p.join()
|
|
116
|
-
|
|
117
207
|
# サブプロセスでの restore のための情報保管
|
|
118
208
|
kwargs = dict(
|
|
119
209
|
input_xlsm_path=self.input_xlsm_path,
|
|
@@ -124,6 +214,7 @@ class ExcelInterface(FEMInterface):
|
|
|
124
214
|
procedure_args=self.procedure_args,
|
|
125
215
|
connect_method='new', # subprocess で connect する際は new を強制する
|
|
126
216
|
procedure_timeout=self.procedure_timeout,
|
|
217
|
+
with_call_femtet=self._with_call_femtet,
|
|
127
218
|
)
|
|
128
219
|
FEMInterface.__init__(self, **kwargs)
|
|
129
220
|
|
|
@@ -207,17 +298,53 @@ class ExcelInterface(FEMInterface):
|
|
|
207
298
|
|
|
208
299
|
def add_femtet_ref_xla(self, wb):
|
|
209
300
|
|
|
301
|
+
# search
|
|
302
|
+
ref_file_1 = r'C:\Program Files\Microsoft Office\root\Office16\XLSTART\FemtetRef.xla'
|
|
303
|
+
if not os.path.exists(ref_file_1):
|
|
304
|
+
# 32bit
|
|
305
|
+
ref_file_1 = r'C:\Program Files (x86)\Microsoft Office\root\Office16\XLSTART\FemtetRef.xla'
|
|
306
|
+
if not os.path.exists(ref_file_1):
|
|
307
|
+
raise FileNotFoundError(f'{ref_file_1} not found. Please check the "Enable Macros" command was fired.')
|
|
308
|
+
contain_1 = False
|
|
309
|
+
for ref in wb.VBProject.References:
|
|
310
|
+
if ref.FullPath is not None:
|
|
311
|
+
if ref.FullPath.lower() == ref_file_1.lower():
|
|
312
|
+
contain_1 = True
|
|
313
|
+
# add
|
|
314
|
+
if not contain_1:
|
|
315
|
+
wb.VBProject.References.AddFromFile(ref_file_1)
|
|
316
|
+
|
|
210
317
|
# search
|
|
211
318
|
ref_file_2 = os.path.abspath(util._get_femtetmacro_dllpath())
|
|
212
|
-
|
|
319
|
+
contain_2 = False
|
|
213
320
|
for ref in wb.VBProject.References:
|
|
214
321
|
if ref.Description is not None:
|
|
215
322
|
if ref.Description == 'FemtetMacro': # FemtetMacro
|
|
216
|
-
|
|
323
|
+
contain_2 = True
|
|
217
324
|
# add
|
|
218
|
-
if not
|
|
325
|
+
if not contain_2:
|
|
219
326
|
wb.VBProject.References.AddFromFile(ref_file_2)
|
|
220
327
|
|
|
328
|
+
def remove_femtet_ref_xla(self, wb):
|
|
329
|
+
|
|
330
|
+
# search
|
|
331
|
+
ref_file_1 = r'C:\Program Files\Microsoft Office\root\Office16\XLSTART\FemtetRef.xla'
|
|
332
|
+
if not os.path.exists(ref_file_1):
|
|
333
|
+
# 32bit
|
|
334
|
+
ref_file_1 = r'C:\Program Files (x86)\Microsoft Office\root\Office16\XLSTART\FemtetRef.xla'
|
|
335
|
+
if not os.path.exists(ref_file_1):
|
|
336
|
+
raise FileNotFoundError(f'{ref_file_1} not found. Please check the "Enable Macros" command was fired.')
|
|
337
|
+
for ref in wb.VBProject.References:
|
|
338
|
+
if ref.FullPath is not None:
|
|
339
|
+
if ref.FullPath == ref_file_1: # or ``FemtetMacroを使用するための参照設定を自動で行ないます。``
|
|
340
|
+
wb.VBProject.References.Remove(ref)
|
|
341
|
+
|
|
342
|
+
# search
|
|
343
|
+
for ref in wb.VBProject.References:
|
|
344
|
+
if ref.Description is not None:
|
|
345
|
+
if ref.Description == 'FemtetMacro': # FemtetMacro
|
|
346
|
+
wb.VBProject.References.Remove(ref)
|
|
347
|
+
|
|
221
348
|
def _setup_after_parallel(self, *args, **kwargs):
|
|
222
349
|
# サブプロセス又はメインプロセスのサブスレッドで、最適化を開始する前の前処理
|
|
223
350
|
|
|
@@ -227,7 +354,17 @@ class ExcelInterface(FEMInterface):
|
|
|
227
354
|
# 最適化中は femtet の autosave を無効にする
|
|
228
355
|
_set_autosave_enabled(False)
|
|
229
356
|
|
|
230
|
-
#
|
|
357
|
+
# 必要なら Femtet を起動する
|
|
358
|
+
if self._with_call_femtet:
|
|
359
|
+
util.execute_femtet()
|
|
360
|
+
|
|
361
|
+
# 直後の Excel 起動に間に合わない場合があるため
|
|
362
|
+
# Femtet が Dispatch 可能になるまで捨てプロセスで待つ
|
|
363
|
+
p = _NestableSpawnProcess(target=wait_femtet)
|
|
364
|
+
p.start()
|
|
365
|
+
p.join()
|
|
366
|
+
|
|
367
|
+
# excel に繋ぐ
|
|
231
368
|
self.connect_excel(self.connect_method)
|
|
232
369
|
|
|
233
370
|
# load_objective は 1 回目に呼ばれたのが main thread なので
|
|
@@ -240,11 +377,6 @@ class ExcelInterface(FEMInterface):
|
|
|
240
377
|
if isinstance(obj.fun, ScapeGoatObjective):
|
|
241
378
|
opt.objectives[obj_name].fun = self.objective_from_excel
|
|
242
379
|
|
|
243
|
-
# TODO:
|
|
244
|
-
# __init__ が作った Femtet 以外を排他処理して
|
|
245
|
-
# Excel がそれを使うことを保証するようにする(遅すぎるか?)
|
|
246
|
-
# そもそも、excel から Femtet を起動できればそれで済む(?)。
|
|
247
|
-
|
|
248
380
|
def update(self, parameters: pd.DataFrame) -> None:
|
|
249
381
|
|
|
250
382
|
# params を作成
|
|
@@ -273,44 +405,51 @@ class ExcelInterface(FEMInterface):
|
|
|
273
405
|
except com_error as e:
|
|
274
406
|
raise SolveError(f'Failed to run macro {self.procedure_name}. The original message is: {e}')
|
|
275
407
|
|
|
276
|
-
|
|
277
408
|
def quit(self):
|
|
278
|
-
|
|
409
|
+
if self.terminate_excel_when_quit:
|
|
410
|
+
logger.info('Excel の終了処理を開始します。')
|
|
411
|
+
|
|
412
|
+
self.remove_femtet_ref_xla(self.wb_input)
|
|
413
|
+
self.remove_femtet_ref_xla(self.wb_output)
|
|
414
|
+
|
|
415
|
+
del self.sh_input
|
|
416
|
+
del self.sh_output
|
|
279
417
|
|
|
280
|
-
|
|
281
|
-
|
|
418
|
+
with watch_excel_macro_error(self.excel, timeout=10, restore_book=False):
|
|
419
|
+
self.wb_input.Close(SaveChanges := False)
|
|
420
|
+
if self.input_xlsm_path.name != self.output_xlsm_path.name:
|
|
421
|
+
with watch_excel_macro_error(self.excel, timeout=10, restore_book=False):
|
|
422
|
+
self.wb_output.Close(SaveChanges := False)
|
|
282
423
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
self.wb_output.Close(SaveChanges := False)
|
|
286
|
-
del self.wb_input
|
|
287
|
-
del self.wb_output
|
|
424
|
+
del self.wb_input
|
|
425
|
+
del self.wb_output
|
|
288
426
|
|
|
289
|
-
|
|
290
|
-
|
|
427
|
+
with watch_excel_macro_error(self.excel, timeout=10, restore_book=False):
|
|
428
|
+
self.excel.Quit()
|
|
429
|
+
del self.excel
|
|
291
430
|
|
|
292
|
-
|
|
293
|
-
gc.collect()
|
|
431
|
+
gc.collect() # ここで Excel のプロセスが残らず落ちる
|
|
294
432
|
|
|
295
|
-
|
|
296
|
-
# excel の process の消滅を待つ
|
|
297
|
-
logger.info('Excel の終了を待っています。')
|
|
298
|
-
while self._excel_pid == _get_pid(self._excel_hwnd):
|
|
299
|
-
sleep(1)
|
|
433
|
+
if self._with_call_femtet:
|
|
300
434
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
435
|
+
# quit した後ならば femtet を終了できる
|
|
436
|
+
# excel の process の消滅を待つ
|
|
437
|
+
logger.info('Excel の終了を待っています。')
|
|
438
|
+
while self._excel_pid == _get_pid(self._excel_hwnd):
|
|
439
|
+
sleep(1)
|
|
440
|
+
|
|
441
|
+
# TODO: 正確だが時間がかかる。選択できるようにしたほうがいいかもしれない。
|
|
442
|
+
logger.info('終了する Femtet を特定しています。')
|
|
443
|
+
femtet_pid = util.get_last_executed_femtet_process_id()
|
|
444
|
+
from multiprocessing import Process
|
|
445
|
+
p = Process(target=_terminate_femtet, args=(femtet_pid,))
|
|
446
|
+
p.start()
|
|
447
|
+
p.join()
|
|
448
|
+
logger.info('Excel-Femtet を終了しました。')
|
|
307
449
|
|
|
308
450
|
logger.info('自動保存機能の設定を元に戻しています。')
|
|
309
451
|
_set_autosave_enabled(self._femtet_autosave_buffer)
|
|
310
452
|
|
|
311
|
-
p.join()
|
|
312
|
-
logger.info('Excel-Femtet を終了しました。')
|
|
313
|
-
|
|
314
453
|
# 直接アクセスしてもよいが、ユーザーに易しい名前にするためだけのプロパティ
|
|
315
454
|
@property
|
|
316
455
|
def output_sheet(self) -> CDispatch:
|
|
@@ -432,6 +571,7 @@ def _terminate_femtet(femtet_pid_):
|
|
|
432
571
|
Femtet, caught_pid = dispatch_specific_femtet(femtet_pid_)
|
|
433
572
|
_exit_or_force_terminate(timeout=3, Femtet=Femtet, force=True)
|
|
434
573
|
|
|
574
|
+
|
|
435
575
|
# main thread で作成した excel への参照を含む関数を
|
|
436
576
|
# 直接 thread や process に渡すと機能しない
|
|
437
577
|
class ScapeGoatObjective:
|
|
@@ -33,11 +33,17 @@ from pyfemtet.dispatch_extensions import (
|
|
|
33
33
|
_get_pids,
|
|
34
34
|
DispatchExtensionException,
|
|
35
35
|
)
|
|
36
|
-
from pyfemtet.opt.interface import FEMInterface
|
|
36
|
+
from pyfemtet.opt.interface import FEMInterface
|
|
37
37
|
from pyfemtet._message import Msg
|
|
38
38
|
from pyfemtet._femtet_config_util.autosave import _get_autosave_enabled, _set_autosave_enabled
|
|
39
39
|
from pyfemtet._femtet_config_util.exit import _exit_or_force_terminate
|
|
40
40
|
|
|
41
|
+
if __name__ == '__main__':
|
|
42
|
+
from pyfemtet.logger import get_module_logger
|
|
43
|
+
logger = get_module_logger('opt.interface.FemtetInterface', __name__)
|
|
44
|
+
else:
|
|
45
|
+
from pyfemtet.opt.interface._base import logger
|
|
46
|
+
|
|
41
47
|
|
|
42
48
|
def _post_activate_message(hwnd):
|
|
43
49
|
win32gui.PostMessage(hwnd, win32con.WM_ACTIVATE, win32con.WA_ACTIVE, 0)
|
|
@@ -60,7 +60,7 @@ def add_parametric_results_as_objectives(femopt, indexes, directions) -> bool:
|
|
|
60
60
|
def _parametric_objective(Femtet, parametric_result_index):
|
|
61
61
|
# load dll and set target femtet
|
|
62
62
|
dll = _get_dll_with_set_femtet(Femtet)
|
|
63
|
-
dll.GetPrmResult.restype = ctypes.c_double
|
|
63
|
+
dll.GetPrmResult.restype = ctypes.c_double # 複素数の場合は実部しか取らない
|
|
64
64
|
return dll.GetPrmResult(parametric_result_index)
|
|
65
65
|
|
|
66
66
|
|
|
@@ -10,7 +10,7 @@ from win32com.client import DispatchEx
|
|
|
10
10
|
from pythoncom import CoInitialize, CoUninitialize, com_error
|
|
11
11
|
|
|
12
12
|
from pyfemtet.core import ModelError
|
|
13
|
-
from pyfemtet.opt.interface import FemtetInterface
|
|
13
|
+
from pyfemtet.opt.interface import FemtetInterface
|
|
14
14
|
from pyfemtet._message import Msg
|
|
15
15
|
|
|
16
16
|
|
pyfemtet/opt/optimizer/_base.py
CHANGED
|
@@ -16,10 +16,9 @@ from pyfemtet._message import Msg
|
|
|
16
16
|
from pyfemtet.opt.optimizer.parameter import ExpressionEvaluator, Parameter
|
|
17
17
|
|
|
18
18
|
# logger
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
logger =
|
|
22
|
-
logger.setLevel(logging.INFO)
|
|
19
|
+
from pyfemtet.logger import get_module_logger
|
|
20
|
+
|
|
21
|
+
logger = get_module_logger('opt.optimizer', __name__)
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
class OptimizationMethodChecker:
|
|
@@ -14,9 +14,12 @@ from botorch.acquisition import AcquisitionFunction
|
|
|
14
14
|
from botorch.optim.initializers import gen_batch_initial_conditions
|
|
15
15
|
|
|
16
16
|
from pyfemtet.opt._femopt_core import Constraint
|
|
17
|
-
from pyfemtet.opt.optimizer import OptunaOptimizer
|
|
17
|
+
from pyfemtet.opt.optimizer import OptunaOptimizer
|
|
18
18
|
from pyfemtet._message import Msg
|
|
19
19
|
|
|
20
|
+
from pyfemtet.logger import get_module_logger
|
|
21
|
+
|
|
22
|
+
logger = get_module_logger(__file__, __name__)
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
BotorchConstraint = Callable[[Tensor], Tensor]
|
|
@@ -20,14 +20,14 @@ from pyfemtet.opt.visualization._wrapped_components import html, dcc, dbc
|
|
|
20
20
|
from abc import ABC, abstractmethod
|
|
21
21
|
import logging
|
|
22
22
|
import psutil
|
|
23
|
-
from pyfemtet.logger import
|
|
23
|
+
from pyfemtet.logger import get_module_logger, get_dash_logger
|
|
24
24
|
|
|
25
|
+
logger = get_module_logger('opt.monitor', __name__)
|
|
26
|
+
logger.setLevel(logging.ERROR)
|
|
25
27
|
|
|
26
|
-
dash_logger =
|
|
28
|
+
dash_logger = get_dash_logger()
|
|
27
29
|
dash_logger.setLevel(logging.ERROR)
|
|
28
30
|
|
|
29
|
-
logger = get_logger('viewer')
|
|
30
|
-
logger.setLevel(logging.ERROR)
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class AbstractPage(ABC):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
pyfemtet/__init__.py,sha256=
|
|
1
|
+
pyfemtet/__init__.py,sha256=P1kRuZW02tF-ekLuBqSjV_tIKKqcbfRPDdpp9C8ftUY,21
|
|
2
2
|
pyfemtet/_femtet_config_util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
pyfemtet/_femtet_config_util/autosave.py,sha256=dNirA9XGuFehas8_Jkj2BW9GOzMbPyhnt1WHcH_ObSU,2070
|
|
4
|
-
pyfemtet/_femtet_config_util/exit.py,sha256=
|
|
4
|
+
pyfemtet/_femtet_config_util/exit.py,sha256=0BWID-tjOkmZwmgPFkcJMkWW39voccz5ARIBWvZbHaw,1877
|
|
5
5
|
pyfemtet/_message/1. make_pot.bat,sha256=wrTA0YaL7nUfNB0cS8zljOmwq2qgyG6RMwHQbrwjvY4,476
|
|
6
6
|
pyfemtet/_message/2. make_mo.bat,sha256=6shJ3Yn4BXjDc0hhv_kiGUtVTq4oSRz8-iS4vW29rNE,155
|
|
7
7
|
pyfemtet/_message/__init__.py,sha256=gE1-XX_PzHj9BbhqPaK5VcIHuv6_Tec5qlPMC3IRiBg,100
|
|
@@ -10,36 +10,36 @@ pyfemtet/_message/locales/ja/LC_MESSAGES/messages.po,sha256=F2bJGHVMtk086pekjVwY
|
|
|
10
10
|
pyfemtet/_message/locales/messages.pot,sha256=8Yjf462pJdEtxBLySKT34zMG5CH5uLB_8VaJQll_QsY,14493
|
|
11
11
|
pyfemtet/_message/messages.py,sha256=F8ENLZKoHq5irn-Ag7rqA3aSDsTmRWDyNHvOLY76ROI,13368
|
|
12
12
|
pyfemtet/_util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
pyfemtet/_util/excel_macro_util.py,sha256=
|
|
13
|
+
pyfemtet/_util/excel_macro_util.py,sha256=wja_yE79xXHnr8YuesDypXRXkC6mI4ZYaUU-1wunZCE,7470
|
|
14
14
|
pyfemtet/_warning.py,sha256=TSOj8mOhuyfOUJB24LsW6GNhTA3IzIEevJw_hLKTrq8,2205
|
|
15
15
|
pyfemtet/brep/__init__.py,sha256=V1IQ2s-8eWjXOVlTp2jMav9u-NBiSkmyAX1vmtHDEso,73
|
|
16
16
|
pyfemtet/brep/_impl.py,sha256=Amf_wsUxUosQB3XXhErJ5RGKXBxRnaaPpavb_0Xx6Ek,404
|
|
17
17
|
pyfemtet/core.py,sha256=3lqfBGJ5IuKz2Nqj5pRo7YQqKwx_0ZDL72u95Ur_1p0,1386
|
|
18
|
-
pyfemtet/dispatch_extensions/__init__.py,sha256=
|
|
19
|
-
pyfemtet/dispatch_extensions/_impl.py,sha256=
|
|
20
|
-
pyfemtet/logger/__init__.py,sha256=
|
|
21
|
-
pyfemtet/logger/_impl.py,sha256=
|
|
18
|
+
pyfemtet/dispatch_extensions/__init__.py,sha256=QKpwZ0ffWUB-fiXXhhTL653FcPGLR-JKfxDNidEFoeM,271
|
|
19
|
+
pyfemtet/dispatch_extensions/_impl.py,sha256=yH_yeAnQ-Xi9GfjX-FQt9u3yHnrLYIteRb6HkgYHVEc,16222
|
|
20
|
+
pyfemtet/logger/__init__.py,sha256=UOJ9n_U2xwdTrp0Xgg-N6geySxNzKqTBQlXsaH0kW_w,420
|
|
21
|
+
pyfemtet/logger/_impl.py,sha256=rsAd0HpmveOaLS39ucp3U2OcDhQMWjC5fnVGhbJtWVw,6375
|
|
22
22
|
pyfemtet/opt/__init__.py,sha256=wRR8LbEhb5I6MUgmnCgjB6-tqHlOVxDIo7yPkq0QbBs,758
|
|
23
23
|
pyfemtet/opt/_femopt.py,sha256=h3DQpwdNyPDU9jxc52DEsHaDWO1mVnA4hOT5_omXglo,37377
|
|
24
|
-
pyfemtet/opt/_femopt_core.py,sha256=
|
|
24
|
+
pyfemtet/opt/_femopt_core.py,sha256=rKuZcv3Dn9zzaXrcXXOWLyFFpL_6yva4-29lFTWikXQ,35288
|
|
25
25
|
pyfemtet/opt/_test_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
pyfemtet/opt/_test_utils/control_femtet.py,sha256=
|
|
26
|
+
pyfemtet/opt/_test_utils/control_femtet.py,sha256=8oAl9y5V2n8Nnsgx_ebcZVzwFt1eI3swkdiKg6pg3-M,1085
|
|
27
27
|
pyfemtet/opt/_test_utils/hyper_sphere.py,sha256=nQhw8EIY0DwvcTqrbKhkxiITLZifr4-nG77E-_6ggmA,700
|
|
28
28
|
pyfemtet/opt/_test_utils/record_history.py,sha256=JCNJLZMCNTpJ6VT7iwEt2DIbwmsuQmgC0ClQSfcatj4,3915
|
|
29
|
-
pyfemtet/opt/interface/__init__.py,sha256=
|
|
30
|
-
pyfemtet/opt/interface/_base.py,sha256=
|
|
31
|
-
pyfemtet/opt/interface/_excel_interface.py,sha256=
|
|
32
|
-
pyfemtet/opt/interface/_femtet.py,sha256=
|
|
33
|
-
pyfemtet/opt/interface/_femtet_parametric.py,sha256=
|
|
29
|
+
pyfemtet/opt/interface/__init__.py,sha256=P5Ij-xjB4628qdgacIXLu_WBaWCoBkAk4nEMUCAQzWs,458
|
|
30
|
+
pyfemtet/opt/interface/_base.py,sha256=NVrvHVL7npgZbAQdMziA5TbTBghgi31JwrFH57edBKE,2615
|
|
31
|
+
pyfemtet/opt/interface/_excel_interface.py,sha256=C9Ix1oUm2dHAHrKQPpb4gJo86iGJBcpXjXLa4c_VGSA,22853
|
|
32
|
+
pyfemtet/opt/interface/_femtet.py,sha256=7FFwGJ4TFIhvjCCRIuEsJpJ-Cmo2OIO5cWKosLqcs-U,34944
|
|
33
|
+
pyfemtet/opt/interface/_femtet_parametric.py,sha256=0pAEhHflp0wIxWBVMXI8nCC02oAyRKLinH3Y6O8bq3M,2224
|
|
34
34
|
pyfemtet/opt/interface/_femtet_with_nx/__init__.py,sha256=-6W2g2FDEcKzGHmI5KAKQe-4U5jDpMj0CXuma-GZca0,83
|
|
35
|
-
pyfemtet/opt/interface/_femtet_with_nx/_interface.py,sha256=
|
|
35
|
+
pyfemtet/opt/interface/_femtet_with_nx/_interface.py,sha256=oefISc6c6RPPyhPnWuzCb60tgsrzGiqoIWk1DsiKzTk,5986
|
|
36
36
|
pyfemtet/opt/interface/_femtet_with_nx/update_model.py,sha256=P7VH0i_o-X9OUe6AGaLF1fACPeHNrMjcrOBCA3MMrI4,3092
|
|
37
|
-
pyfemtet/opt/interface/_femtet_with_sldworks.py,sha256=
|
|
37
|
+
pyfemtet/opt/interface/_femtet_with_sldworks.py,sha256=qqo2P4qZN0d89uNQyohKxq-Yhdql5vC0QHg4bpy7Ky8,11011
|
|
38
38
|
pyfemtet/opt/optimizer/__init__.py,sha256=Ia6viowECkG0IFXtFef0tJ4jDKsoDzJLqMJ9xLFH2LQ,543
|
|
39
|
-
pyfemtet/opt/optimizer/_base.py,sha256=
|
|
39
|
+
pyfemtet/opt/optimizer/_base.py,sha256=GsTOs3ZHLqCglYYRBk4XSJ5h1lR_W9eA2STiyQig6dM,12497
|
|
40
40
|
pyfemtet/opt/optimizer/_optuna/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
41
|
pyfemtet/opt/optimizer/_optuna/_botorch_patch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
-
pyfemtet/opt/optimizer/_optuna/_botorch_patch/enable_nonlinear_constraint.py,sha256=
|
|
42
|
+
pyfemtet/opt/optimizer/_optuna/_botorch_patch/enable_nonlinear_constraint.py,sha256=b2-PP2HM46kJS4cJkBWnxnW9AS9JfeVkEjmkoKK_ziE,8949
|
|
43
43
|
pyfemtet/opt/optimizer/_optuna/_optuna.py,sha256=nKlEYizSu6BQu8OMhRWRJxk5eXJ0LAPR7h6CQOjbdxE,16460
|
|
44
44
|
pyfemtet/opt/optimizer/_optuna/_pof_botorch.py,sha256=yVyg1V3trqirSDtbRepgftvS02AEkAhrgjou21JS124,72717
|
|
45
45
|
pyfemtet/opt/optimizer/_scipy.py,sha256=_2whhMNq6hC1lr5PlYhpZ8Zlh6-DkAjz8SVB5qHIpYg,4766
|
|
@@ -60,7 +60,7 @@ pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.femprj,sha256=knN0bBTHm5CqExLdmxd
|
|
|
60
60
|
pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.py,sha256=JoGQSwH3yJnABxyd-WJfrwMkhd1UV0yYF2L2RvMFXmc,4559
|
|
61
61
|
pyfemtet/opt/samples/femprj_sample/cad_ex01_SW_test_result.reccsv,sha256=NS0Zik2c1mbMdGa0hGJaRQdCD08Bltx84n9QzP5CjPo,4736
|
|
62
62
|
pyfemtet/opt/samples/femprj_sample/constrained_pipe.femprj,sha256=MAl-VQfethwYvl49RkuW7FQlFCQ9_mYvc03SsqBCad0,57414
|
|
63
|
-
pyfemtet/opt/samples/femprj_sample/constrained_pipe.py,sha256=
|
|
63
|
+
pyfemtet/opt/samples/femprj_sample/constrained_pipe.py,sha256=mIscUYVGmoz5IpR_T9wyC1vTVW95PbGAeuTcDvq1Nk8,3226
|
|
64
64
|
pyfemtet/opt/samples/femprj_sample/constrained_pipe_test_result.reccsv,sha256=AbAMXLtxrEBHLjdM0HnGQ7j3uJtVHZpxOZxOqNmO1CA,1796
|
|
65
65
|
pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.femprj,sha256=dbanN3W2eX_ciZ0wZGqK60mc4edSVh5G2OqbbMKyFng,74898
|
|
66
66
|
pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.py,sha256=RxLSXFs0SqUjlug_JZAKlkJhqJdQCY3Y3F-DtSQRtVM,2458
|
|
@@ -99,7 +99,7 @@ pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.femprj,sha256=dMwQM
|
|
|
99
99
|
pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.py,sha256=vMy-KUP1wEMV9Rt6yXjkE40Fcs1t1cpQK-nQJK8hHao,2284
|
|
100
100
|
pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py,sha256=4X0cl3YWpYarcNBCH79mrlyFuKUYSqvnGzokEbv9ILk,2335
|
|
101
101
|
pyfemtet/opt/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
102
|
-
pyfemtet/opt/visualization/_base.py,sha256=
|
|
102
|
+
pyfemtet/opt/visualization/_base.py,sha256=xh6yIkoyBrV670JhAnR9rRewpH7P25wz0pnr0JH0pvc,7623
|
|
103
103
|
pyfemtet/opt/visualization/_complex_components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
104
104
|
pyfemtet/opt/visualization/_complex_components/alert_region.py,sha256=sX8xqT4NqhACagK4YgumF4ResrTqhOKQ8dN4q58shI8,2106
|
|
105
105
|
pyfemtet/opt/visualization/_complex_components/control_femtet.py,sha256=LcMoh_MQQ1-hiz7nMGOmxSSoJLOX8viVxZB6uIggg_g,6243
|
|
@@ -120,8 +120,8 @@ pyfemtet/opt/visualization/result_viewer/.gitignore,sha256=ryvb4aqbbsHireHWlPQfx
|
|
|
120
120
|
pyfemtet/opt/visualization/result_viewer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
121
121
|
pyfemtet/opt/visualization/result_viewer/application.py,sha256=WcHBx_J5eNLKSaprpk9BGifwhO04oN8FiNGYTWorrXA,1691
|
|
122
122
|
pyfemtet/opt/visualization/result_viewer/pages.py,sha256=laEAKHAtdshCAHxgXo-zMNg3RP6lCxfszO3XwLnF1dU,32156
|
|
123
|
-
pyfemtet-0.
|
|
124
|
-
pyfemtet-0.
|
|
125
|
-
pyfemtet-0.
|
|
126
|
-
pyfemtet-0.
|
|
127
|
-
pyfemtet-0.
|
|
123
|
+
pyfemtet-0.7.0.dist-info/LICENSE,sha256=sVQBhyoglGJUu65-BP3iR6ujORI6YgEU2Qm-V4fGlOA,1485
|
|
124
|
+
pyfemtet-0.7.0.dist-info/METADATA,sha256=T0IJPwww5DvoZN1Z2ucdGJhBsThjPn05lVU27zfC_go,3371
|
|
125
|
+
pyfemtet-0.7.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
126
|
+
pyfemtet-0.7.0.dist-info/entry_points.txt,sha256=ZfYqRaoiPtuWqFi2_msccyrVF0LurMn-IHlYamAegZo,104
|
|
127
|
+
pyfemtet-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|