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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.6.6"
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 = logging.getLogger('fem')
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 = logging.getLogger(__name__)
12
- if __name__ == '__main__':
13
- formatter = logging.Formatter(logging.BASIC_FORMAT)
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__':
@@ -9,4 +9,3 @@ from pyfemtet.dispatch_extensions._impl import (
9
9
  _get_pid,
10
10
  _get_pids,
11
11
  )
12
-
@@ -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 = get_logger('dispatch')
28
- logger.setLevel(logging.INFO)
25
+ logger = get_module_logger('dispatch', __name__)
29
26
 
30
27
 
31
28
  DISPATCH_TIMEOUT = 120
@@ -1,3 +1,22 @@
1
- from pyfemtet.logger._impl import get_logger
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
- __all__ = ['get_logger']
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 logging
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
- def _get_worker_name_as_prefix():
9
- name = '(Main) '
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 = _get_worker_name_as_prefix() + msg
44
+ msg = _get_dask_worker_name() + ' ' + msg
40
45
  return msg
41
46
 
42
47
 
43
- logging.setLogRecordFactory(_DaskLogRecord) # すべての logging %(message)s の前に prefix を入れる
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
- def _color_supported() -> bool:
47
- """Detection of color support.
103
+ logger.setLevel(level)
48
104
 
49
- This function is originated from optuna.logging.
50
105
 
51
- # Copyright (c) 2018 Preferred Networks, Inc.
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
- # NO_COLOR environment variable:
56
- if os.environ.get("NO_COLOR", None):
57
- return False
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
- return True
63
-
64
-
65
- def _create_formatter() -> logging.Formatter:
66
- """Create a formatter."""
67
- # header = f"[pyfemtet %(name)s] %(levelname).4s %(worker)s]"
68
- header = f"[pyfemtet %(name)s %(levelname).4s]"
69
- message = "%(message)s"
70
-
71
- formatter = ColoredFormatter(
72
- f"%(log_color)s{header}%(reset)s {message}",
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 get_logger(logger_name):
88
- """Returns a logger.
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
- Examples:
91
- >>> # Retrieves a specific logger used in pyfemtet.opt.
92
- >>> import logging # doctest: +SKIP
93
- >>> from pyfemtet.logger import get_logger # doctest: +SKIP
94
- >>> logger = get_logger('opt') # logger of optimizer # doctest: +SKIP
95
- >>> logger.setLevel(logging.ERROR) # disable all log from optimizer # doctest: +SKIP
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
- formatter = _create_formatter()
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 = logging.getLogger(logger_name)
102
- handler = logging.StreamHandler()
103
- handler.setFormatter(formatter)
104
- logger.addHandler(handler)
105
- logger.setLevel(logging.DEBUG)
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.")
@@ -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 logging
36
- from pyfemtet.logger import get_logger
37
- logger = get_logger('femopt')
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._actor_data is None:
625
+ if self.__scheduler_address is None:
645
626
  return self._df
646
627
  else:
647
- return self._actor_data.get_df().result()
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._actor_data is None:
642
+ if self.__scheduler_address is None:
651
643
  self._df = df
652
644
  else:
653
- self._actor_data.set_df(df).result()
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, logger
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
@@ -5,11 +5,9 @@ from abc import ABC, abstractmethod
5
5
 
6
6
  import pandas as pd
7
7
 
8
- import logging
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 logging
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 # TODO: add_parameter() 等を省略するかどうか。定義するだけでフラグとして機能する。
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
- contain = False
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
- contain = True
323
+ contain_2 = True
217
324
  # add
218
- if not contain:
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
- # excel に繋ぎなおす
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
- logger.info('Excel-Femtet の終了処理を開始します。') # FIXME: message にする
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
- del self.sh_input
281
- del self.sh_output
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
- self.wb_input.Close(SaveChanges := False)
284
- if self.input_xlsm_path.name != self.output_xlsm_path.name:
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
- self.excel.Quit()
290
- del self.excel
427
+ with watch_excel_macro_error(self.excel, timeout=10, restore_book=False):
428
+ self.excel.Quit()
429
+ del self.excel
291
430
 
292
- import gc
293
- gc.collect()
431
+ gc.collect() # ここで Excel のプロセスが残らず落ちる
294
432
 
295
- # quit した後ならば femtet を終了できる
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
- logger.info('終了する Femtet を特定しています。')
303
- femtet_pid = util.get_last_executed_femtet_process_id()
304
- from multiprocessing import Process
305
- p = Process(target=_terminate_femtet, args=(femtet_pid,))
306
- p.start()
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, logger
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
 
@@ -6,7 +6,7 @@ import pandas as pd
6
6
  from dask.distributed import get_worker
7
7
 
8
8
  from pyfemtet.core import ModelError
9
- from pyfemtet.opt.interface import FemtetInterface, logger
9
+ from pyfemtet.opt.interface import FemtetInterface
10
10
  from pyfemtet._message import Msg
11
11
 
12
12
 
@@ -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, logger
13
+ from pyfemtet.opt.interface import FemtetInterface
14
14
  from pyfemtet._message import Msg
15
15
 
16
16
 
@@ -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 logging
20
- from pyfemtet.logger import get_logger
21
- logger = get_logger('opt')
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, logger
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]
@@ -65,7 +65,6 @@ def radius_diff(Femtet, opt):
65
65
  external_r = params['external_r']
66
66
  return external_r - internal_r
67
67
 
68
-
69
68
  if __name__ == '__main__':
70
69
  # Setup optimization method
71
70
  opt = OptunaOptimizer(
@@ -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 get_logger
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 = logging.getLogger('werkzeug')
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyfemtet
3
- Version: 0.6.6
3
+ Version: 0.7.0
4
4
  Summary: Design parameter optimization using Femtet.
5
5
  Home-page: https://github.com/pyfemtet/pyfemtet
6
6
  License: BSD-3-Clause
@@ -1,7 +1,7 @@
1
- pyfemtet/__init__.py,sha256=GTf8rijLTDSqTWQgxKQN312t-j2E-t3ioZB4U22DXxc,21
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=sx8Wcepgi-lL5qJpJl6WvlzbeVheU9_Dtf1f38mmoTo,1822
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=Euxz3QmvTnnQCkWnbnPhvX7xXxppRONX69VlFxNCojA,7540
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=MI9b6oIS2IXnTNHy8jvZ4QURdTHQd9PN-gifYxqVvk4,272
19
- pyfemtet/dispatch_extensions/_impl.py,sha256=HU7rKRAzEe5yYukWrKtdi1aIbUas_kLyaa_KZZGCELE,16244
20
- pyfemtet/logger/__init__.py,sha256=DZNTD9BboiFU9LOiyPKi_Y6gWAga5f1lWkVoq7LV_y0,71
21
- pyfemtet/logger/_impl.py,sha256=ZN5Rj3kb9UEGFt5KSLlzwfrLF_SAoOxgPBkadwh2Y8w,2825
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=Sn13SI1r5OvSu6C9XjkqTrFz2IgO_vMszIAgA-gx-TU,34348
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=Oy2MmNS-LhUXF9rKLa8AXAfJhppIQI8Nha8LmEZflmk,1169
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=5hel-mP6tuxzIEJFMZJZWUEWEbFSsskzCWlQ3HORTYI,466
30
- pyfemtet/opt/interface/_base.py,sha256=aPJ55dTp4-Q4KMkUZVRlquuBBWWOIOdC6yQsYZR4Jy0,2626
31
- pyfemtet/opt/interface/_excel_interface.py,sha256=kUNTtv98Zfot1ZJk281fhg6-EGQp8Jf_T8MeuO9LS08,16830
32
- pyfemtet/opt/interface/_femtet.py,sha256=dmKyRG8sWuX2JHjcXpvJ2q632oZh4I94iVo4u7Z7w_M,34742
33
- pyfemtet/opt/interface/_femtet_parametric.py,sha256=KDG8SB43AgwuhpCStjvx10G0RzyHhga6k4dfvp0gvYU,2175
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=BXWdzIFcId1EovpbRD5DmkW0BwqhpDvOuGBv9kdCGy8,5994
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=A9o-IY8Npq0CHK7yGxBw47wmOtNv5IYR80U2XAabSWM,11019
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=0jX68VEfLI08Qr01BvfPCHKKlr3Bj6gWQ0T81qpX0y4,12507
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=2hUP2c8mokkRaSQ8nXxgCCmz8e0JKvEz8R2qIGnTGm0,8863
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=9Y5kE8ilNTaPzcjn1qCAdXQnyjYRCHpu_hYMOmJXKO8,3227
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=k0PDvqNKn7sFYIgajWykOTgFztlu5_1bc-xfQQh8bKA,7589
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.6.6.dist-info/LICENSE,sha256=sVQBhyoglGJUu65-BP3iR6ujORI6YgEU2Qm-V4fGlOA,1485
124
- pyfemtet-0.6.6.dist-info/METADATA,sha256=4fvkbBciIFpFpL6UBZ7EQ62imk4AdT9AwbuPGXTbktE,3371
125
- pyfemtet-0.6.6.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
126
- pyfemtet-0.6.6.dist-info/entry_points.txt,sha256=ZfYqRaoiPtuWqFi2_msccyrVF0LurMn-IHlYamAegZo,104
127
- pyfemtet-0.6.6.dist-info/RECORD,,
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,,