PyFemtet 0.2.2__tar.gz → 0.3.0__tar.gz
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.
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/PKG-INFO +5 -4
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.py +14 -7
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/gau_ex08_parametric.py +16 -5
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/her_ex40_parametric.py +24 -10
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/wat_ex14_parallel_parametric.py +7 -7
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/wat_ex14_parametric.py +7 -7
- pyfemtet-0.3.0/pyfemtet/__init__.py +1 -0
- pyfemtet-0.3.0/pyfemtet/core.py +38 -0
- pyfemtet-0.3.0/pyfemtet/dispatch_extensions.py +462 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/opt/_FemtetWithNX/update_model.py +26 -19
- pyfemtet-0.3.0/pyfemtet/opt/__init__.py +2 -0
- pyfemtet-0.3.0/pyfemtet/opt/_optimizer.py +241 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/opt/base.py +682 -314
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/opt/interface.py +149 -179
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/opt/monitor.py +151 -97
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyproject.toml +8 -5
- pyfemtet-0.2.2/pyfemtet/__init__.py +0 -1
- pyfemtet-0.2.2/pyfemtet/_opt/_NX_Femtet.py +0 -68
- pyfemtet-0.2.2/pyfemtet/_opt/_SimplestUI.py +0 -91
- pyfemtet-0.2.2/pyfemtet/_opt/visualization/ProcessMonitor.py +0 -127
- pyfemtet-0.2.2/pyfemtet/_opt/visualization/_dash.py +0 -212
- pyfemtet-0.2.2/pyfemtet/_opt/visualization/_visualization.py +0 -282
- pyfemtet-0.2.2/pyfemtet/_opt/visualization/_visualizationNameSpace.py +0 -269
- pyfemtet-0.2.2/pyfemtet/opt/__init__.py +0 -6
- pyfemtet-0.2.2/pyfemtet/opt/core.py +0 -143
- pyfemtet-0.2.2/pyfemtet/opt/optimizer.py +0 -241
- pyfemtet-0.2.2/pyfemtet/tools/DispatchUtils.py +0 -270
- pyfemtet-0.2.2/pyfemtet/tools/__init__.py +0 -57
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/LICENSE +0 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/README.md +0 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.femprj +0 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.prt +0 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/gau_ex08_parametric.femprj +0 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/her_ex40_parametric.femprj +0 -0
- {pyfemtet-0.2.2 → pyfemtet-0.3.0}/pyfemtet/FemtetPJTSample/wat_ex14_parametric.femprj +0 -0
- {pyfemtet-0.2.2/pyfemtet/_opt → pyfemtet-0.3.0/pyfemtet/_old}/_SW_Femtet.py +0 -0
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyfemtet
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Design parameter optimization using Femtet.
|
|
5
5
|
Home-page: https://github.com/pyfemtet/pyfemtet
|
|
6
6
|
License: BSD-3-Clause
|
|
7
7
|
Author: kazuma.naito
|
|
8
8
|
Author-email: kazuma.naito@murata.com
|
|
9
|
-
Requires-Python: >=3.9,<3.
|
|
9
|
+
Requires-Python: >=3.9,<3.13
|
|
10
10
|
Classifier: License :: OSI Approved :: BSD License
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
-
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Requires-Dist: dash (>=2.14.2,<3.0.0)
|
|
17
17
|
Requires-Dist: dash-bootstrap-components (>=1.5.0,<2.0.0)
|
|
18
|
+
Requires-Dist: dask (>=2023.12.1,<2024.0.0)
|
|
19
|
+
Requires-Dist: distributed (>=2023.12.1,<2024.0.0)
|
|
18
20
|
Requires-Dist: femtetutils (>=1.0.0,<2.0.0)
|
|
19
21
|
Requires-Dist: numpy (>=1.26.2,<2.0.0)
|
|
20
22
|
Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
|
|
@@ -23,7 +25,6 @@ Requires-Dist: pandas (>=2.1.3,<3.0.0)
|
|
|
23
25
|
Requires-Dist: plotly (>=5.18.0,<6.0.0)
|
|
24
26
|
Requires-Dist: psutil (>=5.9.6,<6.0.0)
|
|
25
27
|
Requires-Dist: pywin32 (>=306,<307)
|
|
26
|
-
Requires-Dist: ray (>=2.8.1,<3.0.0)
|
|
27
28
|
Requires-Dist: scipy (>=1.11.4,<2.0.0)
|
|
28
29
|
Requires-Dist: tqdm (>=4.66.1,<5.0.0)
|
|
29
30
|
Project-URL: Repository, https://github.com/pyfemtet/pyfemtet
|
|
@@ -10,7 +10,8 @@ Femtet にインポートして最適化を行います。
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
|
-
from pyfemtet.opt import
|
|
13
|
+
from pyfemtet.opt import FEMOpt, OptunaOptimizer
|
|
14
|
+
from pyfemtet.opt.interface import FemtetWithNXInterface
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
here, me = os.path.split(__file__)
|
|
@@ -33,7 +34,7 @@ def volume(Femtet):
|
|
|
33
34
|
return ret
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
def C_minus_B(_,
|
|
37
|
+
def C_minus_B(_, opt):
|
|
37
38
|
"""C 寸法と B 寸法の差を計算します。
|
|
38
39
|
|
|
39
40
|
拘束関数の第一引数は Femtet インスタンスである必要がありますが、
|
|
@@ -44,11 +45,11 @@ def C_minus_B(_, femopt):
|
|
|
44
45
|
A = Femtet.GetVariableValue('A')
|
|
45
46
|
|
|
46
47
|
pyfemtet.opt では目的関数・拘束関数の第二引数以降に任意の変数を設定できます。
|
|
47
|
-
この例では、第二引数に
|
|
48
|
+
この例では、第二引数に FEMOpt のメンバー変数 opt を取り、
|
|
48
49
|
そのメソッド get_parameter() を用いて設計変数を取得しています。
|
|
49
50
|
|
|
50
51
|
"""
|
|
51
|
-
A, B, C =
|
|
52
|
+
A, B, C = opt.get_parameter('values')
|
|
52
53
|
return C - B
|
|
53
54
|
|
|
54
55
|
|
|
@@ -61,8 +62,14 @@ if __name__ == '__main__':
|
|
|
61
62
|
femprj_path='NX_ex01.femprj',
|
|
62
63
|
)
|
|
63
64
|
|
|
65
|
+
opt = OptunaOptimizer(
|
|
66
|
+
sampler_kwargs=dict(
|
|
67
|
+
n_startup_trials=5,
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
64
71
|
# 最適化処理を行うオブジェクトに連携オブジェクトを紐づけ
|
|
65
|
-
femopt =
|
|
72
|
+
femopt = FEMOpt(fem=fem, opt=opt)
|
|
66
73
|
|
|
67
74
|
# 設計変数の設定
|
|
68
75
|
femopt.add_parameter('A', 10, lower_bound=1, upper_bound=59)
|
|
@@ -70,7 +77,7 @@ if __name__ == '__main__':
|
|
|
70
77
|
femopt.add_parameter('C', 20, lower_bound=5, upper_bound=59)
|
|
71
78
|
|
|
72
79
|
# 拘束関数の設定
|
|
73
|
-
femopt.add_constraint(C_minus_B, 'C>B', lower_bound=1, args=femopt)
|
|
80
|
+
femopt.add_constraint(C_minus_B, 'C>B', lower_bound=1, args=femopt.opt)
|
|
74
81
|
|
|
75
82
|
# 目的関数の設定
|
|
76
83
|
femopt.add_objective(disp, name='変位', direction=0)
|
|
@@ -78,4 +85,4 @@ if __name__ == '__main__':
|
|
|
78
85
|
|
|
79
86
|
# 最適化の実行
|
|
80
87
|
femopt.set_random_seed(42)
|
|
81
|
-
femopt.main(n_trials=20,
|
|
88
|
+
femopt.main(n_trials=20, n_parallel=3)
|
|
@@ -4,8 +4,8 @@ gau_ex08_parametric.femprj に対し磁場解析を行い、
|
|
|
4
4
|
自己インダクタンスを特定の値にする
|
|
5
5
|
有限長さソレノイドコイルの寸法を探索します。
|
|
6
6
|
"""
|
|
7
|
-
|
|
8
|
-
from pyfemtet.opt import
|
|
7
|
+
from optuna.integration.botorch import BoTorchSampler
|
|
8
|
+
from pyfemtet.opt import FEMOpt, OptunaOptimizer
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def inductance(Femtet):
|
|
@@ -28,19 +28,30 @@ def inductance(Femtet):
|
|
|
28
28
|
|
|
29
29
|
if __name__ == '__main__':
|
|
30
30
|
|
|
31
|
+
# 最適化手法を定義するオブジェクトを用意
|
|
32
|
+
# BoTorch ライブラリを使わない場合、このブロックをコメントアウトし、
|
|
33
|
+
# opt = None としてください。
|
|
34
|
+
opt = OptunaOptimizer(
|
|
35
|
+
sampler_class=BoTorchSampler,
|
|
36
|
+
sampler_kwargs=dict(
|
|
37
|
+
consider_running_trials=True,
|
|
38
|
+
n_startup_trials=5,
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
|
|
31
42
|
# 最適化処理を行うオブジェクトを用意
|
|
32
|
-
femopt =
|
|
43
|
+
femopt = FEMOpt(opt=opt) # ここで起動している Femtet が紐づけされます
|
|
33
44
|
|
|
34
45
|
# 設計変数の登録
|
|
35
46
|
femopt.add_parameter("h", 3, lower_bound=1.5, upper_bound=6, memo='1巻きピッチ')
|
|
36
47
|
femopt.add_parameter("r", 5, lower_bound=1, upper_bound=10, memo='コイル半径')
|
|
37
48
|
femopt.add_parameter("n", 3, lower_bound=1, upper_bound=5, memo='コイル巻き数')
|
|
38
49
|
|
|
39
|
-
# インダクタンスが 0.
|
|
50
|
+
# インダクタンスが 0.1 uF に近づくようにゴールを設定
|
|
40
51
|
femopt.add_objective(
|
|
41
52
|
inductance, name='自己インダクタンス', direction=0.1e-06
|
|
42
53
|
)
|
|
43
54
|
|
|
44
55
|
# 最適化の実行
|
|
45
56
|
femopt.set_random_seed(42)
|
|
46
|
-
femopt.main(n_trials=20
|
|
57
|
+
femopt.main(n_trials=20)
|
|
@@ -3,8 +3,9 @@ from time import sleep
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from scipy.signal import find_peaks
|
|
5
5
|
from tqdm import tqdm
|
|
6
|
+
from optuna.integration.botorch import BoTorchSampler
|
|
6
7
|
|
|
7
|
-
from pyfemtet.opt import
|
|
8
|
+
from pyfemtet.opt import OptunaOptimizer, FEMOpt
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
|
|
@@ -49,8 +50,8 @@ class SParameterCalculator:
|
|
|
49
50
|
"""S に対して最初のピークを与える freq を計算します。"""
|
|
50
51
|
x = -np.array(self.S)
|
|
51
52
|
peaks, _ = find_peaks(x, height=None, threshold=None, distance=None, prominence=0.5, width=None, wlen=None, rel_height=0.5, plateau_size=None)
|
|
52
|
-
from pyfemtet.
|
|
53
|
-
if len(peaks)==0:
|
|
53
|
+
from pyfemtet.core import SolveError
|
|
54
|
+
if len(peaks) == 0:
|
|
54
55
|
raise SolveError('ピークが検出されませんでした。')
|
|
55
56
|
self.resonance_frequency = self.freq[peaks[0]]
|
|
56
57
|
self.minimum_S = self.S[peaks[0]]
|
|
@@ -71,7 +72,7 @@ class SParameterCalculator:
|
|
|
71
72
|
return f # GHz
|
|
72
73
|
|
|
73
74
|
|
|
74
|
-
def
|
|
75
|
+
def antenna_is_smaller_than_substrate(Femtet):
|
|
75
76
|
"""アンテナのサイズと基板のサイズの関係を計算します。
|
|
76
77
|
|
|
77
78
|
Femtet : マクロを使用するためのインスタンスです。詳しくは "Femtet マクロヘルプ / CFemtet クラス" をご覧ください。
|
|
@@ -86,7 +87,7 @@ def anntena_is_smaller_than_substrate(Femtet):
|
|
|
86
87
|
return Sx/2 - ant_r
|
|
87
88
|
|
|
88
89
|
|
|
89
|
-
def
|
|
90
|
+
def port_is_inside_antenna(Femtet):
|
|
90
91
|
"""給電ポートの位置とアンテナのサイズの関係を計算します。
|
|
91
92
|
|
|
92
93
|
Femtet : マクロを使用するためのインスタンスです。詳しくは "Femtet マクロヘルプ / CFemtet クラス" をご覧ください。
|
|
@@ -101,12 +102,25 @@ def port_is_inside_anntena(Femtet):
|
|
|
101
102
|
return ant_r - xf
|
|
102
103
|
|
|
103
104
|
|
|
104
|
-
if __name__=='__main__':
|
|
105
|
+
if __name__ == '__main__':
|
|
105
106
|
# S パラメータ計算用クラス
|
|
106
107
|
s = SParameterCalculator()
|
|
108
|
+
|
|
109
|
+
# 最適化手法を定義するオブジェクトを用意
|
|
110
|
+
# BoTorch ライブラリを使わない場合、このブロックをコメントアウトし、
|
|
111
|
+
# opt = None としてください。
|
|
112
|
+
opt = OptunaOptimizer(
|
|
113
|
+
sampler_class=BoTorchSampler,
|
|
114
|
+
sampler_kwargs=dict(
|
|
115
|
+
consider_running_trials=True,
|
|
116
|
+
n_startup_trials=5,
|
|
117
|
+
)
|
|
118
|
+
)
|
|
107
119
|
|
|
108
120
|
# 最適化処理を行うオブジェクトを用意
|
|
109
|
-
femopt =
|
|
121
|
+
femopt = FEMOpt(
|
|
122
|
+
opt=opt,
|
|
123
|
+
) # ここで起動している Femtet が紐づけされます
|
|
110
124
|
|
|
111
125
|
# 設計変数の設定
|
|
112
126
|
femopt.add_parameter('ant_r', 10, 5, 20, memo='円形アンテナの半径')
|
|
@@ -114,11 +128,11 @@ if __name__=='__main__':
|
|
|
114
128
|
femopt.add_parameter('xf', 5, 1, 20, memo='給電ポートの偏心量')
|
|
115
129
|
|
|
116
130
|
# 拘束の設定
|
|
117
|
-
femopt.add_constraint(
|
|
118
|
-
femopt.add_constraint(
|
|
131
|
+
femopt.add_constraint(antenna_is_smaller_than_substrate, 'アンテナサイズ', lower_bound=1)
|
|
132
|
+
femopt.add_constraint(port_is_inside_antenna, 'ポート位置', lower_bound=1)
|
|
119
133
|
|
|
120
134
|
# 目的の設定
|
|
121
135
|
femopt.add_objective(s.get_resonance_frequency, '第一共振周波数(GHz)', direction=3.0)
|
|
122
136
|
|
|
123
137
|
femopt.set_random_seed(42)
|
|
124
|
-
femopt.main(
|
|
138
|
+
femopt.main(n_trials=20)
|
|
@@ -6,10 +6,10 @@ wat_ex14_parametric.femprj に対し熱伝導解析を行い、
|
|
|
6
6
|
基板寸法・チップ配置寸法を探索します。
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from pyfemtet.opt import
|
|
9
|
+
from pyfemtet.opt import FEMOpt
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
def max_temperature(Femtet, body_name):
|
|
13
13
|
"""Femtet の解析結果からチップの最高温度を取得します。
|
|
14
14
|
|
|
15
15
|
Femtet : マクロを使用するためのインスタンスです。詳しくは "Femtet マクロヘルプ / CFemtet クラス" をご覧ください。
|
|
@@ -21,9 +21,9 @@ def maxtemp(Femtet, body_name):
|
|
|
21
21
|
"""
|
|
22
22
|
Gogh = Femtet.Gogh
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
temp, _, _ = Gogh.Watt.GetTemp_py(body_name)
|
|
25
25
|
|
|
26
|
-
return
|
|
26
|
+
return temp # degree
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def substrate_size(Femtet):
|
|
@@ -45,15 +45,15 @@ def substrate_size(Femtet):
|
|
|
45
45
|
if __name__ == '__main__':
|
|
46
46
|
|
|
47
47
|
# 最適化処理を行うオブジェクトを用意
|
|
48
|
-
femopt =
|
|
48
|
+
femopt = FEMOpt()
|
|
49
49
|
|
|
50
50
|
# 設計変数の設定
|
|
51
51
|
femopt.add_parameter("substrate_w", 40, lower_bound=22, upper_bound=40, memo='基板サイズ X')
|
|
52
52
|
femopt.add_parameter("substrate_d", 60, lower_bound=33, upper_bound=60, memo='基板サイズ Y')
|
|
53
53
|
|
|
54
54
|
# 目的関数の設定
|
|
55
|
-
femopt.add_objective(
|
|
56
|
-
femopt.add_objective(
|
|
55
|
+
femopt.add_objective(max_temperature, name='メインチップ温度', args=('MAINCHIP',))
|
|
56
|
+
femopt.add_objective(max_temperature, name='サブチップ温度', args=('SUBCHIP',))
|
|
57
57
|
femopt.add_objective(substrate_size, name='基板サイズ')
|
|
58
58
|
|
|
59
59
|
# 最適化の実行
|
|
@@ -6,10 +6,10 @@ wat_ex14_parametric.femprj に対し熱伝導解析を行い、
|
|
|
6
6
|
基板寸法・チップ配置寸法を探索します。
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from pyfemtet.opt import
|
|
9
|
+
from pyfemtet.opt import FEMOpt
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def
|
|
12
|
+
def max_temperature(Femtet, body_name):
|
|
13
13
|
"""Femtet の解析結果からチップの最高温度を取得します。
|
|
14
14
|
|
|
15
15
|
Femtet : マクロを使用するためのインスタンスです。詳しくは "Femtet マクロヘルプ / CFemtet クラス" をご覧ください。
|
|
@@ -21,9 +21,9 @@ def maxtemp(Femtet, body_name):
|
|
|
21
21
|
"""
|
|
22
22
|
Gogh = Femtet.Gogh
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
temp, _, _ = Gogh.Watt.GetTemp_py(body_name)
|
|
25
25
|
|
|
26
|
-
return
|
|
26
|
+
return temp # degree
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def substrate_size(Femtet):
|
|
@@ -45,15 +45,15 @@ def substrate_size(Femtet):
|
|
|
45
45
|
if __name__ == '__main__':
|
|
46
46
|
|
|
47
47
|
# 最適化処理を行うオブジェクトを用意
|
|
48
|
-
femopt =
|
|
48
|
+
femopt = FEMOpt()
|
|
49
49
|
|
|
50
50
|
# 設計変数の設定
|
|
51
51
|
femopt.add_parameter("substrate_w", 40, lower_bound=22, upper_bound=40, memo='基板サイズ X')
|
|
52
52
|
femopt.add_parameter("substrate_d", 60, lower_bound=33, upper_bound=60, memo='基板サイズ Y')
|
|
53
53
|
|
|
54
54
|
# 目的関数の設定
|
|
55
|
-
femopt.add_objective(
|
|
56
|
-
femopt.add_objective(
|
|
55
|
+
femopt.add_objective(max_temperature, name='メインチップ温度', args=('MAINCHIP',))
|
|
56
|
+
femopt.add_objective(max_temperature, name='サブチップ温度', args=('SUBCHIP',))
|
|
57
57
|
femopt.add_objective(substrate_size, name='基板サイズ')
|
|
58
58
|
|
|
59
59
|
# 最適化の実行
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class ModelError(Exception):
|
|
2
|
+
"""Exception raised for errors in the model update.
|
|
3
|
+
|
|
4
|
+
If this exception is thrown during an optimization calculation, the process attempts to skip that attempt if possible.
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MeshError(Exception):
|
|
11
|
+
"""Exception raised for errors in the meshing.
|
|
12
|
+
|
|
13
|
+
If this exception is thrown during an optimization calculation, the process attempts to skip that attempt if possible.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SolveError(Exception):
|
|
20
|
+
"""Exception raised for errors in the solver.
|
|
21
|
+
|
|
22
|
+
If this exception is thrown during an optimization calculation, the process attempts to skip that attempt if possible.
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# class PostError(Exception):
|
|
29
|
+
# pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# class FEMCrash(Exception):
|
|
33
|
+
# pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FemtetAutomationError(Exception):
|
|
37
|
+
"""Exception raised for errors in automating Femtet."""
|
|
38
|
+
pass
|