pyfemtet 0.5.2__py3-none-any.whl → 0.5.4__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 (54) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/{message → _message}/locales/ja/LC_MESSAGES/messages.po +88 -76
  3. pyfemtet/{message → _message}/locales/messages.pot +88 -76
  4. pyfemtet/{message → _message}/messages.py +1 -1
  5. pyfemtet/_warning.py +23 -0
  6. pyfemtet/dispatch_extensions/__init__.py +12 -0
  7. pyfemtet/{dispatch_extensions.py → dispatch_extensions/_impl.py} +45 -43
  8. pyfemtet/logger/__init__.py +3 -0
  9. pyfemtet/{logger.py → logger/_impl.py} +12 -6
  10. pyfemtet/opt/_femopt.py +236 -58
  11. pyfemtet/opt/_femopt_core.py +21 -8
  12. pyfemtet/opt/_test_utils/record_history.py +1 -1
  13. pyfemtet/opt/interface/__init__.py +0 -1
  14. pyfemtet/opt/interface/_base.py +3 -3
  15. pyfemtet/opt/interface/_femtet.py +101 -55
  16. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +35 -12
  17. pyfemtet/opt/interface/_femtet_with_sldworks.py +22 -2
  18. pyfemtet/opt/optimizer/_base.py +76 -42
  19. pyfemtet/opt/optimizer/_optuna.py +33 -1
  20. pyfemtet/opt/optimizer/_optuna_botorchsampler_parameter_constraint_helper.py +1 -2
  21. pyfemtet/opt/optimizer/_scipy.py +20 -5
  22. pyfemtet/opt/optimizer/_scipy_scalar.py +20 -5
  23. pyfemtet/opt/prediction/{base.py → _base.py} +3 -2
  24. pyfemtet/opt/prediction/single_task_gp.py +10 -5
  25. pyfemtet/opt/visualization/{base.py → _base.py} +1 -1
  26. pyfemtet/opt/visualization/{complex_components → _complex_components}/alert_region.py +2 -2
  27. pyfemtet/opt/visualization/{complex_components → _complex_components}/control_femtet.py +3 -3
  28. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_figure_creator.py +1 -1
  29. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_graph.py +5 -5
  30. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph.py +5 -5
  31. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph_creator.py +2 -2
  32. pyfemtet/opt/visualization/_create_wrapped_components.py +2 -2
  33. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/application.py +3 -3
  34. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/pages.py +10 -10
  35. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dbc.py +1 -1
  36. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dcc.py +1 -1
  37. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/html.py +1 -1
  38. pyfemtet/opt/visualization/result_viewer/application.py +4 -4
  39. pyfemtet/opt/visualization/result_viewer/pages.py +9 -9
  40. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/METADATA +2 -2
  41. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/RECORD +53 -51
  42. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/WHEEL +1 -1
  43. pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo +0 -0
  44. /pyfemtet/{message → _message}/1. make_pot.bat +0 -0
  45. /pyfemtet/{message → _message}/2. make_mo.bat +0 -0
  46. /pyfemtet/{message → _message}/__init__.py +0 -0
  47. /pyfemtet/{message → _message}/babel.cfg +0 -0
  48. /pyfemtet/opt/{parameter.py → optimizer/parameter.py} +0 -0
  49. /pyfemtet/opt/visualization/{complex_components → _complex_components}/__init__.py +0 -0
  50. /pyfemtet/opt/visualization/{process_monitor → _process_monitor}/__init__.py +0 -0
  51. /pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/__init__.py +0 -0
  52. /pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/str_enum.py +0 -0
  53. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/LICENSE +0 -0
  54. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/entry_points.txt +0 -0
@@ -34,47 +34,75 @@ from pyfemtet.dispatch_extensions import (
34
34
  DispatchExtensionException,
35
35
  )
36
36
  from pyfemtet.opt.interface import FEMInterface, logger
37
- from pyfemtet.message import Msg
37
+ from pyfemtet._message import Msg
38
38
 
39
39
 
40
- def post_activate_message(hwnd):
40
+ def _post_activate_message(hwnd):
41
41
  win32gui.PostMessage(hwnd, win32con.WM_ACTIVATE, win32con.WA_ACTIVE, 0)
42
42
 
43
43
 
44
44
  class FemtetInterface(FEMInterface):
45
- """Concrete class for the interface with Femtet.
45
+ """Control Femtet from optimizer.
46
46
 
47
- Args:
48
- femprj_path (str or None, optional): The path to the .femprj file. Defaults to None.
49
- model_name (str or None, optional): The name of the analysis model. Defaults to None.
50
- connect_method (str, optional): The connection method to use. Can be 'new', 'existing', or 'auto'. Defaults to 'auto'.
51
- strictly_pid_specify (bool, optional): If True and connect_method=='new', search launched Femtet process strictly based on its process id.
52
- allow_without_project (bool, optional): Allow to launch Femtet with no project file. Default to False.
53
- open_result_with_gui (bool, optional): Open analysis result with Femtet GUI. Default to True.
54
- parametric_output_indexes_use_as_objective (dict, optional): Parametric output indexes and their directions which will be used as objective functions. Parametric output should be set on Femtet parametric analysis dialog. Note that output 'No.' in dialog is starts with 1, but this 'index' is starts with 0. The key is the 'index', the value is direction ('maximize', 'minimize' or float). Default to None.
55
-
56
- Warning:
57
- Even if you specify ``strictly_pid_specify=True`` on the constructor,
58
- **the connection behavior is like** ``strictly_pid_specify=False`` **in parallel processing**
59
- because of its large overhead.
60
- So you should close all Femtet processes before running FEMOpt.optimize()
61
- if ``n_parallel`` >= 2.
62
-
63
- Tip:
64
- If you search for information about the method to connect python and Femtet, see :func:`connect_femtet`.
47
+ Args:
48
+ femprj_path (str, optional):
49
+ The path to the project file.
50
+ If not specified, get it from connected Femtet.
51
+
52
+ model_name (str, optional):
53
+ The name of the model.
54
+ If not specified, get it from connected Femtet or the
55
+ first model when Femtet open the project file.
56
+
57
+ connect_method (str, optional):
58
+ The connection method.
59
+ Default is 'auto'. Other valid values are 'new' or 'existing'.
60
+
61
+ save_pdt (str, optional):
62
+ The type to save result file.
63
+ Can specify 'all' or None. Default is 'all'.
64
+
65
+ strictly_pid_specify (bool, optional):
66
+ Whether to strictly specify the PID in Femtet connection.
67
+ Default is True.
68
+
69
+ allow_without_project (bool, optional):
70
+ Whether to allow without a project. Default is False.
71
+
72
+ open_result_with_gui (bool, optional):
73
+ Whether to open the result with GUI. Default is True.
74
+
75
+ parametric_output_indexes_use_as_objective (dict[int, str or float], optional):
76
+ A list of parametric output indexes and its direction
77
+ to use as the objective function. If not specified,
78
+ it will be None and no parametric outputs are used
79
+ as objectives.
80
+
81
+ **kwargs: Additional arguments from inherited classes.
82
+
83
+ Warning:
84
+ Even if you specify ``strictly_pid_specify=True`` on the constructor,
85
+ **the connection behavior is like** ``strictly_pid_specify=False`` **in parallel processing**
86
+ because of its large overhead.
87
+ So you should close all Femtet processes before running FEMOpt.optimize()
88
+ if ``n_parallel`` >= 2.
89
+
90
+ Tip:
91
+ If you search for information about the method to
92
+ connect python and Femtet, see :func:`connect_femtet`.
65
93
 
66
94
  """
67
95
 
68
96
  def __init__(
69
97
  self,
70
- femprj_path=None,
71
- model_name=None,
72
- connect_method='auto', # dask worker では __init__ の中で 'new' にするので super() の引数にしない。(しても意味がない)
73
- save_pdt='all', # 'all' or None
74
- strictly_pid_specify=True, # dask worker では True にしたいので super() の引数にしない。
75
- allow_without_project=False, # main でのみ True を許容したいので super() の引数にしない。
76
- open_result_with_gui=True,
77
- parametric_output_indexes_use_as_objective=None,
98
+ femprj_path: str = None,
99
+ model_name: str = None,
100
+ connect_method: str = 'auto', # dask worker では __init__ の中で 'new' にするので super() の引数にしない。(しても意味がない)
101
+ save_pdt: str = 'all', # 'all' or None
102
+ strictly_pid_specify: bool = True, # dask worker では True にしたいので super() の引数にしない。
103
+ allow_without_project: bool = False, # main でのみ True を許容したいので super() の引数にしない。
104
+ open_result_with_gui: bool = True,
105
+ parametric_output_indexes_use_as_objective: dict[int, str or float] = None,
78
106
  **kwargs # 継承されたクラスからの引数
79
107
  ):
80
108
 
@@ -102,8 +130,8 @@ class FemtetInterface(FEMInterface):
102
130
  self.max_api_retry = 3
103
131
  self.strictly_pid_specify = strictly_pid_specify
104
132
  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)
133
+ self._original_autosave_enabled = _get_autosave_enabled()
134
+ _set_autosave_enabled(False)
107
135
 
108
136
  # dask サブプロセスのときは femprj を更新し connect_method を new にする
109
137
  try:
@@ -145,7 +173,7 @@ class FemtetInterface(FEMInterface):
145
173
  )
146
174
 
147
175
  def __del__(self):
148
- set_autosave_enabled(self._original_autosave_enabled)
176
+ _set_autosave_enabled(self._original_autosave_enabled)
149
177
  if self.quit_when_destruct:
150
178
  self.quit()
151
179
  # CoUninitialize() # Win32 exception occurred releasing IUnknown at 0x0000022427692748
@@ -170,12 +198,12 @@ class FemtetInterface(FEMInterface):
170
198
  """Connects to a Femtet process.
171
199
 
172
200
  Args:
173
- connect_method (str, optional): The connection method. Can be 'new', 'existing', or 'auto'. Defaults to 'new'.
201
+ connect_method (str, optional): The connection method. Can be 'new', 'existing', or 'auto'. Defaults to 'auto'.
174
202
  pid (int or None, optional): The process ID of an existing Femtet process and wanted to connect.
175
203
 
176
204
  Note:
177
205
  When connect_method is 'new', starts a new Femtet process and connects to it.
178
- **`pid` will be ignored.**
206
+ `pid` will be ignored.
179
207
 
180
208
  Note:
181
209
  When 'existing', connect to an existing Femtet process.
@@ -338,11 +366,11 @@ class FemtetInterface(FEMInterface):
338
366
  # さらに、プロジェクトツリーが開いていないとアクティブ化イベントも意味がないらしい。
339
367
  if fun.__name__ == 'ReExecute':
340
368
  if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
341
- post_activate_message(self.Femtet.hWnd)
369
+ _post_activate_message(self.Femtet.hWnd)
342
370
  # API を実行
343
371
  returns = fun(*args, **kwargs) # can raise pywintypes.error
344
372
  if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
345
- post_activate_message(self.Femtet.hWnd)
373
+ _post_activate_message(self.Femtet.hWnd)
346
374
  else:
347
375
  returns = fun(*args, **kwargs)
348
376
 
@@ -670,9 +698,25 @@ class FemtetInterface(FEMInterface):
670
698
  self.postprocess(self.Femtet)
671
699
 
672
700
  def preprocess(self, Femtet):
701
+ """A method called just before :func:`solve`.
702
+
703
+ This method is called just before solve.
704
+ By inheriting from the Interface class
705
+ and overriding this method, it is possible
706
+ to perform any desired preprocessing after
707
+ the model update and before solving.
708
+ """
673
709
  pass
674
710
 
675
711
  def postprocess(self, Femtet):
712
+ """A method called just after :func:`solve`.
713
+
714
+ This method is called just after solve.
715
+ By inheriting from the Interface class
716
+ and overriding this method, it is possible
717
+ to perform any desired postprocessing after
718
+ the solve and before evaluating objectives.
719
+ """
676
720
  pass
677
721
 
678
722
  def quit(self, timeout=1, force=True):
@@ -723,9 +767,9 @@ class FemtetInterface(FEMInterface):
723
767
  def _version(self):
724
768
  return _version(Femtet=self.Femtet)
725
769
 
726
- def create_postprocess_args(self):
727
- file_content = self.create_result_file_content()
728
- jpg_content = self.create_jpg_content()
770
+ def _create_postprocess_args(self):
771
+ file_content = self._create_result_file_content()
772
+ jpg_content = self._create_jpg_content()
729
773
 
730
774
  out = dict(
731
775
  original_femprj_path=self.original_femprj_path,
@@ -736,14 +780,14 @@ class FemtetInterface(FEMInterface):
736
780
  return out
737
781
 
738
782
  @staticmethod
739
- def create_pdt_path(femprj_path, model_name, trial):
783
+ def _create_pdt_path(femprj_path, model_name, trial):
740
784
  result_dir = femprj_path.replace('.femprj', '.Results')
741
785
  pdt_path = os.path.join(result_dir, model_name + f'_trial{trial}.pdt')
742
786
  return pdt_path
743
787
 
744
788
  # noinspection PyMethodOverriding
745
789
  @staticmethod
746
- def postprocess_func(
790
+ def _postprocess_func(
747
791
  trial: int,
748
792
  original_femprj_path: str,
749
793
  model_name: str,
@@ -753,7 +797,7 @@ class FemtetInterface(FEMInterface):
753
797
  ):
754
798
  result_dir = original_femprj_path.replace('.femprj', '.Results')
755
799
  if pdt_file_content is not None:
756
- pdt_path = FemtetInterface.create_pdt_path(original_femprj_path, model_name, trial)
800
+ pdt_path = FemtetInterface._create_pdt_path(original_femprj_path, model_name, trial)
757
801
  with open(pdt_path, 'wb') as f:
758
802
  f.write(pdt_file_content)
759
803
 
@@ -762,7 +806,7 @@ class FemtetInterface(FEMInterface):
762
806
  with open(jpg_path, 'wb') as f:
763
807
  f.write(jpg_file_content)
764
808
 
765
- def create_result_file_content(self):
809
+ def _create_result_file_content(self):
766
810
  """Called after solve"""
767
811
  if self.save_pdt == 'all':
768
812
  # save to worker space
@@ -786,7 +830,7 @@ class FemtetInterface(FEMInterface):
786
830
  else:
787
831
  return None
788
832
 
789
- def create_jpg_content(self):
833
+ def _create_jpg_content(self):
790
834
  result_dir = self.femprj_path.replace('.femprj', '.Results')
791
835
  jpg_path = os.path.join(result_dir, self.model_name + '.jpg')
792
836
 
@@ -860,35 +904,37 @@ class _UnPicklableNoFEM(FemtetInterface):
860
904
 
861
905
 
862
906
  # レジストリのパスと値の名前
863
- REGISTRY_PATH: Final[str] = r"SOFTWARE\Murata Software\Femtet2014\Femtet"
864
- VALUE_NAME: Final[str] = "AutoSave"
907
+ _REGISTRY_PATH: Final[str] = r"SOFTWARE\Murata Software\Femtet2014\Femtet"
908
+ _VALUE_NAME: Final[str] = "AutoSave"
865
909
 
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)
910
+
911
+ def _get_autosave_enabled() -> bool:
912
+ with winreg.OpenKey(winreg.HKEY_CURRENT_USER, _REGISTRY_PATH) as key:
913
+ value, regtype = winreg.QueryValueEx(key, _VALUE_NAME)
869
914
  if regtype == winreg.REG_DWORD:
870
915
  return bool(value)
871
916
  else:
872
917
  raise ValueError("Unexpected registry value type.")
873
918
 
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))
919
+
920
+ def _set_autosave_enabled(enable: bool) -> None:
921
+ with winreg.OpenKey(winreg.HKEY_CURRENT_USER, _REGISTRY_PATH, 0, winreg.KEY_SET_VALUE) as key:
922
+ winreg.SetValueEx(key, _VALUE_NAME, 0, winreg.REG_DWORD, int(enable))
877
923
 
878
924
 
879
925
  def _test_autosave_setting():
880
926
 
881
927
  # 使用例
882
- current_setting = get_autosave_enabled()
928
+ current_setting = _get_autosave_enabled()
883
929
  print(f"Current AutoSave setting is {'enabled' if current_setting else 'disabled'}.")
884
930
 
885
931
  # 設定を変更する例
886
932
  new_setting = not current_setting
887
- set_autosave_enabled(new_setting)
933
+ _set_autosave_enabled(new_setting)
888
934
  print(f"AutoSave setting has been {'enabled' if new_setting else 'disabled'}.")
889
935
 
890
936
  # 再度設定を確認する
891
- after_setting = get_autosave_enabled()
937
+ after_setting = _get_autosave_enabled()
892
938
  print(f"Current AutoSave setting is {'enabled' if after_setting else 'disabled'}.")
893
939
 
894
940
  assert new_setting == after_setting, "レジストリ編集に失敗しました。"
@@ -7,23 +7,47 @@ from dask.distributed import get_worker
7
7
 
8
8
  from pyfemtet.core import ModelError
9
9
  from pyfemtet.opt.interface import FemtetInterface, logger
10
- from pyfemtet.message import Msg
10
+ from pyfemtet._message import Msg
11
11
 
12
12
 
13
13
  here, me = os.path.split(__file__)
14
14
 
15
15
 
16
16
  class FemtetWithNXInterface(FemtetInterface):
17
- """Femtet with NX interface class.
17
+ """Control Femtet and NX.
18
18
 
19
- Args:
20
- prt_path: The path to the prt file.
21
- export_curves(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
22
- export_surfaces(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
23
- export_solids(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
24
- export_flattened_assembly(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
19
+ Using this class, you can import CAD files created
20
+ in NX through the Parasolid format into a
21
+ Femtet project. It allows you to pass design
22
+ variables to NX, update the model, and
23
+ perform analysis using the updated model in Femtet.
25
24
 
26
- For details of The other arguments, see ``FemtetInterface``.
25
+ Args:
26
+ prt_path (str):
27
+ The path to .prt file containing the
28
+ CAD data from which the import is made.
29
+
30
+ export_curves(bool or None, optional):
31
+ Defaults to None.
32
+ export_surfaces(bool or None, optional):
33
+ Defaults to None.
34
+ export_solids(bool or None, optional):
35
+ Defaults to None.
36
+ export_flattened_assembly(bool or None, optional):
37
+ Defaults to None.
38
+ **kwargs:
39
+ For other arguments, please refer to the
40
+ :class:`FemtetInterface` class.
41
+
42
+ Notes:
43
+ ```export_*``` arguments sets
44
+ parasolid export setting of NX.
45
+ If None, PyFemtet does not change
46
+ the current setting of NX.
47
+
48
+ It is recommended not to change these values
49
+ from the settings used when exporting the
50
+ Parasolid that was imported into Femtet.
27
51
 
28
52
  """
29
53
 
@@ -84,7 +108,7 @@ class FemtetWithNXInterface(FemtetInterface):
84
108
  )
85
109
  super()._setup_before_parallel(client)
86
110
 
87
- def update_model(self, parameters: 'pd.DataFrame') -> None:
111
+ def update_model(self, parameters: 'pd.DataFrame', with_warning=False) -> None:
88
112
  """Update .x_t"""
89
113
 
90
114
  self.parameters = parameters.copy()
@@ -151,5 +175,4 @@ class FemtetWithNXInterface(FemtetInterface):
151
175
  )
152
176
 
153
177
  # femprj モデルの変数も更新
154
- super().update_model(parameters)
155
-
178
+ super().update_model(parameters, with_warning=False)
@@ -10,10 +10,30 @@ from pythoncom import CoInitialize, CoUninitialize
10
10
 
11
11
  from pyfemtet.core import ModelError
12
12
  from pyfemtet.opt.interface import FemtetInterface, logger
13
- from pyfemtet.message import Msg
13
+ from pyfemtet._message import Msg
14
14
 
15
15
 
16
16
  class FemtetWithSolidworksInterface(FemtetInterface):
17
+ """Control Femtet and Solidworks.
18
+
19
+ Using this class, you can import CAD files created
20
+ in Solidworks through the Parasolid format into a
21
+ Femtet project. It allows you to pass design
22
+ variables to Solidworks, update the model, and
23
+ perform analysis using the updated model in Femtet.
24
+
25
+
26
+ Args:
27
+ sldprt_path (str):
28
+ The path to .sldprt file containing the
29
+ CAD data from which the import is made.
30
+ **kwargs:
31
+ For other arguments, please refer to the
32
+ :class:`FemtetInterface` class.
33
+
34
+ """
35
+
36
+
17
37
  # 定数の宣言
18
38
  swThisConfiguration = 1 # https://help.solidworks.com/2023/english/api/swconst/SOLIDWORKS.Interop.swconst~SOLIDWORKS.Interop.swconst.swInConfigurationOpts_e.html
19
39
  swAllConfiguration = 2
@@ -76,7 +96,7 @@ class FemtetWithSolidworksInterface(FemtetInterface):
76
96
  CoInitialize()
77
97
  self.initialize_sldworks_connection()
78
98
 
79
- def update_model(self, parameters: pd.DataFrame):
99
+ def update_model(self, parameters: pd.DataFrame, with_warning=False):
80
100
  """Update .x_t"""
81
101
 
82
102
  self.parameters = parameters.copy()
@@ -8,13 +8,12 @@ from time import sleep
8
8
 
9
9
  # 3rd-party
10
10
  import numpy as np
11
- import pandas as pd
12
11
 
13
12
  # pyfemtet relative
14
- from pyfemtet.opt.interface import FemtetInterface
13
+ from pyfemtet.opt.interface import FEMInterface
15
14
  from pyfemtet.opt._femopt_core import OptimizationStatus, Objective, Constraint
16
- from pyfemtet.message import Msg
17
- from pyfemtet.opt.parameter import ExpressionEvaluator
15
+ from pyfemtet._message import Msg
16
+ from pyfemtet.opt.optimizer.parameter import ExpressionEvaluator, Parameter
18
17
 
19
18
  # logger
20
19
  import logging
@@ -117,17 +116,11 @@ class AbstractOptimizer(ABC):
117
116
  fem (FEMInterface): The finite element method object.
118
117
  fem_class (type): The class of the finite element method object.
119
118
  fem_kwargs (dict): The keyword arguments used to instantiate the finite element method object.
120
- parameters (pd.DataFrame): The parameters used in the optimization.
121
- objectives (dict): A dictionary containing the objective functions used in the optimization.
122
- constraints (dict): A dictionary containing the constraint functions used in the optimization.
123
- entire_status (OptimizationStatus): The status of the entire optimization process.
119
+ variables (ExpressionEvaluator): The variables using optimization process including parameters.
120
+ objectives (dict[str, Objective]): A dictionary containing the objective functions used in the optimization.
121
+ constraints (dict[str, Constraint]): A dictionary containing the constraint functions used in the optimization.
124
122
  history (History): An actor object that records the history of each iteration in the optimization process.
125
- worker_status (OptimizationStatus): The status of each worker in a distributed computing environment.
126
- message (str): A message associated with the current state of the optimization process.
127
123
  seed (int or None): The random seed used for random number generation during the optimization process.
128
- timeout (float or int or None): The maximum time allowed for each iteration of the optimization process. If exceeded, it will be interrupted and terminated early.
129
- n_trials (int or None): The maximum number of trials allowed for each iteration of the optimization process. If exceeded, it will be interrupted and terminated early.
130
- is_cluster (bool): Flag indicating if running on a distributed computing cluster.
131
124
 
132
125
  """
133
126
 
@@ -150,9 +143,33 @@ class AbstractOptimizer(ABC):
150
143
  self._exception = None
151
144
  self.method_checker: OptimizationMethodChecker = OptimizationMethodChecker(self)
152
145
 
153
- def f(self, x):
154
- """Get x, update fem analysis, return objectives (and constraints)."""
155
- # interruption の実装は具象クラスに任せる
146
+ # ===== algorithm specific methods =====
147
+ @abstractmethod
148
+ def run(self) -> None:
149
+ """Start optimization."""
150
+ pass
151
+
152
+ # ----- FEMOpt interfaces -----
153
+ @abstractmethod
154
+ def _setup_before_parallel(self, *args, **kwargs):
155
+ """Setup before parallel processes are launched."""
156
+ pass
157
+
158
+ # ===== calc =====
159
+ def f(self, x: np.ndarray) -> list[np.ndarray]:
160
+ """Calculate objectives and constraints.
161
+
162
+ Args:
163
+ x (np.ndarray): Optimization parameters.
164
+
165
+ Returns:
166
+ list[np.ndarray]:
167
+ The list of internal objective values,
168
+ un-normalized objective values and
169
+ constraint values.
170
+
171
+ """
172
+
156
173
 
157
174
  if isinstance(x, np.float64):
158
175
  x = np.array([x])
@@ -202,8 +219,8 @@ class AbstractOptimizer(ABC):
202
219
  y,
203
220
  c,
204
221
  self.message,
205
- postprocess_func=self.fem.postprocess_func,
206
- postprocess_args=self.fem.create_postprocess_args(),
222
+ postprocess_func=self.fem._postprocess_func,
223
+ postprocess_args=self.fem._create_postprocess_args(),
207
224
  )
208
225
 
209
226
  logger.debug('history.record end')
@@ -212,26 +229,21 @@ class AbstractOptimizer(ABC):
212
229
 
213
230
  return np.array(y), np.array(_y), np.array(c)
214
231
 
215
- def _reconstruct_fem(self, skip_reconstruct=False):
216
- """Reconstruct FEMInterface in a subprocess."""
217
- # reconstruct fem
218
- if not skip_reconstruct:
219
- self.fem = self.fem_class(**self.fem_kwargs)
220
-
221
- # COM 定数の restore
222
- for obj in self.objectives.values():
223
- obj._restore_constants()
224
- for cns in self.constraints.values():
225
- cns._restore_constants()
226
-
232
+ # ===== parameter processing =====
227
233
  def get_parameter(self, format='dict'):
228
234
  """Returns the parameters in the specified format.
229
235
 
230
236
  Args:
231
- format (str, optional): The desired format of the parameters. Can be 'df' (DataFrame), 'value' (alias of values), 'values' (np.ndarray), or 'dict'. Defaults to 'dict'.
237
+ format (str, optional):
238
+ The desired format of the parameters.
239
+ Can be 'df' (DataFrame),
240
+ 'values' (np.ndarray),
241
+ 'dict' or
242
+ 'raw' (list of Variable object).
243
+ Defaults to 'dict'.
232
244
 
233
245
  Returns:
234
- object: The parameters in the specified format.
246
+ The parameters in the specified format.
235
247
 
236
248
  Raises:
237
249
  ValueError: If an invalid format is provided.
@@ -239,11 +251,14 @@ class AbstractOptimizer(ABC):
239
251
  """
240
252
  return self.variables.get_variables(format=format, filter_parameter=True)
241
253
 
242
- def set_parameter(self, params: dict) -> None:
254
+ def set_parameter(self, params: dict[str, float]) -> None:
243
255
  """Update parameter.
244
256
 
245
257
  Args:
246
- params (dict): Key is the name of parameter and the value is the value of it. The partial set is available.
258
+ params (dict):
259
+ Key is the name of parameter and
260
+ the value is the value of it.
261
+ The partial set is available.
247
262
 
248
263
  """
249
264
  for name, value in params.items():
@@ -255,11 +270,25 @@ class AbstractOptimizer(ABC):
255
270
 
256
271
  Args:
257
272
  values (np.ndarray): Values of all parameters.
273
+
258
274
  """
259
275
  prm_names = self.variables.get_parameter_names()
260
276
  assert len(values) == len(prm_names)
261
277
  self.set_parameter({k: v for k, v in zip(prm_names, values)})
262
278
 
279
+ # ===== FEMOpt interfaces =====
280
+ def _reconstruct_fem(self, skip_reconstruct=False):
281
+ """Reconstruct FEMInterface in a subprocess."""
282
+ # reconstruct fem
283
+ if not skip_reconstruct:
284
+ self.fem = self.fem_class(**self.fem_kwargs)
285
+
286
+ # COM 定数の restore
287
+ for obj in self.objectives.values():
288
+ obj._restore_constants()
289
+ for cns in self.constraints.values():
290
+ cns._restore_constants()
291
+
263
292
  def _check_interruption(self):
264
293
  """"""
265
294
  if self.entire_status.get() == OptimizationStatus.INTERRUPTING:
@@ -275,6 +304,7 @@ class AbstractOptimizer(ABC):
275
304
  if not self.worker_status.get() == OptimizationStatus.CRASHED:
276
305
  self.worker_status.set(OptimizationStatus.TERMINATED)
277
306
 
307
+ # run via FEMOpt (considering parallel processing)
278
308
  def _run(
279
309
  self,
280
310
  subprocess_idx,
@@ -331,12 +361,16 @@ class AbstractOptimizer(ABC):
331
361
 
332
362
  return self._exception
333
363
 
334
- @abstractmethod
335
- def run(self) -> None:
336
- """Start calculation using optimization library."""
337
- pass
338
364
 
339
- @abstractmethod
340
- def _setup_before_parallel(self, *args, **kwargs):
341
- """Setup before parallel processes are launched."""
342
- pass
365
+ if __name__ == '__main__':
366
+ class Optimizer(AbstractOptimizer):
367
+ def run(self): pass
368
+ def _setup_before_parallel(self, *args, **kwargs): pass
369
+
370
+ opt = Optimizer()
371
+ opt.set_parameter(
372
+ dict(
373
+ prm1=0.,
374
+ prm2=1.,
375
+ )
376
+ )
@@ -14,7 +14,7 @@ from optuna.study import MaxTrialsCallback
14
14
  from pyfemtet.opt._femopt_core import OptimizationStatus, generate_lhs, Constraint
15
15
  from pyfemtet.opt.optimizer import AbstractOptimizer, logger, OptimizationMethodChecker
16
16
  from pyfemtet.core import MeshError, ModelError, SolveError
17
- from pyfemtet.message import Msg
17
+ from pyfemtet._message import Msg
18
18
 
19
19
  # filter warnings
20
20
  import warnings
@@ -37,6 +37,38 @@ class OptunaMethodChecker(OptimizationMethodChecker):
37
37
 
38
38
 
39
39
  class OptunaOptimizer(AbstractOptimizer):
40
+ """Optimizer using ```optuna```.
41
+
42
+ This class provides an interface for the optimization
43
+ engine using Optuna. For more details, please refer to
44
+ the Optuna documentation.
45
+
46
+ See Also:
47
+ https://optuna.readthedocs.io/en/stable/reference/index.html
48
+
49
+ Args:
50
+ sampler_class (optuna.samplers.BaseSampler, optional):
51
+ A sampler class from Optuna. If not specified,
52
+ ```optuna.samplers.TPESampler``` is specified.
53
+ This defines the sampling strategy used during
54
+ optimization. Defaults to None.
55
+ sampler_kwargs (dict, optional):
56
+ A dictionary of keyword arguments to be passed to
57
+ the sampler class. This allows for customization
58
+ of the sampling process. Defaults to None.
59
+ add_init_method (str or Iterable[str], optional):
60
+ A method or a collection of methods to be added
61
+ during initialization. This can be used to specify
62
+ additional setup procedures.
63
+ Currently, the only valid value is 'LHS'
64
+ (using Latin Hypercube Sampling).
65
+ Defaults to None.
66
+
67
+ Warnings:
68
+ Do not include ```constraints_func``` in ```sampler_kwargs```.
69
+ It is generated and provided by :func:`FEMOpt.add_constraint`.
70
+
71
+ """
40
72
 
41
73
  def __init__(
42
74
  self,
@@ -15,7 +15,7 @@ from botorch.optim.initializers import gen_batch_initial_conditions
15
15
 
16
16
  from pyfemtet.opt._femopt_core import Constraint
17
17
  from pyfemtet.opt.optimizer import OptunaOptimizer, logger
18
- from pyfemtet.message import Msg
18
+ from pyfemtet._message import Msg
19
19
 
20
20
  from time import time
21
21
 
@@ -183,7 +183,6 @@ class NonlinearInequalityConstraints:
183
183
  item = (lambda x: GeneralFunctionWithForwardDifference.apply(cns_botorch, x), True)
184
184
  self._nonlinear_inequality_constraints.append(item)
185
185
 
186
-
187
186
  def _filter_feasible_conditions(self, ic_batch):
188
187
  # List to store feasible initial conditions
189
188
  feasible_ic_list = []