pyfemtet 0.4.25__py3-none-any.whl → 0.5.1__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/message/locales/ja/LC_MESSAGES/messages.mo +0 -0
- pyfemtet/message/locales/ja/LC_MESSAGES/messages.po +114 -62
- pyfemtet/message/locales/messages.pot +114 -62
- pyfemtet/message/messages.py +6 -2
- pyfemtet/opt/__init__.py +2 -2
- pyfemtet/opt/_femopt.py +27 -46
- pyfemtet/opt/_femopt_core.py +50 -33
- pyfemtet/opt/_test_utils/__init__.py +0 -0
- pyfemtet/opt/_test_utils/control_femtet.py +45 -0
- pyfemtet/opt/_test_utils/hyper_sphere.py +24 -0
- pyfemtet/opt/_test_utils/record_history.py +72 -0
- pyfemtet/opt/interface/_femtet.py +39 -1
- pyfemtet/opt/optimizer/__init__.py +12 -0
- pyfemtet/opt/{opt → optimizer}/_base.py +30 -9
- pyfemtet/opt/{opt → optimizer}/_optuna.py +14 -33
- pyfemtet/opt/optimizer/_optuna_botorchsampler_parameter_constraint_helper.py +325 -0
- pyfemtet/opt/{opt → optimizer}/_scipy.py +10 -6
- pyfemtet/opt/{opt → optimizer}/_scipy_scalar.py +24 -12
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +97 -0
- pyfemtet/opt/samples/femprj_sample/constrained_pipe_test_result.reccsv +13 -0
- pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gal_ex58_parametric_test_result.reccsv +1 -1
- pyfemtet/opt/{femprj_sample → samples/femprj_sample}/her_ex40_parametric.py +10 -8
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric_test_result.reccsv +18 -0
- pyfemtet/opt/samples/femprj_sample_jp/constrained_pipe_jp.py +93 -0
- pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/her_ex40_parametric_jp.py +10 -8
- pyfemtet/opt/visualization/complex_components/main_figure_creator.py +69 -0
- pyfemtet/opt/visualization/complex_components/main_graph.py +299 -14
- pyfemtet/opt/visualization/process_monitor/pages.py +1 -1
- pyfemtet/opt/visualization/result_viewer/application.py +1 -1
- pyfemtet/opt/visualization/result_viewer/pages.py +9 -9
- {pyfemtet-0.4.25.dist-info → pyfemtet-0.5.1.dist-info}/METADATA +1 -1
- pyfemtet-0.5.1.dist-info/RECORD +115 -0
- pyfemtet/_test_util.py +0 -135
- pyfemtet/opt/femprj_sample/ParametricIF - True.femprj +0 -0
- pyfemtet/opt/femprj_sample/her_ex40_parametric_test_result.reccsv +0 -18
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
- pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
- pyfemtet/opt/opt/__init__.py +0 -12
- pyfemtet/opt/opt/_optuna_botorch_helper.py +0 -209
- pyfemtet-0.4.25.dist-info/RECORD +0 -140
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/.gitignore +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/ParametricIF.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/ParametricIF.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/ParametricIF_test_result.reccsv +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX.prt +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX_test_result.reccsv +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW.SLDPRT +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW_test_result.reccsv +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gal_ex58_parametric.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gal_ex58_parametric.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gau_ex08_parametric.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gau_ex08_parametric.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gau_ex08_parametric_test_result.reccsv +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/her_ex40_parametric.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric_parallel.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric_test_result.reccsv +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric.femprj +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric_parallel.py +0 -0
- /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric_test_result.reccsv +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/ParametricIF_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/ParametricIF_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_NX_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_NX_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_SW_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_SW_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gal_ex58_parametric_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gal_ex58_parametric_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gau_ex08_parametric_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gau_ex08_parametric_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/her_ex40_parametric_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/paswat_ex1_parametric_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/paswat_ex1_parametric_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/paswat_ex1_parametric_parallel_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/wat_ex14_parametric_jp.femprj +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/wat_ex14_parametric_jp.py +0 -0
- /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/wat_ex14_parametric_parallel_jp.py +0 -0
- {pyfemtet-0.4.25.dist-info → pyfemtet-0.5.1.dist-info}/LICENSE +0 -0
- {pyfemtet-0.4.25.dist-info → pyfemtet-0.5.1.dist-info}/WHEEL +0 -0
- {pyfemtet-0.4.25.dist-info → pyfemtet-0.5.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from time import sleep
|
|
2
|
+
from subprocess import run
|
|
3
|
+
from multiprocessing import Process
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
from win32com.client import Dispatch
|
|
6
|
+
from femtetutils import util
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("test")
|
|
12
|
+
logger.setLevel(logging.DEBUG)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _open_femprj(femprj_path):
|
|
16
|
+
Femtet = Dispatch("FemtetMacro.Femtet")
|
|
17
|
+
for _ in tqdm(range(5), "Wait to complete Dispatch before opening femprj..."):
|
|
18
|
+
sleep(1)
|
|
19
|
+
Femtet.LoadProject(femprj_path, True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def launch_femtet(femprj_path):
|
|
23
|
+
# launch Femtet externally
|
|
24
|
+
util.execute_femtet()
|
|
25
|
+
pid = util.get_last_executed_femtet_process_id()
|
|
26
|
+
for _ in tqdm(range(8), "Wait to complete Femtet launching."):
|
|
27
|
+
sleep(1)
|
|
28
|
+
|
|
29
|
+
# open femprj in a different process
|
|
30
|
+
# to release Femtet for sample program
|
|
31
|
+
if femprj_path:
|
|
32
|
+
p = Process(
|
|
33
|
+
target=_open_femprj,
|
|
34
|
+
args=(femprj_path,),
|
|
35
|
+
)
|
|
36
|
+
p.start()
|
|
37
|
+
p.join()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def taskkill_femtet():
|
|
41
|
+
for _ in tqdm(range(3), "Wait before taskkill Femtet"):
|
|
42
|
+
sleep(1)
|
|
43
|
+
run(["taskkill", "/f", "/im", "Femtet.exe"])
|
|
44
|
+
for _ in tqdm(range(3), "Wait after taskkill Femtet"):
|
|
45
|
+
sleep(1)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from numpy import sin, cos
|
|
3
|
+
from pyfemtet.opt import AbstractOptimizer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class HyperSphere(object):
|
|
7
|
+
|
|
8
|
+
def __init__(self, N):
|
|
9
|
+
self.N = N
|
|
10
|
+
self._x = np.zeros(self.N, dtype=float)
|
|
11
|
+
|
|
12
|
+
def calc(self, r, *angles):
|
|
13
|
+
_x = []
|
|
14
|
+
for i in range(self.N - 1):
|
|
15
|
+
__x = r * np.prod([sin(angles[j]) for j in range(i)])
|
|
16
|
+
__x = __x * cos(angles[i])
|
|
17
|
+
_x.append(__x)
|
|
18
|
+
_x.append(r * np.prod([sin(angles[j]) for j in range(self.N - 1)]))
|
|
19
|
+
self._x = np.array(_x)
|
|
20
|
+
|
|
21
|
+
def x(self, opt: AbstractOptimizer, index: int):
|
|
22
|
+
r, *angles = opt.get_parameter("values")
|
|
23
|
+
self.calc(r, *angles)
|
|
24
|
+
return self._x[index]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import csv
|
|
3
|
+
from shutil import copy
|
|
4
|
+
from glob import glob
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
from pyfemtet.opt import FEMOpt
|
|
10
|
+
from pyfemtet.message import encoding as ENCODING
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def find_latest_csv(dir_path=None):
|
|
14
|
+
if dir_path is None:
|
|
15
|
+
dir_path = ""
|
|
16
|
+
target = os.path.join(dir_path, "*.csv")
|
|
17
|
+
files = [(f, os.path.getmtime(f)) for f in glob(target)]
|
|
18
|
+
out = sorted(files, key=lambda files: files[1])[-1]
|
|
19
|
+
return os.path.abspath(out[0])
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def py_to_reccsv(py_path, suffix=""):
|
|
23
|
+
dst_csv_path = py_path + suffix
|
|
24
|
+
dst_csv_path = dst_csv_path.replace(f".py{suffix}", f"{suffix}.reccsv")
|
|
25
|
+
return dst_csv_path
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def record_result(src: FEMOpt or str, py_path, suffix=""):
|
|
29
|
+
"""Record the result csv for `is_equal_result`."""
|
|
30
|
+
|
|
31
|
+
if isinstance(src, FEMOpt): # get df directory
|
|
32
|
+
src_csv_path = src.history_path
|
|
33
|
+
else:
|
|
34
|
+
src_csv_path = os.path.abspath(src)
|
|
35
|
+
|
|
36
|
+
dst_csv_path = py_to_reccsv(py_path, suffix)
|
|
37
|
+
copy(src_csv_path, dst_csv_path)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _get_obj_from_csv(csv_path, encoding=ENCODING):
|
|
41
|
+
df = pd.read_csv(csv_path, encoding=encoding, header=2)
|
|
42
|
+
columns = df.columns
|
|
43
|
+
with open(csv_path, mode="r", encoding=encoding, newline="\n") as f:
|
|
44
|
+
reader = csv.reader(f, delimiter=",")
|
|
45
|
+
meta = reader.__next__()
|
|
46
|
+
obj_indices = np.where(np.array(meta) == "obj")[0]
|
|
47
|
+
out = df.iloc[:, obj_indices]
|
|
48
|
+
return out, columns
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def is_equal_result(ref_path, dif_path, log_path):
|
|
52
|
+
"""Check the equality of two result csv files."""
|
|
53
|
+
ref_df, ref_columns = _get_obj_from_csv(ref_path)
|
|
54
|
+
dif_df, dif_columns = _get_obj_from_csv(dif_path)
|
|
55
|
+
|
|
56
|
+
with open(log_path, "a", newline="\n", encoding=ENCODING) as f:
|
|
57
|
+
f.write("\n\n===== 結果の分析 =====\n\n")
|
|
58
|
+
f.write(f" \tref\tdif\n")
|
|
59
|
+
f.write(f"---------------------\n")
|
|
60
|
+
f.write(f"len(col)\t{len(ref_columns)}\t{len(dif_columns)}\n")
|
|
61
|
+
f.write(f"len(df) \t{len(ref_df)}\t{len(dif_df)}\n")
|
|
62
|
+
try:
|
|
63
|
+
difference = (
|
|
64
|
+
np.abs(ref_df.values - dif_df.values) / np.abs(dif_df.values)
|
|
65
|
+
).mean()
|
|
66
|
+
f.write(f"diff \t{int(difference*100)}%\n")
|
|
67
|
+
except Exception:
|
|
68
|
+
f.write(f"diff \tcannot calc\n")
|
|
69
|
+
|
|
70
|
+
assert len(ref_columns) == len(dif_columns), "結果 csv の column 数が異なります。"
|
|
71
|
+
assert len(ref_df) == len(dif_df), "結果 csv の row 数が異なります。"
|
|
72
|
+
assert difference <= 0.05, "前回の結果との平均差異が 5% を超えています。"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from typing import Optional, List
|
|
1
|
+
from typing import Optional, List, Final
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
from time import sleep, time
|
|
6
|
+
import winreg
|
|
6
7
|
|
|
7
8
|
import pandas as pd
|
|
8
9
|
import psutil
|
|
@@ -101,6 +102,8 @@ class FemtetInterface(FEMInterface):
|
|
|
101
102
|
self.max_api_retry = 3
|
|
102
103
|
self.strictly_pid_specify = strictly_pid_specify
|
|
103
104
|
self.parametric_output_indexes_use_as_objective = parametric_output_indexes_use_as_objective
|
|
105
|
+
self._original_autosave_enabled = get_autosave_enabled()
|
|
106
|
+
set_autosave_enabled(False)
|
|
104
107
|
|
|
105
108
|
# dask サブプロセスのときは femprj を更新し connect_method を new にする
|
|
106
109
|
try:
|
|
@@ -142,6 +145,7 @@ class FemtetInterface(FEMInterface):
|
|
|
142
145
|
)
|
|
143
146
|
|
|
144
147
|
def __del__(self):
|
|
148
|
+
set_autosave_enabled(self._original_autosave_enabled)
|
|
145
149
|
if self.quit_when_destruct:
|
|
146
150
|
self.quit()
|
|
147
151
|
# CoUninitialize() # Win32 exception occurred releasing IUnknown at 0x0000022427692748
|
|
@@ -854,3 +858,37 @@ class _UnPicklableNoFEM(FemtetInterface):
|
|
|
854
858
|
pdt_path = os.path.join(here, f'trial{trial}.pdt')
|
|
855
859
|
return pdt_path
|
|
856
860
|
|
|
861
|
+
|
|
862
|
+
# レジストリのパスと値の名前
|
|
863
|
+
REGISTRY_PATH: Final[str] = r"SOFTWARE\Murata Software\Femtet2014\Femtet"
|
|
864
|
+
VALUE_NAME: Final[str] = "AutoSave"
|
|
865
|
+
|
|
866
|
+
def get_autosave_enabled() -> bool:
|
|
867
|
+
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, REGISTRY_PATH) as key:
|
|
868
|
+
value, regtype = winreg.QueryValueEx(key, VALUE_NAME)
|
|
869
|
+
if regtype == winreg.REG_DWORD:
|
|
870
|
+
return bool(value)
|
|
871
|
+
else:
|
|
872
|
+
raise ValueError("Unexpected registry value type.")
|
|
873
|
+
|
|
874
|
+
def set_autosave_enabled(enable: bool) -> None:
|
|
875
|
+
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, REGISTRY_PATH, 0, winreg.KEY_SET_VALUE) as key:
|
|
876
|
+
winreg.SetValueEx(key, VALUE_NAME, 0, winreg.REG_DWORD, int(enable))
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
def _test_autosave_setting():
|
|
880
|
+
|
|
881
|
+
# 使用例
|
|
882
|
+
current_setting = get_autosave_enabled()
|
|
883
|
+
print(f"Current AutoSave setting is {'enabled' if current_setting else 'disabled'}.")
|
|
884
|
+
|
|
885
|
+
# 設定を変更する例
|
|
886
|
+
new_setting = not current_setting
|
|
887
|
+
set_autosave_enabled(new_setting)
|
|
888
|
+
print(f"AutoSave setting has been {'enabled' if new_setting else 'disabled'}.")
|
|
889
|
+
|
|
890
|
+
# 再度設定を確認する
|
|
891
|
+
after_setting = get_autosave_enabled()
|
|
892
|
+
print(f"Current AutoSave setting is {'enabled' if after_setting else 'disabled'}.")
|
|
893
|
+
|
|
894
|
+
assert new_setting == after_setting, "レジストリ編集に失敗しました。"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from pyfemtet.opt.optimizer._base import AbstractOptimizer, logger, OptimizationMethodChecker
|
|
2
|
+
from pyfemtet.opt.optimizer._optuna import OptunaOptimizer
|
|
3
|
+
from pyfemtet.opt.optimizer._scipy import ScipyOptimizer
|
|
4
|
+
from pyfemtet.opt.optimizer._scipy_scalar import ScipyScalarOptimizer
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
'ScipyScalarOptimizer',
|
|
8
|
+
'ScipyOptimizer',
|
|
9
|
+
'OptunaOptimizer',
|
|
10
|
+
'AbstractOptimizer',
|
|
11
|
+
'logger',
|
|
12
|
+
]
|
|
@@ -12,7 +12,7 @@ import pandas as pd
|
|
|
12
12
|
|
|
13
13
|
# pyfemtet relative
|
|
14
14
|
from pyfemtet.opt.interface import FemtetInterface
|
|
15
|
-
from pyfemtet.opt._femopt_core import OptimizationStatus
|
|
15
|
+
from pyfemtet.opt._femopt_core import OptimizationStatus, Objective, Constraint
|
|
16
16
|
from pyfemtet.message import Msg
|
|
17
17
|
from pyfemtet.opt.parameter import ExpressionEvaluator
|
|
18
18
|
|
|
@@ -135,10 +135,9 @@ class AbstractOptimizer(ABC):
|
|
|
135
135
|
self.fem = None
|
|
136
136
|
self.fem_class = None
|
|
137
137
|
self.fem_kwargs = dict()
|
|
138
|
-
self.parameters: pd.DataFrame = pd.DataFrame()
|
|
139
138
|
self.variables: ExpressionEvaluator = ExpressionEvaluator()
|
|
140
|
-
self.objectives: dict = dict()
|
|
141
|
-
self.constraints: dict = dict()
|
|
139
|
+
self.objectives: dict[str, Constraint] = dict()
|
|
140
|
+
self.constraints: dict[str, Constraint] = dict()
|
|
142
141
|
self.entire_status = None # actor
|
|
143
142
|
self.history = None # actor
|
|
144
143
|
self.worker_status = None # actor
|
|
@@ -155,10 +154,11 @@ class AbstractOptimizer(ABC):
|
|
|
155
154
|
"""Get x, update fem analysis, return objectives (and constraints)."""
|
|
156
155
|
# interruption の実装は具象クラスに任せる
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
157
|
+
if isinstance(x, np.float64):
|
|
158
|
+
x = np.array([x])
|
|
159
|
+
|
|
160
|
+
# Optimizer の x の更新
|
|
161
|
+
self.set_parameter_values(x)
|
|
162
162
|
|
|
163
163
|
logger.info('---------------------')
|
|
164
164
|
logger.info(f'input: {x}')
|
|
@@ -237,7 +237,28 @@ class AbstractOptimizer(ABC):
|
|
|
237
237
|
ValueError: If an invalid format is provided.
|
|
238
238
|
|
|
239
239
|
"""
|
|
240
|
-
return self.variables.get_variables(format=format)
|
|
240
|
+
return self.variables.get_variables(format=format, filter_parameter=True)
|
|
241
|
+
|
|
242
|
+
def set_parameter(self, params: dict) -> None:
|
|
243
|
+
"""Update parameter.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
params (dict): Key is the name of parameter and the value is the value of it. The partial set is available.
|
|
247
|
+
|
|
248
|
+
"""
|
|
249
|
+
for name, value in params.items():
|
|
250
|
+
self.variables.variables[name].value = value
|
|
251
|
+
self.variables.evaluate()
|
|
252
|
+
|
|
253
|
+
def set_parameter_values(self, values: np.ndarray) -> None:
|
|
254
|
+
"""Update parameter with values.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
values (np.ndarray): Values of all parameters.
|
|
258
|
+
"""
|
|
259
|
+
prm_names = self.variables.get_parameter_names()
|
|
260
|
+
assert len(values) == len(prm_names)
|
|
261
|
+
self.set_parameter({k: v for k, v in zip(prm_names, values)})
|
|
241
262
|
|
|
242
263
|
def _check_interruption(self):
|
|
243
264
|
""""""
|
|
@@ -11,8 +11,8 @@ from optuna.trial import TrialState
|
|
|
11
11
|
from optuna.study import MaxTrialsCallback
|
|
12
12
|
|
|
13
13
|
# pyfemtet relative
|
|
14
|
-
from pyfemtet.opt._femopt_core import OptimizationStatus, generate_lhs
|
|
15
|
-
from pyfemtet.opt.
|
|
14
|
+
from pyfemtet.opt._femopt_core import OptimizationStatus, generate_lhs, Constraint
|
|
15
|
+
from pyfemtet.opt.optimizer import AbstractOptimizer, logger, OptimizationMethodChecker
|
|
16
16
|
from pyfemtet.core import MeshError, ModelError, SolveError
|
|
17
17
|
from pyfemtet.message import Msg
|
|
18
18
|
|
|
@@ -54,7 +54,7 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
54
54
|
self.additional_initial_parameter = []
|
|
55
55
|
self.additional_initial_methods = add_init_method if hasattr(add_init_method, '__iter__') else [add_init_method]
|
|
56
56
|
self.method_checker = OptunaMethodChecker(self)
|
|
57
|
-
self.
|
|
57
|
+
self._do_monkey_patch = False
|
|
58
58
|
|
|
59
59
|
def _objective(self, trial):
|
|
60
60
|
|
|
@@ -114,14 +114,14 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
114
114
|
|
|
115
115
|
# 拘束 attr の更新
|
|
116
116
|
if len(self.constraints) > 0:
|
|
117
|
-
_c = [] #
|
|
117
|
+
_c = [] # <= 0 is feasible
|
|
118
118
|
for (name, cns), c_value in zip(self.constraints.items(), c):
|
|
119
119
|
lb, ub = cns.lb, cns.ub
|
|
120
120
|
if lb is not None: # fun >= lb <=> lb - fun <= 0
|
|
121
121
|
_c.append(lb - c_value)
|
|
122
122
|
if ub is not None: # ub >= fun <=> fun - ub <= 0
|
|
123
123
|
_c.append(c_value - ub)
|
|
124
|
-
trial.set_user_attr('
|
|
124
|
+
trial.set_user_attr('constraints', _c)
|
|
125
125
|
|
|
126
126
|
# 中断の確認 (解析中に interrupt されている場合対策)
|
|
127
127
|
if self.entire_status.get() == OptimizationStatus.INTERRUPTING:
|
|
@@ -134,8 +134,8 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
134
134
|
|
|
135
135
|
def _constraint(self, trial):
|
|
136
136
|
# if break trial without weak constraint calculation, return 1 (as infeasible).
|
|
137
|
-
if '
|
|
138
|
-
return trial.user_attrs['
|
|
137
|
+
if 'constraints' in trial.user_attrs.keys():
|
|
138
|
+
return trial.user_attrs['constraints']
|
|
139
139
|
else:
|
|
140
140
|
_c = []
|
|
141
141
|
for name, cns in self.constraints.items():
|
|
@@ -203,7 +203,7 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
203
203
|
if 'LHS' in self.additional_initial_methods:
|
|
204
204
|
names = []
|
|
205
205
|
bounds = []
|
|
206
|
-
for i, row in self.
|
|
206
|
+
for i, row in self.get_parameter('df').iterrows():
|
|
207
207
|
names.append(row['name'])
|
|
208
208
|
lb = row['lower_bound']
|
|
209
209
|
ub = row['upper_bound']
|
|
@@ -275,20 +275,16 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
275
275
|
)
|
|
276
276
|
|
|
277
277
|
# monkey patch
|
|
278
|
-
if
|
|
278
|
+
if self._do_monkey_patch:
|
|
279
279
|
assert isinstance(sampler, optuna.integration.BoTorchSampler), Msg.ERR_PARAMETER_CONSTRAINT_ONLY_BOTORCH
|
|
280
280
|
|
|
281
|
-
from pyfemtet.opt.
|
|
282
|
-
|
|
281
|
+
from pyfemtet.opt.optimizer._optuna_botorchsampler_parameter_constraint_helper import do_patch
|
|
282
|
+
|
|
283
|
+
do_patch(
|
|
283
284
|
study,
|
|
284
|
-
self,
|
|
285
|
+
self.constraints,
|
|
286
|
+
self
|
|
285
287
|
)
|
|
286
|
-
for p_cns in self.parameter_constraints:
|
|
287
|
-
fun = p_cns['fun']
|
|
288
|
-
prm_args = p_cns['prm_args']
|
|
289
|
-
kwargs = p_cns['kwargs']
|
|
290
|
-
mp.add_nonlinear_constraint(fun, prm_args, kwargs)
|
|
291
|
-
mp.do_monkey_patch()
|
|
292
288
|
|
|
293
289
|
# run
|
|
294
290
|
study.optimize(
|
|
@@ -296,18 +292,3 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
296
292
|
timeout=self.timeout,
|
|
297
293
|
callbacks=self.optimize_callbacks,
|
|
298
294
|
)
|
|
299
|
-
|
|
300
|
-
def add_parameter_constraints(
|
|
301
|
-
self,
|
|
302
|
-
fun,
|
|
303
|
-
prm_args=None,
|
|
304
|
-
kwargs=None
|
|
305
|
-
):
|
|
306
|
-
kwargs = kwargs if kwargs is not None else {}
|
|
307
|
-
self.parameter_constraints.append(
|
|
308
|
-
dict(
|
|
309
|
-
fun=fun,
|
|
310
|
-
prm_args=prm_args,
|
|
311
|
-
kwargs=kwargs,
|
|
312
|
-
)
|
|
313
|
-
)
|