pyfemtet 0.4.19__py3-none-any.whl → 0.4.21__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 +107 -96
- pyfemtet/message/locales/messages.pot +104 -96
- pyfemtet/opt/_femopt.py +63 -38
- pyfemtet/opt/_femopt_core.py +2 -2
- pyfemtet/opt/interface/_femtet.py +77 -24
- pyfemtet/opt/opt/_base.py +21 -14
- pyfemtet/opt/opt/_optuna.py +20 -13
- pyfemtet/opt/opt/_scipy.py +1 -1
- pyfemtet/opt/opt/_scipy_scalar.py +1 -1
- pyfemtet/opt/parameter.py +113 -0
- {pyfemtet-0.4.19.dist-info → pyfemtet-0.4.21.dist-info}/METADATA +4 -3
- {pyfemtet-0.4.19.dist-info → pyfemtet-0.4.21.dist-info}/RECORD +17 -16
- {pyfemtet-0.4.19.dist-info → pyfemtet-0.4.21.dist-info}/LICENSE +0 -0
- {pyfemtet-0.4.19.dist-info → pyfemtet-0.4.21.dist-info}/WHEEL +0 -0
- {pyfemtet-0.4.19.dist-info → pyfemtet-0.4.21.dist-info}/entry_points.txt +0 -0
|
@@ -215,6 +215,24 @@ class FemtetInterface(FEMInterface):
|
|
|
215
215
|
if self.Femtet is None:
|
|
216
216
|
raise RuntimeError(Msg.ERR_FEMTET_CONNECTION_FAILED)
|
|
217
217
|
|
|
218
|
+
def _check_gaudi_accessible(self) -> bool:
|
|
219
|
+
try:
|
|
220
|
+
_ = self.Femtet.Gaudi
|
|
221
|
+
except com_error:
|
|
222
|
+
# モデルが開かれていないかFemtetが起動していない
|
|
223
|
+
return False
|
|
224
|
+
return True
|
|
225
|
+
|
|
226
|
+
# noinspection PyMethodMayBeStatic
|
|
227
|
+
def _construct_femtet_api(self, string): # static にしてはいけない
|
|
228
|
+
if isinstance(string, str):
|
|
229
|
+
if string.startswith('self.'):
|
|
230
|
+
return eval(string)
|
|
231
|
+
else:
|
|
232
|
+
return eval('self.' + string)
|
|
233
|
+
else:
|
|
234
|
+
return string # Callable
|
|
235
|
+
|
|
218
236
|
def _call_femtet_api(
|
|
219
237
|
self,
|
|
220
238
|
fun,
|
|
@@ -232,7 +250,7 @@ class FemtetInterface(FEMInterface):
|
|
|
232
250
|
|
|
233
251
|
Parameters
|
|
234
252
|
----------
|
|
235
|
-
fun : Callable
|
|
253
|
+
fun : Callable or str
|
|
236
254
|
Femtet API
|
|
237
255
|
return_value_if_failed : Any
|
|
238
256
|
API が失敗した時の戻り値
|
|
@@ -271,36 +289,62 @@ class FemtetInterface(FEMInterface):
|
|
|
271
289
|
# 1. 結果に関わらず戻り値が None で API 実行時に com_error を送出する
|
|
272
290
|
# 2. API 実行時に成功失敗を示す戻り値を返し、ShowLastError で例外にアクセスできる状態になる
|
|
273
291
|
|
|
292
|
+
# 実行する API をデバッグ出力
|
|
293
|
+
if isinstance(fun, str):
|
|
294
|
+
logger.debug(' ' * print_indent + f'Femtet API:{fun}, args:{args}, kwargs:{kwargs}')
|
|
295
|
+
else:
|
|
296
|
+
logger.debug(' ' * print_indent + f'Femtet API:{fun.__name__}, args:{args}, kwargs:{kwargs}')
|
|
297
|
+
|
|
274
298
|
# Gaudi コマンドなら Gaudi.Activate する
|
|
275
|
-
logger.debug(' ' * print_indent + f'Femtet API:{fun.__name__}, args:{args}, kwargs:{kwargs}')
|
|
276
299
|
if is_Gaudi_method: # Optimizer は Gogh に触らないので全部にこれをつけてもいい気がする
|
|
277
300
|
try:
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
301
|
+
# まず Gaudi にアクセスできるか
|
|
302
|
+
gaudi_accessible = self._check_gaudi_accessible()
|
|
303
|
+
if gaudi_accessible:
|
|
304
|
+
# Gaudi にアクセスできるなら Gaudi を Activate する
|
|
305
|
+
fun = self._construct_femtet_api(fun) # (str) -> Callable
|
|
306
|
+
if fun.__name__ != 'Activate':
|
|
307
|
+
# 再帰ループにならないように
|
|
308
|
+
self._call_femtet_api(
|
|
309
|
+
self.Femtet.Gaudi.Activate,
|
|
310
|
+
False, # None 以外なら何でもいい
|
|
311
|
+
Exception,
|
|
312
|
+
'Gaudi のオープンに失敗しました',
|
|
313
|
+
print_indent=print_indent + 1
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
else:
|
|
317
|
+
# Gaudi にアクセスできないならば次の API 実行でエラーになる
|
|
318
|
+
pass
|
|
319
|
+
|
|
285
320
|
except com_error:
|
|
286
|
-
# Gaudi へのアクセスだけで com_error が生じうる
|
|
287
|
-
# そういう場合は次の API 実行で間違いなくエラーになるので放っておく
|
|
288
321
|
pass
|
|
289
322
|
|
|
290
323
|
# API を実行
|
|
291
324
|
try:
|
|
325
|
+
# gaudi のメソッドかどうかにかかわらず、gaudi へのアクセスでエラーが出るか
|
|
326
|
+
if not self._check_gaudi_accessible():
|
|
327
|
+
raise com_error
|
|
328
|
+
|
|
329
|
+
# gaudi_accessible なので関数が何であろうが安全にアクセスはできる
|
|
330
|
+
if isinstance(fun, str):
|
|
331
|
+
fun = self._construct_femtet_api(fun) # (str) -> Callable
|
|
332
|
+
|
|
292
333
|
# 解析結果を開いた状態で Gaudi.Activate して ReExecute する場合、ReExecute の前後にアクティブ化イベントが必要
|
|
293
334
|
# さらに、プロジェクトツリーが開いていないとアクティブ化イベントも意味がないらしい。
|
|
294
335
|
if fun.__name__ == 'ReExecute':
|
|
295
336
|
if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
|
|
296
337
|
post_activate_message(self.Femtet.hWnd)
|
|
338
|
+
# API を実行
|
|
297
339
|
returns = fun(*args, **kwargs) # can raise pywintypes.error
|
|
298
340
|
if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
|
|
299
341
|
post_activate_message(self.Femtet.hWnd)
|
|
300
342
|
else:
|
|
301
343
|
returns = fun(*args, **kwargs)
|
|
344
|
+
|
|
345
|
+
# API の実行に失敗
|
|
302
346
|
except (com_error, error):
|
|
303
|
-
#
|
|
347
|
+
# 後続の処理でエラー判定されるように returns を作る
|
|
304
348
|
# com_error ではなく error の場合はおそらく Femtet が落ちている
|
|
305
349
|
if ret_for_check_idx is None:
|
|
306
350
|
returns = return_value_if_failed
|
|
@@ -361,7 +405,7 @@ class FemtetInterface(FEMInterface):
|
|
|
361
405
|
|
|
362
406
|
def femtet_is_alive(self) -> bool:
|
|
363
407
|
"""Returns connected femtet process is existing or not."""
|
|
364
|
-
return _get_pid(self.Femtet.hWnd) > 0
|
|
408
|
+
return _get_pid(self.Femtet.hWnd) > 0 # hWnd の値はすでに Femtet が終了している場合は 0
|
|
365
409
|
|
|
366
410
|
def open(self, femprj_path: str, model_name: str or None = None) -> None:
|
|
367
411
|
"""Open specific analysis model with connected Femtet."""
|
|
@@ -479,7 +523,7 @@ class FemtetInterface(FEMInterface):
|
|
|
479
523
|
# 変数更新のための処理
|
|
480
524
|
sleep(0.1) # Gaudi がおかしくなる時がある対策
|
|
481
525
|
self._call_femtet_api(
|
|
482
|
-
self.Femtet.Gaudi.Activate,
|
|
526
|
+
'self.Femtet.Gaudi.Activate',
|
|
483
527
|
True, # 戻り値を持たないのでここは無意味で None 以外なら何でもいい
|
|
484
528
|
Exception, # 生きてるのに開けない場合
|
|
485
529
|
error_message=Msg.NO_ANALYSIS_MODEL_IS_OPEN,
|
|
@@ -553,7 +597,7 @@ class FemtetInterface(FEMInterface):
|
|
|
553
597
|
|
|
554
598
|
# 設計変数に従ってモデルを再構築
|
|
555
599
|
self._call_femtet_api(
|
|
556
|
-
self.Femtet.Gaudi.ReExecute,
|
|
600
|
+
'self.Femtet.Gaudi.ReExecute',
|
|
557
601
|
False,
|
|
558
602
|
ModelError, # 生きてるのに失敗した場合
|
|
559
603
|
error_message=Msg.ERR_RE_EXECUTE_MODEL_FAILED,
|
|
@@ -576,7 +620,7 @@ class FemtetInterface(FEMInterface):
|
|
|
576
620
|
"""Execute FEM analysis."""
|
|
577
621
|
# # メッシュを切る
|
|
578
622
|
self._call_femtet_api(
|
|
579
|
-
self.Femtet.Gaudi.Mesh,
|
|
623
|
+
'self.Femtet.Gaudi.Mesh',
|
|
580
624
|
0,
|
|
581
625
|
MeshError,
|
|
582
626
|
Msg.ERR_MODEL_MESH_FAILED,
|
|
@@ -630,6 +674,11 @@ class FemtetInterface(FEMInterface):
|
|
|
630
674
|
def quit(self, timeout=1, force=True):
|
|
631
675
|
"""Force to terminate connected Femtet."""
|
|
632
676
|
major, minor, bugfix = 2024, 0, 1
|
|
677
|
+
|
|
678
|
+
# すでに終了しているならば何もしない
|
|
679
|
+
if not self.femtet_is_alive():
|
|
680
|
+
return
|
|
681
|
+
|
|
633
682
|
if self._version() >= _version(major, minor, bugfix):
|
|
634
683
|
# gracefully termination method without save project available from 2024.0.1
|
|
635
684
|
try:
|
|
@@ -715,16 +764,20 @@ class FemtetInterface(FEMInterface):
|
|
|
715
764
|
# save to worker space
|
|
716
765
|
result_dir = self.femprj_path.replace('.femprj', '.Results')
|
|
717
766
|
pdt_path = os.path.join(result_dir, self.model_name + '.pdt')
|
|
718
|
-
succeed = self.Femtet.SavePDT(pdt_path, True)
|
|
719
767
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
768
|
+
self._call_femtet_api(
|
|
769
|
+
fun=self.Femtet.SavePDT,
|
|
770
|
+
args=(pdt_path, True),
|
|
771
|
+
return_value_if_failed=False,
|
|
772
|
+
if_error=SolveError,
|
|
773
|
+
error_message=Msg.ERR_FAILED_TO_SAVE_PDT,
|
|
774
|
+
is_Gaudi_method=False,
|
|
775
|
+
)
|
|
725
776
|
|
|
726
|
-
|
|
727
|
-
|
|
777
|
+
# convert .pdt to ByteIO and return it
|
|
778
|
+
with open(pdt_path, 'rb') as f:
|
|
779
|
+
content = f.read()
|
|
780
|
+
return content
|
|
728
781
|
|
|
729
782
|
else:
|
|
730
783
|
return None
|
pyfemtet/opt/opt/_base.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# typing
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Optional
|
|
3
4
|
|
|
4
5
|
# built-in
|
|
5
6
|
import traceback
|
|
@@ -13,6 +14,7 @@ import pandas as pd
|
|
|
13
14
|
from pyfemtet.opt.interface import FemtetInterface
|
|
14
15
|
from pyfemtet.opt._femopt_core import OptimizationStatus
|
|
15
16
|
from pyfemtet.message import Msg
|
|
17
|
+
from pyfemtet.opt.parameter import ExpressionEvaluator
|
|
16
18
|
|
|
17
19
|
# logger
|
|
18
20
|
import logging
|
|
@@ -134,6 +136,7 @@ class AbstractOptimizer(ABC):
|
|
|
134
136
|
self.fem_class = None
|
|
135
137
|
self.fem_kwargs = dict()
|
|
136
138
|
self.parameters: pd.DataFrame = pd.DataFrame()
|
|
139
|
+
self.variables: ExpressionEvaluator = ExpressionEvaluator()
|
|
137
140
|
self.objectives: dict = dict()
|
|
138
141
|
self.constraints: dict = dict()
|
|
139
142
|
self.entire_status = None # actor
|
|
@@ -153,14 +156,22 @@ class AbstractOptimizer(ABC):
|
|
|
153
156
|
# interruption の実装は具象クラスに任せる
|
|
154
157
|
|
|
155
158
|
# x の更新
|
|
156
|
-
|
|
159
|
+
prm_names = self.variables.get_parameter_names()
|
|
160
|
+
for name, value in zip(prm_names, x):
|
|
161
|
+
self.variables.variables[name].value = value
|
|
162
|
+
|
|
157
163
|
logger.info('---------------------')
|
|
158
164
|
logger.info(f'input: {x}')
|
|
159
165
|
|
|
160
166
|
# FEM の更新
|
|
161
167
|
logger.debug('fem.update() start')
|
|
162
168
|
try:
|
|
163
|
-
self.
|
|
169
|
+
df_to_fem = self.variables.get_variables(
|
|
170
|
+
format='df',
|
|
171
|
+
filter_pass_to_fem=True
|
|
172
|
+
)
|
|
173
|
+
self.fem.update(df_to_fem)
|
|
174
|
+
|
|
164
175
|
except Exception as e:
|
|
165
176
|
logger.info(f'{type(e).__name__} : {e}')
|
|
166
177
|
logger.info(Msg.INFO_EXCEPTION_DURING_FEM_ANALYSIS)
|
|
@@ -178,8 +189,14 @@ class AbstractOptimizer(ABC):
|
|
|
178
189
|
c = [cns.calc(self.fem) for cns in self.constraints.values()]
|
|
179
190
|
|
|
180
191
|
logger.debug('history.record start')
|
|
192
|
+
|
|
193
|
+
df_to_opt = self.variables.get_variables(
|
|
194
|
+
format='df',
|
|
195
|
+
filter_parameter=True,
|
|
196
|
+
)
|
|
197
|
+
|
|
181
198
|
self.history.record(
|
|
182
|
-
|
|
199
|
+
df_to_opt,
|
|
183
200
|
self.objectives,
|
|
184
201
|
self.constraints,
|
|
185
202
|
y,
|
|
@@ -220,17 +237,7 @@ class AbstractOptimizer(ABC):
|
|
|
220
237
|
ValueError: If an invalid format is provided.
|
|
221
238
|
|
|
222
239
|
"""
|
|
223
|
-
|
|
224
|
-
return self.parameters
|
|
225
|
-
elif format == 'values' or format == 'value':
|
|
226
|
-
return self.parameters.value.values
|
|
227
|
-
elif format == 'dict':
|
|
228
|
-
ret = {}
|
|
229
|
-
for i, row in self.parameters.iterrows():
|
|
230
|
-
ret[row['name']] = row.value
|
|
231
|
-
return ret
|
|
232
|
-
else:
|
|
233
|
-
raise ValueError(f'get_parameter() got invalid format: {format}')
|
|
240
|
+
return self.variables.get_variables(format=format)
|
|
234
241
|
|
|
235
242
|
def _check_interruption(self):
|
|
236
243
|
""""""
|
pyfemtet/opt/opt/_optuna.py
CHANGED
|
@@ -63,19 +63,25 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
63
63
|
trial.study.stop() # 現在実行中の trial を最後にする
|
|
64
64
|
return None # set TrialState FAIL
|
|
65
65
|
|
|
66
|
-
# candidate x
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
# candidate x and update parameters
|
|
67
|
+
for prm in self.variables.get_variables(format='raw', filter_parameter=True):
|
|
68
|
+
value = trial.suggest_float(
|
|
69
|
+
name=prm.name,
|
|
70
|
+
low=prm.lower_bound,
|
|
71
|
+
high=prm.upper_bound,
|
|
72
|
+
step=prm.step,
|
|
73
|
+
)
|
|
74
|
+
self.variables.variables[prm.name].value = value
|
|
75
|
+
|
|
76
|
+
# update expressions
|
|
77
|
+
self.variables.evaluate()
|
|
72
78
|
|
|
73
79
|
# message の設定
|
|
74
80
|
self.message = trial.user_attrs['message'] if 'message' in trial.user_attrs.keys() else ''
|
|
75
81
|
|
|
76
|
-
# fem
|
|
77
|
-
self.
|
|
78
|
-
self.fem.update_parameter(
|
|
82
|
+
# fem 経由で変数を取得して constraint を計算する時のためにアップデート
|
|
83
|
+
df_fem = self.variables.get_variables(format='df', filter_pass_to_fem=True)
|
|
84
|
+
self.fem.update_parameter(df_fem)
|
|
79
85
|
|
|
80
86
|
# strict 拘束
|
|
81
87
|
strict_constraints = [cns for cns in self.constraints.values() if cns.strict]
|
|
@@ -89,10 +95,11 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
89
95
|
if not feasible:
|
|
90
96
|
logger.info(Msg.INFO_INFEASIBLE)
|
|
91
97
|
logger.info(f'Constraint: {cns.name}')
|
|
92
|
-
logger.info(self.
|
|
98
|
+
logger.info(self.variables.get_variables('dict', filter_parameter=True))
|
|
93
99
|
raise optuna.TrialPruned() # set TrialState PRUNED because FAIL causes similar candidate loop.
|
|
94
100
|
|
|
95
101
|
# 計算
|
|
102
|
+
x = self.variables.get_variables(format='values', filter_parameter=True)
|
|
96
103
|
try:
|
|
97
104
|
_, _y, c = self.f(x) # f の中で info は出している
|
|
98
105
|
except (ModelError, MeshError, SolveError) as e:
|
|
@@ -175,7 +182,7 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
175
182
|
# 初期値の設定
|
|
176
183
|
if len(self.study.trials) == 0: # リスタートでなければ
|
|
177
184
|
# ユーザーの指定した初期値
|
|
178
|
-
params = self.
|
|
185
|
+
params = self.variables.get_variables('dict', filter_parameter=True)
|
|
179
186
|
self.study.enqueue_trial(params, user_attrs={"message": "initial"})
|
|
180
187
|
|
|
181
188
|
# add_initial_parameter で追加された初期値
|
|
@@ -197,8 +204,8 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
197
204
|
bounds = []
|
|
198
205
|
for i, row in self.parameters.iterrows():
|
|
199
206
|
names.append(row['name'])
|
|
200
|
-
lb = row['
|
|
201
|
-
ub = row['
|
|
207
|
+
lb = row['lower_bound']
|
|
208
|
+
ub = row['upper_bound']
|
|
202
209
|
bounds.append([lb, ub])
|
|
203
210
|
data = generate_lhs(bounds, seed=self.seed)
|
|
204
211
|
for datum in data:
|
pyfemtet/opt/opt/_scipy.py
CHANGED
|
@@ -114,7 +114,7 @@ class ScipyOptimizer(AbstractOptimizer):
|
|
|
114
114
|
if 'bounds' not in self.minimize_kwargs.keys():
|
|
115
115
|
bounds = []
|
|
116
116
|
for i, row in self.parameters.iterrows():
|
|
117
|
-
lb, ub = row['
|
|
117
|
+
lb, ub = row['lower_buond'], row['upper_bound']
|
|
118
118
|
if lb is None: lb = -np.inf
|
|
119
119
|
if ub is None: ub = np.inf
|
|
120
120
|
bounds.append([lb, ub])
|
|
@@ -78,7 +78,7 @@ class ScipyScalarOptimizer(AbstractOptimizer):
|
|
|
78
78
|
if 'bounds' not in self.minimize_kwargs.keys():
|
|
79
79
|
bounds = []
|
|
80
80
|
for i, row in self.parameters.iterrows():
|
|
81
|
-
lb, ub = row['
|
|
81
|
+
lb, ub = row['lower_bound'], row['upper_bound']
|
|
82
82
|
if lb is None: lb = -np.inf
|
|
83
83
|
if ub is None: ub = np.inf
|
|
84
84
|
bounds.append([lb, ub])
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from graphlib import TopologicalSorter
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
import inspect
|
|
4
|
+
from typing import Optional, Callable, Any, Tuple, Dict
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class Variable:
|
|
12
|
+
name: str
|
|
13
|
+
value: float
|
|
14
|
+
pass_to_fem: Optional[bool] = True
|
|
15
|
+
properties: Optional[dict[Any]] = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class Parameter(Variable):
|
|
20
|
+
lower_bound: Optional[float] = None
|
|
21
|
+
upper_bound: Optional[float] = None
|
|
22
|
+
step: Optional[float] = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class Expression(Variable):
|
|
27
|
+
# fun に params を自動で代入するので positional args は実装しない
|
|
28
|
+
fun: Optional[Callable] = None
|
|
29
|
+
kwargs: Optional[Dict] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ExpressionEvaluator:
|
|
33
|
+
def __init__(self):
|
|
34
|
+
self.variables = {} # Parameter 又は計算された Expression が入る
|
|
35
|
+
self.parameters = {}
|
|
36
|
+
self.expressions = {}
|
|
37
|
+
self.dependencies = {}
|
|
38
|
+
self.evaluation_order = []
|
|
39
|
+
|
|
40
|
+
def add_parameter(self, prm: Parameter):
|
|
41
|
+
self.variables[prm.name] = prm
|
|
42
|
+
self.parameters[prm.name] = prm
|
|
43
|
+
self.dependencies[prm.name] = set()
|
|
44
|
+
|
|
45
|
+
def add_expression(self, exp: Expression):
|
|
46
|
+
self.expressions[exp.name] = exp
|
|
47
|
+
|
|
48
|
+
# params は Python 変数として使える文字のみからなる文字列のリスト
|
|
49
|
+
params = inspect.signature(exp.fun).parameters
|
|
50
|
+
self.dependencies[exp.name] = set(params) - set(exp.kwargs.keys())
|
|
51
|
+
|
|
52
|
+
def resolve(self):
|
|
53
|
+
ts = TopologicalSorter(self.dependencies)
|
|
54
|
+
self.evaluation_order = list(ts.static_order())
|
|
55
|
+
|
|
56
|
+
def evaluate(self):
|
|
57
|
+
# order 順に見ていき、expression なら計算して variables を更新する
|
|
58
|
+
for var_name in self.evaluation_order:
|
|
59
|
+
if var_name in self.expressions.keys():
|
|
60
|
+
# 現在の expression に関して parameter 部分の引数 kwargs を作成
|
|
61
|
+
kwargs = {param: self.variables[param].value for param in self.dependencies[var_name]}
|
|
62
|
+
|
|
63
|
+
# fun に すべての kwargs を入れて expression の value を更新
|
|
64
|
+
exp: Expression = self.expressions[var_name]
|
|
65
|
+
kwargs.update(exp.kwargs)
|
|
66
|
+
exp.value = exp.fun(**kwargs)
|
|
67
|
+
|
|
68
|
+
# 計算済み variables に追加
|
|
69
|
+
self.variables[var_name] = exp
|
|
70
|
+
|
|
71
|
+
def get_variables(self, format='dict', filter_pass_to_fem=False, filter_parameter=False):
|
|
72
|
+
"""format: dict, values, df, raw(list of Variable object)"""
|
|
73
|
+
|
|
74
|
+
# リストを作成
|
|
75
|
+
vars = [self.variables[name] for name in self.evaluation_order if name in self.variables]
|
|
76
|
+
|
|
77
|
+
# 必要なら FEM に直接使うもののみ取り出し
|
|
78
|
+
if filter_pass_to_fem:
|
|
79
|
+
vars = [var for var in vars if var.pass_to_fem]
|
|
80
|
+
|
|
81
|
+
# 必要なら parameter のみ取り出し
|
|
82
|
+
if filter_parameter:
|
|
83
|
+
vars = [var for var in vars if isinstance(var, Parameter)]
|
|
84
|
+
|
|
85
|
+
if format == 'raw':
|
|
86
|
+
return vars
|
|
87
|
+
|
|
88
|
+
elif format == 'dict':
|
|
89
|
+
return {var.name: var.value for var in vars}
|
|
90
|
+
|
|
91
|
+
elif format == 'values':
|
|
92
|
+
return np.array([var.value for var in vars]).astype(float)
|
|
93
|
+
|
|
94
|
+
elif format == 'df':
|
|
95
|
+
data = dict(
|
|
96
|
+
name=[var.name for var in vars],
|
|
97
|
+
value=[var.value for var in vars],
|
|
98
|
+
properties=[var.properties for var in vars],
|
|
99
|
+
)
|
|
100
|
+
if filter_parameter:
|
|
101
|
+
data.update(
|
|
102
|
+
dict(
|
|
103
|
+
lower_bound=[var.lower_bound for var in vars],
|
|
104
|
+
upper_bound=[var.upper_bound for var in vars],
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
return pd.DataFrame(data)
|
|
108
|
+
|
|
109
|
+
else:
|
|
110
|
+
raise NotImplementedError(f'invalid format: {format}. Valid formats are `dict`, `values`, `df` and `raw`(= list of Variables).')
|
|
111
|
+
|
|
112
|
+
def get_parameter_names(self):
|
|
113
|
+
return list(self.parameters.keys())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyfemtet
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.21
|
|
4
4
|
Summary: Design parameter optimization using Femtet.
|
|
5
5
|
Home-page: https://github.com/pyfemtet/pyfemtet
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -16,7 +16,7 @@ Requires-Dist: babel (>=2.15.0,<3.0.0)
|
|
|
16
16
|
Requires-Dist: botorch (>=0.9.5) ; python_version >= "3.12" and python_version < "3.13"
|
|
17
17
|
Requires-Dist: botorch (>=0.9.5,<0.10.0) ; python_version < "3.12"
|
|
18
18
|
Requires-Dist: colorlog (>=6.8.0,<7.0.0)
|
|
19
|
-
Requires-Dist: dash (>=2.
|
|
19
|
+
Requires-Dist: dash (>=2.17.0,<3.0.0)
|
|
20
20
|
Requires-Dist: dash-bootstrap-components (>=1.5.0,<2.0.0)
|
|
21
21
|
Requires-Dist: dask (>=2023.12.1,<2024.0.0)
|
|
22
22
|
Requires-Dist: distributed (>=2023.12.1,<2024.0.0)
|
|
@@ -26,11 +26,12 @@ Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
|
|
|
26
26
|
Requires-Dist: optuna (>=3.4.0,<4.0.0)
|
|
27
27
|
Requires-Dist: optuna-integration (>=3.6.0,<4.0.0)
|
|
28
28
|
Requires-Dist: pandas (>=2.1.3,<3.0.0)
|
|
29
|
-
Requires-Dist: plotly (>=5.
|
|
29
|
+
Requires-Dist: plotly (>=5.22.0,<6.0.0)
|
|
30
30
|
Requires-Dist: psutil (>=5.9.6,<6.0.0)
|
|
31
31
|
Requires-Dist: pytest-dashboard (>=0.1.2,<0.2.0)
|
|
32
32
|
Requires-Dist: pywin32 (>=306,<307)
|
|
33
33
|
Requires-Dist: scipy (>=1.11.4,<2.0.0)
|
|
34
|
+
Requires-Dist: torch (>=2.3.0,<2.4.0)
|
|
34
35
|
Requires-Dist: tqdm (>=4.66.1,<5.0.0)
|
|
35
36
|
Project-URL: Repository, https://github.com/pyfemtet/pyfemtet
|
|
36
37
|
Description-Content-Type: text/markdown
|
|
@@ -12,7 +12,7 @@ pyfemtet/FemtetPJTSample/her_ex40_parametric.py,sha256=B5PQoh71Q3KN2CyLU1gP_Yh9g
|
|
|
12
12
|
pyfemtet/FemtetPJTSample/wat_ex14_parallel_parametric.py,sha256=UfhJffuXyhzdIWNpOrpV6xLTK1fuVvgyhlyg4Rp-628,2148
|
|
13
13
|
pyfemtet/FemtetPJTSample/wat_ex14_parametric.femprj,sha256=pxacKe0NPNUPAcxqo2cATFApsMKiVt2g2e_FOk4fpjA,172895
|
|
14
14
|
pyfemtet/FemtetPJTSample/wat_ex14_parametric.py,sha256=LGbWxCek0Ad2YrDCKykiQkE3aIypM4g8P3mLd_2anEE,2052
|
|
15
|
-
pyfemtet/__init__.py,sha256=
|
|
15
|
+
pyfemtet/__init__.py,sha256=1n-NaGbhCs2-5sTHYY-kUYdFODaECYkQxiDw4p6nNng,22
|
|
16
16
|
pyfemtet/_test_util.py,sha256=CT9J19qQ4gYT5glFs8WwlTDmc3SokvdE5ucpB-KCOro,4274
|
|
17
17
|
pyfemtet/core.py,sha256=3lqfBGJ5IuKz2Nqj5pRo7YQqKwx_0ZDL72u95Ur_1p0,1386
|
|
18
18
|
pyfemtet/dispatch_extensions.py,sha256=XVZajbjh7mb6NG4Hq8qff2TJWab75r4Hd59cIvCRsVg,16213
|
|
@@ -21,13 +21,13 @@ pyfemtet/message/1. make_pot.bat,sha256=oS38xYsaUnQAuKwUR8hZJFgt3AKBU993fWFDSg2R
|
|
|
21
21
|
pyfemtet/message/2. make_mo.bat,sha256=nqUi3Cze7JGKkYItlch8ZG2gSbRNZiS2ltuCS7DbmG8,154
|
|
22
22
|
pyfemtet/message/__init__.py,sha256=gE1-XX_PzHj9BbhqPaK5VcIHuv6_Tec5qlPMC3IRiBg,100
|
|
23
23
|
pyfemtet/message/babel.cfg,sha256=rlvsm_EjDU2ki-OLVPG3toWspVuVA0JFAFvFp2U-By4,72
|
|
24
|
-
pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo,sha256=
|
|
25
|
-
pyfemtet/message/locales/ja/LC_MESSAGES/messages.po,sha256=
|
|
26
|
-
pyfemtet/message/locales/messages.pot,sha256=
|
|
24
|
+
pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo,sha256=VbUncnHf3ztDF3WqaoNd4AcGqpYKLMEKc1LL5P4yuoQ,16965
|
|
25
|
+
pyfemtet/message/locales/ja/LC_MESSAGES/messages.po,sha256=6UtCDxiDiRetnnSRo-l_BunYfYoIm0L-9Z8qU3r8z8Q,21723
|
|
26
|
+
pyfemtet/message/locales/messages.pot,sha256=JWknwqPn_541aeIEbxp9Y2tqXvUcoM-vgdjeUo4C2T0,12336
|
|
27
27
|
pyfemtet/message/messages.py,sha256=GCzjA6dBLI8108K3hel82pcr1nYTvjJKCfCAn5jZ5OM,11324
|
|
28
28
|
pyfemtet/opt/__init__.py,sha256=AJc1_d0sQ2_X4h_8FOcdmHvSPrFV_vfxlRrZTsqDZuE,612
|
|
29
|
-
pyfemtet/opt/_femopt.py,sha256=
|
|
30
|
-
pyfemtet/opt/_femopt_core.py,sha256=
|
|
29
|
+
pyfemtet/opt/_femopt.py,sha256=lJJYDNoeAFlPEDD7mMz5PXA-x91vz6u0hnai7FLJJ30,24905
|
|
30
|
+
pyfemtet/opt/_femopt_core.py,sha256=ezf-E1_oaupSgHb0mwPooV0nvsrQC1wgtumN5WzQop8,25311
|
|
31
31
|
pyfemtet/opt/femprj_sample/.gitignore,sha256=hx-5Hhaf7kpHe1wvWWfJqjPfObg-zf9CTI4joNh2Hk4,28
|
|
32
32
|
pyfemtet/opt/femprj_sample/ParametricIF - True.femprj,sha256=tCd29CUXmyJ0VH6cV0xTdjQMLBPkCk0UrFwvRbyrcYA,431415
|
|
33
33
|
pyfemtet/opt/femprj_sample/ParametricIF.femprj,sha256=9BtDHmc3cdom0Zq33DTdZ0mDAsIUY6i8SRkkg-n7GO0,442090
|
|
@@ -109,17 +109,18 @@ pyfemtet/opt/femprj_sample_jp/wat_ex14_parametric_jp.py,sha256=W30jobW1eEYuAsJJR
|
|
|
109
109
|
pyfemtet/opt/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py,sha256=ul2JUwlM5jfjNRELHkT7ZDuyMOq5RAHO32vAweEhCwg,2641
|
|
110
110
|
pyfemtet/opt/interface/__init__.py,sha256=qz5BszPuU3jZIoDnPjkPDAgvgHLlx1sYhuqh5ID798k,480
|
|
111
111
|
pyfemtet/opt/interface/_base.py,sha256=I4pJttLeRW-6WWMuCNynwxWPwriiGZk20vHLVcfixZY,2332
|
|
112
|
-
pyfemtet/opt/interface/_femtet.py,sha256=
|
|
112
|
+
pyfemtet/opt/interface/_femtet.py,sha256=vWPEn8TpJFCSN48uk430kAFr7_5ralMoOGF8IKvpIjU,34441
|
|
113
113
|
pyfemtet/opt/interface/_femtet_parametric.py,sha256=KDG8SB43AgwuhpCStjvx10G0RzyHhga6k4dfvp0gvYU,2175
|
|
114
114
|
pyfemtet/opt/interface/_femtet_with_nx/__init__.py,sha256=-6W2g2FDEcKzGHmI5KAKQe-4U5jDpMj0CXuma-GZca0,83
|
|
115
115
|
pyfemtet/opt/interface/_femtet_with_nx/_interface.py,sha256=cibPOhsUAvTDJa1xdEhVClZjwPkEx2kBmi61vyTJHUs,5514
|
|
116
116
|
pyfemtet/opt/interface/_femtet_with_nx/update_model.py,sha256=P7VH0i_o-X9OUe6AGaLF1fACPeHNrMjcrOBCA3MMrI4,3092
|
|
117
117
|
pyfemtet/opt/interface/_femtet_with_sldworks.py,sha256=Ldr8Esa5xZ-D_E5uIXBTF2DHslXVMFDYOsqTd8FhY1M,6242
|
|
118
118
|
pyfemtet/opt/opt/__init__.py,sha256=_9hkYtxk-8PfWkWJaiYqESrH5CnSKM2Gv93HxtD-f3o,383
|
|
119
|
-
pyfemtet/opt/opt/_base.py,sha256=
|
|
120
|
-
pyfemtet/opt/opt/_optuna.py,sha256=
|
|
121
|
-
pyfemtet/opt/opt/_scipy.py,sha256=
|
|
122
|
-
pyfemtet/opt/opt/_scipy_scalar.py,sha256=
|
|
119
|
+
pyfemtet/opt/opt/_base.py,sha256=pIxreZzhT4YQOj7mtXnfidNqJ18ypZBpD2CK0G_uQ6Q,11425
|
|
120
|
+
pyfemtet/opt/opt/_optuna.py,sha256=y4MnFPDyP1eheq5nUh786z0BM-pHNYrSwjo1TD044h0,11105
|
|
121
|
+
pyfemtet/opt/opt/_scipy.py,sha256=8Alx9sIlLzNTxuVGTHOJMsvW5LSp8WDFiqD8IV6CVPc,4203
|
|
122
|
+
pyfemtet/opt/opt/_scipy_scalar.py,sha256=ot1KbetZeQh5XkllzHc1PubPjBPgVBtC0a4jllNi8G4,2833
|
|
123
|
+
pyfemtet/opt/parameter.py,sha256=YLE9lmYRaZA8isnTPJnbYXpUn6zsJFW4xg03QaSWey8,3950
|
|
123
124
|
pyfemtet/opt/prediction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
124
125
|
pyfemtet/opt/prediction/base.py,sha256=q4lDqrOtAkiWG-OblQEddnEVj29Q-EJE3-O5QTOb3Q4,1761
|
|
125
126
|
pyfemtet/opt/prediction/single_task_gp.py,sha256=VbsVllzXzCGqkM1fC61Ouqwuv3ddS5INbFwDG8v-d6g,3303
|
|
@@ -145,8 +146,8 @@ pyfemtet/opt/visualization/wrapped_components/dbc.py,sha256=wzR1ZMOb4uwPNTMFn5up
|
|
|
145
146
|
pyfemtet/opt/visualization/wrapped_components/dcc.py,sha256=hcW7SR6VIMn4S4-JMyohvOzdc0Aw8A4chIeHqQEUbFU,17499
|
|
146
147
|
pyfemtet/opt/visualization/wrapped_components/html.py,sha256=sE2XHTDY1GvA1NW7y6SKWf-WglVXFKKvXhU9h3z53_g,95652
|
|
147
148
|
pyfemtet/opt/visualization/wrapped_components/str_enum.py,sha256=NZqbh2jNEAckvJyZv__MWeRs2F2Q-dkJCWo30rU2rrM,1383
|
|
148
|
-
pyfemtet-0.4.
|
|
149
|
-
pyfemtet-0.4.
|
|
150
|
-
pyfemtet-0.4.
|
|
151
|
-
pyfemtet-0.4.
|
|
152
|
-
pyfemtet-0.4.
|
|
149
|
+
pyfemtet-0.4.21.dist-info/LICENSE,sha256=sVQBhyoglGJUu65-BP3iR6ujORI6YgEU2Qm-V4fGlOA,1485
|
|
150
|
+
pyfemtet-0.4.21.dist-info/METADATA,sha256=r0QpSmzWtYQ9Us_OsVe_cNJGRo8E6JKci0aL9SDD-qI,3459
|
|
151
|
+
pyfemtet-0.4.21.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
152
|
+
pyfemtet-0.4.21.dist-info/entry_points.txt,sha256=ZfYqRaoiPtuWqFi2_msccyrVF0LurMn-IHlYamAegZo,104
|
|
153
|
+
pyfemtet-0.4.21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|