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.

Files changed (117) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo +0 -0
  3. pyfemtet/message/locales/ja/LC_MESSAGES/messages.po +114 -62
  4. pyfemtet/message/locales/messages.pot +114 -62
  5. pyfemtet/message/messages.py +6 -2
  6. pyfemtet/opt/__init__.py +2 -2
  7. pyfemtet/opt/_femopt.py +27 -46
  8. pyfemtet/opt/_femopt_core.py +50 -33
  9. pyfemtet/opt/_test_utils/__init__.py +0 -0
  10. pyfemtet/opt/_test_utils/control_femtet.py +45 -0
  11. pyfemtet/opt/_test_utils/hyper_sphere.py +24 -0
  12. pyfemtet/opt/_test_utils/record_history.py +72 -0
  13. pyfemtet/opt/interface/_femtet.py +39 -1
  14. pyfemtet/opt/optimizer/__init__.py +12 -0
  15. pyfemtet/opt/{opt → optimizer}/_base.py +30 -9
  16. pyfemtet/opt/{opt → optimizer}/_optuna.py +14 -33
  17. pyfemtet/opt/optimizer/_optuna_botorchsampler_parameter_constraint_helper.py +325 -0
  18. pyfemtet/opt/{opt → optimizer}/_scipy.py +10 -6
  19. pyfemtet/opt/{opt → optimizer}/_scipy_scalar.py +24 -12
  20. pyfemtet/opt/samples/femprj_sample/constrained_pipe.femprj +0 -0
  21. pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +97 -0
  22. pyfemtet/opt/samples/femprj_sample/constrained_pipe_test_result.reccsv +13 -0
  23. pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gal_ex58_parametric_test_result.reccsv +1 -1
  24. pyfemtet/opt/{femprj_sample → samples/femprj_sample}/her_ex40_parametric.py +10 -8
  25. pyfemtet/opt/samples/femprj_sample/her_ex40_parametric_test_result.reccsv +18 -0
  26. pyfemtet/opt/samples/femprj_sample_jp/constrained_pipe_jp.py +93 -0
  27. pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/her_ex40_parametric_jp.py +10 -8
  28. pyfemtet/opt/visualization/complex_components/main_figure_creator.py +69 -0
  29. pyfemtet/opt/visualization/complex_components/main_graph.py +299 -14
  30. pyfemtet/opt/visualization/process_monitor/pages.py +1 -1
  31. pyfemtet/opt/visualization/result_viewer/application.py +1 -1
  32. pyfemtet/opt/visualization/result_viewer/pages.py +9 -9
  33. {pyfemtet-0.4.25.dist-info → pyfemtet-0.5.1.dist-info}/METADATA +1 -1
  34. pyfemtet-0.5.1.dist-info/RECORD +115 -0
  35. pyfemtet/_test_util.py +0 -135
  36. pyfemtet/opt/femprj_sample/ParametricIF - True.femprj +0 -0
  37. pyfemtet/opt/femprj_sample/her_ex40_parametric_test_result.reccsv +0 -18
  38. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  39. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  40. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
  41. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  42. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
  43. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  44. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  45. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  46. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  47. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  48. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  49. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  50. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  51. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  52. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  53. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  54. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
  55. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  56. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
  57. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  58. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
  59. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  60. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
  61. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  62. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
  63. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  64. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
  65. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  66. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
  67. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  68. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
  69. pyfemtet/opt/opt/__init__.py +0 -12
  70. pyfemtet/opt/opt/_optuna_botorch_helper.py +0 -209
  71. pyfemtet-0.4.25.dist-info/RECORD +0 -140
  72. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/.gitignore +0 -0
  73. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/ParametricIF.femprj +0 -0
  74. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/ParametricIF.py +0 -0
  75. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/ParametricIF_test_result.reccsv +0 -0
  76. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX.femprj +0 -0
  77. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX.prt +0 -0
  78. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX.py +0 -0
  79. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_NX_test_result.reccsv +0 -0
  80. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW.SLDPRT +0 -0
  81. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW.femprj +0 -0
  82. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW.py +0 -0
  83. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/cad_ex01_SW_test_result.reccsv +0 -0
  84. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gal_ex58_parametric.femprj +0 -0
  85. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gal_ex58_parametric.py +0 -0
  86. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gau_ex08_parametric.femprj +0 -0
  87. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gau_ex08_parametric.py +0 -0
  88. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/gau_ex08_parametric_test_result.reccsv +0 -0
  89. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/her_ex40_parametric.femprj +0 -0
  90. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric.femprj +0 -0
  91. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric.py +0 -0
  92. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric_parallel.py +0 -0
  93. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/paswat_ex1_parametric_test_result.reccsv +0 -0
  94. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric.femprj +0 -0
  95. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric.py +0 -0
  96. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric_parallel.py +0 -0
  97. /pyfemtet/opt/{femprj_sample → samples/femprj_sample}/wat_ex14_parametric_test_result.reccsv +0 -0
  98. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/ParametricIF_jp.femprj +0 -0
  99. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/ParametricIF_jp.py +0 -0
  100. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_NX_jp.femprj +0 -0
  101. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_NX_jp.py +0 -0
  102. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_SW_jp.femprj +0 -0
  103. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/cad_ex01_SW_jp.py +0 -0
  104. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gal_ex58_parametric_jp.femprj +0 -0
  105. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gal_ex58_parametric_jp.py +0 -0
  106. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gau_ex08_parametric_jp.femprj +0 -0
  107. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/gau_ex08_parametric_jp.py +0 -0
  108. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/her_ex40_parametric_jp.femprj +0 -0
  109. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/paswat_ex1_parametric_jp.femprj +0 -0
  110. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/paswat_ex1_parametric_jp.py +0 -0
  111. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/paswat_ex1_parametric_parallel_jp.py +0 -0
  112. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/wat_ex14_parametric_jp.femprj +0 -0
  113. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/wat_ex14_parametric_jp.py +0 -0
  114. /pyfemtet/opt/{femprj_sample_jp → samples/femprj_sample_jp}/wat_ex14_parametric_parallel_jp.py +0 -0
  115. {pyfemtet-0.4.25.dist-info → pyfemtet-0.5.1.dist-info}/LICENSE +0 -0
  116. {pyfemtet-0.4.25.dist-info → pyfemtet-0.5.1.dist-info}/WHEEL +0 -0
  117. {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
- # x の更新
159
- prm_names = self.variables.get_parameter_names()
160
- for name, value in zip(prm_names, x):
161
- self.variables.variables[name].value = value
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.opt import AbstractOptimizer, logger, OptimizationMethodChecker
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.parameter_constraints = []
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 = [] # 非正なら OK
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('constraint', _c)
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 'constraint' in trial.user_attrs.keys():
138
- return trial.user_attrs['constraint']
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.parameters.iterrows():
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 len(self.parameter_constraints) > 0:
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.opt._optuna_botorch_helper import OptunaBotorchWithParameterConstraintMonkeyPatch
282
- mp = OptunaBotorchWithParameterConstraintMonkeyPatch(
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
- )