PyFemtet 0.3.2__tar.gz → 0.3.4__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.
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/PKG-INFO +2 -1
- pyfemtet-0.3.4/pyfemtet/__init__.py +1 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/dispatch_extensions.py +49 -46
- pyfemtet-0.3.4/pyfemtet/logger.py +101 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/opt/base.py +236 -167
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/opt/interface.py +23 -19
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyproject.toml +2 -1
- pyfemtet-0.3.2/pyfemtet/__init__.py +0 -1
- pyfemtet-0.3.2/pyfemtet/opt/_optimizer.py +0 -241
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/LICENSE +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/README.md +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.femprj +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.prt +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/gau_ex08_parametric.femprj +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/gau_ex08_parametric.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/her_ex40_parametric.femprj +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/her_ex40_parametric.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/wat_ex14_parallel_parametric.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/wat_ex14_parametric.femprj +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/FemtetPJTSample/wat_ex14_parametric.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/_old/_SW_Femtet.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/core.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/opt/_FemtetWithNX/update_model.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/opt/__init__.py +0 -0
- {pyfemtet-0.3.2 → pyfemtet-0.3.4}/pyfemtet/opt/monitor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyfemtet
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Design parameter optimization using Femtet.
|
|
5
5
|
Home-page: https://github.com/pyfemtet/pyfemtet
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Requires-Dist: botorch (>=0.9.5,<0.10.0) ; python_version < "3.12"
|
|
17
|
+
Requires-Dist: colorlog (>=6.8.0,<7.0.0)
|
|
17
18
|
Requires-Dist: dash (>=2.14.2,<3.0.0)
|
|
18
19
|
Requires-Dist: dash-bootstrap-components (>=1.5.0,<2.0.0)
|
|
19
20
|
Requires-Dist: dask (>=2023.12.1,<2024.0.0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.4"
|
|
@@ -3,9 +3,8 @@ from typing import Tuple
|
|
|
3
3
|
import os
|
|
4
4
|
from time import time, sleep
|
|
5
5
|
from multiprocessing import current_process
|
|
6
|
-
import logging
|
|
7
|
-
import warnings
|
|
8
6
|
|
|
7
|
+
from tqdm import tqdm
|
|
9
8
|
import psutil
|
|
10
9
|
from dask.distributed import Lock
|
|
11
10
|
|
|
@@ -17,16 +16,15 @@ from femtetutils import util
|
|
|
17
16
|
|
|
18
17
|
from multiprocessing.context import BaseContext, SpawnProcess, _concrete_contexts
|
|
19
18
|
from multiprocessing.process import _children, _cleanup
|
|
19
|
+
from multiprocessing.managers import SyncManager
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
logger
|
|
23
|
-
|
|
24
|
-
handler.setFormatter(logging.Formatter('[%(process)d] %(message)s'))
|
|
25
|
-
logger.addHandler(handler)
|
|
21
|
+
import logging
|
|
22
|
+
from .logger import get_logger
|
|
23
|
+
logger = get_logger('dispatch')
|
|
26
24
|
logger.setLevel(logging.INFO)
|
|
27
25
|
|
|
28
26
|
|
|
29
|
-
DISPATCH_TIMEOUT =
|
|
27
|
+
DISPATCH_TIMEOUT = 120
|
|
30
28
|
|
|
31
29
|
|
|
32
30
|
class DispatchExtensionException(Exception):
|
|
@@ -114,11 +112,6 @@ _concrete_contexts.update(
|
|
|
114
112
|
)
|
|
115
113
|
|
|
116
114
|
|
|
117
|
-
def _log_prefix():
|
|
118
|
-
prefix = current_process().name + ' : '
|
|
119
|
-
return prefix
|
|
120
|
-
|
|
121
|
-
|
|
122
115
|
def _get_hwnds(pid):
|
|
123
116
|
"""Proces ID から window handle を取得します."""
|
|
124
117
|
def callback(hwnd, _hwnds):
|
|
@@ -147,6 +140,10 @@ def _get_pids(process_name):
|
|
|
147
140
|
return pids
|
|
148
141
|
|
|
149
142
|
|
|
143
|
+
def _get_subprocess_log_prefix():
|
|
144
|
+
return f'({current_process().name}) '
|
|
145
|
+
|
|
146
|
+
|
|
150
147
|
def launch_and_dispatch_femtet(timeout=DISPATCH_TIMEOUT) -> Tuple[IFemtet, int]:
|
|
151
148
|
"""Launch Femtet by new process and connect to it.
|
|
152
149
|
|
|
@@ -160,16 +157,16 @@ def launch_and_dispatch_femtet(timeout=DISPATCH_TIMEOUT) -> Tuple[IFemtet, int]:
|
|
|
160
157
|
Returns:
|
|
161
158
|
Tuple[IFemtet, int]:
|
|
162
159
|
"""
|
|
163
|
-
|
|
164
160
|
util.execute_femtet()
|
|
165
161
|
pid = util.get_last_executed_femtet_process_id()
|
|
166
162
|
logger.debug(f'Target pid is {pid}.')
|
|
167
|
-
|
|
163
|
+
for i in tqdm(range(5), 'wait for launch femtet...'):
|
|
164
|
+
sleep(1)
|
|
168
165
|
Femtet, pid = dispatch_specific_femtet(pid, timeout)
|
|
169
166
|
return Femtet, pid
|
|
170
167
|
|
|
171
168
|
|
|
172
|
-
def dispatch_femtet(timeout=DISPATCH_TIMEOUT) -> Tuple[IFemtet, int]:
|
|
169
|
+
def dispatch_femtet(timeout=DISPATCH_TIMEOUT, subprocess_log_prefix='') -> Tuple[IFemtet, int]:
|
|
173
170
|
"""Connect to existing Femtet process.
|
|
174
171
|
|
|
175
172
|
Args:
|
|
@@ -181,11 +178,13 @@ def dispatch_femtet(timeout=DISPATCH_TIMEOUT) -> Tuple[IFemtet, int]:
|
|
|
181
178
|
Returns:
|
|
182
179
|
Tuple[IFemtet, int]:
|
|
183
180
|
"""
|
|
184
|
-
|
|
185
181
|
# Dispatch
|
|
186
|
-
|
|
182
|
+
if subprocess_log_prefix:
|
|
183
|
+
logger.debug('%s'+'Try to connect Femtet.', subprocess_log_prefix)
|
|
184
|
+
else:
|
|
185
|
+
logger.info('Try to connect Femtet.')
|
|
187
186
|
Femtet = Dispatch('FemtetMacro.Femtet')
|
|
188
|
-
logger.debug(
|
|
187
|
+
logger.debug('%s'+'Dispatch finished.', subprocess_log_prefix)
|
|
189
188
|
|
|
190
189
|
# timeout 秒以内に接続が確立するか
|
|
191
190
|
start = time()
|
|
@@ -194,27 +193,28 @@ def dispatch_femtet(timeout=DISPATCH_TIMEOUT) -> Tuple[IFemtet, int]:
|
|
|
194
193
|
|
|
195
194
|
# 接続が確立
|
|
196
195
|
if hwnd > 0:
|
|
197
|
-
logger.debug(f'{
|
|
196
|
+
logger.debug('%s'+f'Dispatched hwnd is {hwnd} and its pid is {_get_pid(hwnd)}. Connection established.', subprocess_log_prefix)
|
|
198
197
|
break
|
|
199
198
|
else:
|
|
200
|
-
logger.debug(f'
|
|
199
|
+
logger.debug('%s'+f'Dispatched hwnd is {hwnd}. Waiting for establishing connection.', subprocess_log_prefix)
|
|
201
200
|
|
|
202
201
|
# 接続がタイムアウト
|
|
203
202
|
if time()-start > timeout:
|
|
204
|
-
raise FemtetConnectionTimeoutError(f'
|
|
203
|
+
raise FemtetConnectionTimeoutError(f'Connection trial with Femtet is timed out in {timeout} sec')
|
|
205
204
|
|
|
206
205
|
sleep(1)
|
|
207
206
|
|
|
208
207
|
# pid を取得
|
|
209
208
|
pid = _get_pid(hwnd)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
if subprocess_log_prefix:
|
|
210
|
+
logger.debug('%s'+f'Successfully connected. The pid of Femtet is {pid}.', subprocess_log_prefix)
|
|
211
|
+
else:
|
|
212
|
+
logger.info(f'Successfully connected. The pid of Femtet is {pid}.')
|
|
214
213
|
|
|
215
214
|
return Femtet, pid
|
|
216
215
|
|
|
217
216
|
|
|
217
|
+
|
|
218
218
|
def _block_other_femtets(
|
|
219
219
|
target_pid,
|
|
220
220
|
subprocess_idx,
|
|
@@ -239,9 +239,10 @@ def _block_other_femtets(
|
|
|
239
239
|
else:
|
|
240
240
|
lock_inter_subproc.acquire()
|
|
241
241
|
try:
|
|
242
|
-
logger.debug(f'
|
|
243
|
-
_, my_pid = dispatch_femtet(2)
|
|
242
|
+
logger.debug('%s'+f'Subprocess started.', _get_subprocess_log_prefix())
|
|
243
|
+
_, my_pid = dispatch_femtet(2, _get_subprocess_log_prefix())
|
|
244
244
|
except DispatchExtensionException:
|
|
245
|
+
logger.debug('%s'+f'Connection failed. The other subprocesses will skip.', _get_subprocess_log_prefix())
|
|
245
246
|
my_pid = 0
|
|
246
247
|
# ひとつでもここに来れば、それ以降は探しても無駄なのでスキップフラグを立てる
|
|
247
248
|
for i in range(len(connection_flags)-1):
|
|
@@ -251,8 +252,6 @@ def _block_other_femtets(
|
|
|
251
252
|
|
|
252
253
|
# # target なら Dispatch の終了を通知する前に main を lock する
|
|
253
254
|
# if my_pid == target_pid:
|
|
254
|
-
# logger.info(f'{_log_prefix()}Connected to {my_pid}. This is the target.')
|
|
255
|
-
# logger.info(f'{_log_prefix()}Start to block main process.')
|
|
256
255
|
# lock_main.acquire()
|
|
257
256
|
|
|
258
257
|
# Dispatch の終了を通知
|
|
@@ -266,29 +265,30 @@ def _block_other_femtets(
|
|
|
266
265
|
# if all(connection_flags[:-1]):
|
|
267
266
|
# break
|
|
268
267
|
# if time()-start > timeout_main_wait_for_us:
|
|
269
|
-
# logger.error(f'{_log_prefix()}Timed out while waiting for other subprocesses.')
|
|
270
268
|
# return -1
|
|
271
269
|
# sleep(1)
|
|
272
|
-
|
|
273
|
-
logger.debug(f'{_log_prefix()}Release {my_pid}.')
|
|
270
|
+
logger.debug('%s'+f'Release {my_pid}.', _get_subprocess_log_prefix())
|
|
274
271
|
# lock_main.release()
|
|
275
272
|
return 0
|
|
276
273
|
|
|
277
274
|
# my_pid が非正なら何にも関与しないので即刻終了する
|
|
278
275
|
elif my_pid <= 0:
|
|
279
|
-
logger.debug(
|
|
276
|
+
logger.debug('%s'+'Failed or timed out to connect Femtet.', _get_subprocess_log_prefix())
|
|
280
277
|
return 1
|
|
281
278
|
|
|
282
279
|
# そうでなければメインプロセスが Dispatch を終えるまで解放しない
|
|
283
280
|
else:
|
|
284
|
-
logger.debug(f'
|
|
281
|
+
logger.debug('%s'+f'Connected to {my_pid}. Keep connection to block.', _get_subprocess_log_prefix())
|
|
285
282
|
start = time()
|
|
286
283
|
while True:
|
|
287
284
|
if connection_flags[-1]:
|
|
288
|
-
logger.debug(
|
|
285
|
+
logger.debug('%s'+'Main process seems to connect target Femtet.', _get_subprocess_log_prefix())
|
|
289
286
|
return 1
|
|
290
287
|
if time()-start > timeout_main_wait_for_us:
|
|
291
|
-
logger.
|
|
288
|
+
logger.warning(
|
|
289
|
+
'%s'+f'Timed out to wait for the main process to {timeout_main_wait_for_us}',
|
|
290
|
+
_get_subprocess_log_prefix()
|
|
291
|
+
)
|
|
292
292
|
return -1
|
|
293
293
|
sleep(1)
|
|
294
294
|
|
|
@@ -379,7 +379,6 @@ def dispatch_specific_femtet_core(pid, timeout=DISPATCH_TIMEOUT) -> Tuple[IFemte
|
|
|
379
379
|
Returns:
|
|
380
380
|
Tuple[IFemtet, int]:
|
|
381
381
|
"""
|
|
382
|
-
|
|
383
382
|
# TODO: 安定性を見て lock_main を復活させるか決める
|
|
384
383
|
|
|
385
384
|
if timeout < 5:
|
|
@@ -387,15 +386,15 @@ def dispatch_specific_femtet_core(pid, timeout=DISPATCH_TIMEOUT) -> Tuple[IFemte
|
|
|
387
386
|
|
|
388
387
|
# 存在する Femtet プロセスの列挙
|
|
389
388
|
pids = _get_pids('Femtet.exe')
|
|
390
|
-
logger.info(f'
|
|
389
|
+
logger.info(f'PID of existing Femtet processes: {pids}')
|
|
391
390
|
if not (pid in pids):
|
|
392
391
|
raise FemtetNotFoundException(f"Femtet (pid = {pid}) doesn't exist.")
|
|
393
392
|
|
|
393
|
+
logger.info('Searching specific Femtet...')
|
|
394
|
+
|
|
394
395
|
# 子プロセスの準備
|
|
395
396
|
# with Manager() as manager:
|
|
396
|
-
|
|
397
|
-
from multiprocessing.managers import SyncManager
|
|
398
|
-
m = SyncManager(ctx=_NestableSpawnContext())
|
|
397
|
+
m = SyncManager(ctx=_NestableSpawnContext()) # このへんが時間のかかる処理
|
|
399
398
|
m.start()
|
|
400
399
|
with m as manager:
|
|
401
400
|
# フラグの準備
|
|
@@ -406,9 +405,11 @@ def dispatch_specific_femtet_core(pid, timeout=DISPATCH_TIMEOUT) -> Tuple[IFemte
|
|
|
406
405
|
connection_flags.append(False)
|
|
407
406
|
|
|
408
407
|
# 目的以外の Femtet をブロックする子プロセスを開始
|
|
408
|
+
logger.debug('Start subprocess to block Femtet other than target pid.')
|
|
409
409
|
processes = []
|
|
410
|
-
for subprocess_id in range(len(pids)):
|
|
410
|
+
for subprocess_id in tqdm(range(len(pids)), 'Specifying connection...'):
|
|
411
411
|
p = _NestableSpawnProcess(
|
|
412
|
+
# p = Process(
|
|
412
413
|
target=_block_other_femtets,
|
|
413
414
|
args=(
|
|
414
415
|
pid,
|
|
@@ -423,6 +424,7 @@ def dispatch_specific_femtet_core(pid, timeout=DISPATCH_TIMEOUT) -> Tuple[IFemte
|
|
|
423
424
|
processes.append(p)
|
|
424
425
|
|
|
425
426
|
# 子プロセスの Dispatch 完了を待つ
|
|
427
|
+
start = time()
|
|
426
428
|
while True:
|
|
427
429
|
if all(connection_flags[:-1]):
|
|
428
430
|
break
|
|
@@ -443,7 +445,7 @@ def dispatch_specific_femtet_core(pid, timeout=DISPATCH_TIMEOUT) -> Tuple[IFemte
|
|
|
443
445
|
|
|
444
446
|
# 子プロセスによるブロックが終了しているので Dispatch する
|
|
445
447
|
try:
|
|
446
|
-
logger.debug(
|
|
448
|
+
logger.debug('Block process seems to be finished. Try Dispatch.')
|
|
447
449
|
Femtet, my_pid = dispatch_femtet()
|
|
448
450
|
except DispatchExtensionException as e:
|
|
449
451
|
# lock_main.release()
|
|
@@ -458,8 +460,9 @@ def dispatch_specific_femtet_core(pid, timeout=DISPATCH_TIMEOUT) -> Tuple[IFemte
|
|
|
458
460
|
|
|
459
461
|
if my_pid != pid: # pid の結果が違う場合
|
|
460
462
|
txt = f'Target pid is {pid}, but connected pid is {my_pid}. '
|
|
461
|
-
txt += f'The common reason is that
|
|
462
|
-
|
|
463
|
+
txt += f'The common reason is that THIS python process once connected {pid}.'
|
|
464
|
+
logger.warn(txt)
|
|
465
|
+
# warnings.warn(txt)
|
|
463
466
|
|
|
464
467
|
return Femtet, my_pid
|
|
465
468
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import logging
|
|
4
|
+
from colorlog import ColoredFormatter
|
|
5
|
+
from dask.distributed import get_worker
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
__all__ = ['get_logger']
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _get_worker_name_as_prefix():
|
|
12
|
+
name = '(Main) '
|
|
13
|
+
try:
|
|
14
|
+
worker = get_worker()
|
|
15
|
+
if isinstance(worker.name, str): # local なら index, cluster なら tcp address
|
|
16
|
+
name = f'({worker.name}) '
|
|
17
|
+
else:
|
|
18
|
+
name = f'(Sub{worker.name}) '
|
|
19
|
+
except ValueError:
|
|
20
|
+
pass
|
|
21
|
+
return name
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DaskLogRecord(logging.LogRecord):
|
|
25
|
+
"""Generate a log message with dask worker name."""
|
|
26
|
+
|
|
27
|
+
# def __init__(self, *args, **kwargs):
|
|
28
|
+
# super().__init__(*args, **kwargs)
|
|
29
|
+
# self.worker = _get_worker_name_as_prefix()
|
|
30
|
+
|
|
31
|
+
def getMessage(self):
|
|
32
|
+
"""Add worker name to loggin message.
|
|
33
|
+
|
|
34
|
+
This function is originated from logging.LogRecord.
|
|
35
|
+
|
|
36
|
+
# Copyright (C) 2001-2022 Vinay Sajip. All Rights Reserved.
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
msg = str(self.msg)
|
|
40
|
+
if self.args:
|
|
41
|
+
msg = msg % self.args
|
|
42
|
+
msg = _get_worker_name_as_prefix() + msg
|
|
43
|
+
return msg
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
logging.setLogRecordFactory(DaskLogRecord) # すべての logging %(message)s の前に prefix を入れる
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _color_supported() -> bool:
|
|
50
|
+
"""Detection of color support.
|
|
51
|
+
|
|
52
|
+
This function is originated from optuna.logging.
|
|
53
|
+
|
|
54
|
+
# Copyright (c) 2018 Preferred Networks, Inc.
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
# NO_COLOR environment variable:
|
|
59
|
+
if os.environ.get("NO_COLOR", None):
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
if not hasattr(sys.stderr, "isatty") or not sys.stderr.isatty():
|
|
63
|
+
return False
|
|
64
|
+
else:
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _create_formatter() -> logging.Formatter:
|
|
69
|
+
"""Create a formatter."""
|
|
70
|
+
# header = f"[pyfemtet %(name)s] %(levelname).4s %(worker)s]"
|
|
71
|
+
header = f"[pyfemtet %(name)s %(levelname).4s]"
|
|
72
|
+
message = "%(message)s"
|
|
73
|
+
|
|
74
|
+
formatter = ColoredFormatter(
|
|
75
|
+
f"%(log_color)s{header}%(reset)s {message}",
|
|
76
|
+
datefmt=None,
|
|
77
|
+
reset=True,
|
|
78
|
+
log_colors={
|
|
79
|
+
"DEBUG": "purple",
|
|
80
|
+
"INFO": "cyan",
|
|
81
|
+
"WARNING": "yellow",
|
|
82
|
+
"ERROR": "light_red",
|
|
83
|
+
"CRITICAL": "red",
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return formatter
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_logger(logger_name):
|
|
91
|
+
"""Return a logger with a default ColoredFormatter."""
|
|
92
|
+
|
|
93
|
+
formatter = _create_formatter()
|
|
94
|
+
|
|
95
|
+
logger = logging.getLogger(logger_name)
|
|
96
|
+
handler = logging.StreamHandler()
|
|
97
|
+
handler.setFormatter(formatter)
|
|
98
|
+
logger.addHandler(handler)
|
|
99
|
+
logger.setLevel(logging.DEBUG)
|
|
100
|
+
|
|
101
|
+
return logger
|