pyfemtet 0.4.2__tar.gz → 0.4.3__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.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/PKG-INFO +1 -1
- pyfemtet-0.4.3/pyfemtet/FemtetPJTSample/her_ex40_parametric.py +148 -0
- pyfemtet-0.4.3/pyfemtet/__init__.py +1 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/cad_ex01_NX.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/cad_ex01_NX.prt +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/cad_ex01_NX.py +132 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/cad_ex01_SW.SLDPRT +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/cad_ex01_SW.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/cad_ex01_SW.py +132 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/gal_ex58_parametric.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/gal_ex58_parametric.py +75 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/gau_ex08_parametric.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/gau_ex08_parametric.py +59 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/her_ex40_parametric.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/her_ex40_parametric.py +137 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/paswat_ex1_parametric.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/paswat_ex1_parametric.py +61 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/paswat_ex1_parametric_parallel.py +62 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/wat_ex14_parametric.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample/wat_ex14_parametric.py +59 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/cad_ex01_NX_jp.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/cad_ex01_NX_jp.py +126 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/cad_ex01_SW_jp.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/cad_ex01_SW_jp.py +126 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/gal_ex58_parametric_jp.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/gal_ex58_parametric_jp.py +71 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/gau_ex08_parametric_jp.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/gau_ex08_parametric_jp.py +58 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/her_ex40_parametric_jp.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/her_ex40_parametric_jp.py +137 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/paswat_ex1_parametric_jp.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/paswat_ex1_parametric_jp.py +59 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/paswat_ex1_parametric_parallel_jp.py +60 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/wat_ex14_parametric_jp.femprj +0 -0
- pyfemtet-0.4.3/pyfemtet/opt/femprj_sample_jp/wat_ex14_parametric_jp.py +57 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/interface/_femtet.py +5 -1
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/interface/_femtet_with_nx/_interface.py +2 -8
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/interface/_femtet_with_sldworks.py +2 -8
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyproject.toml +1 -1
- pyfemtet-0.4.2/pyfemtet/__init__.py +0 -1
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/LICENSE +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/README.md +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.femprj +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.prt +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/NX_ex01/NX_ex01.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/Sldworks_ex01/Sldworks_ex01.SLDPRT +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/Sldworks_ex01/Sldworks_ex01.femprj +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/Sldworks_ex01/Sldworks_ex01.py +0 -0
- /pyfemtet-0.4.2/pyfemtet/FemtetPJTSample/her_ex40_parametric.py → /pyfemtet-0.4.3/pyfemtet/FemtetPJTSample/_her_ex40_parametric.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/gau_ex08_parametric.femprj +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/gau_ex08_parametric.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/her_ex40_parametric.femprj +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/wat_ex14_parallel_parametric.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/wat_ex14_parametric.femprj +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/FemtetPJTSample/wat_ex14_parametric.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/core.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/dispatch_extensions.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/logger.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/__init__.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/_femopt.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/_femopt_core.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/interface/__init__.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/interface/_base.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/interface/_femtet_with_nx/__init__.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/interface/_femtet_with_nx/update_model.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/opt/__init__.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/opt/_base.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/opt/_optuna.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/visualization/__init__.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/visualization/_graphs.py +0 -0
- {pyfemtet-0.4.2 → pyfemtet-0.4.3}/pyfemtet/opt/visualization/_monitor.py +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Single-objective optimization: Resonant frequency of a circular patch antenna
|
|
2
|
+
|
|
3
|
+
Using Femtet’s electromagnetic wave analysis solver,
|
|
4
|
+
we explain an example of setting the resonant frequency
|
|
5
|
+
of a circular patch antenna to a specific value.
|
|
6
|
+
"""
|
|
7
|
+
from time import sleep
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from scipy.signal import find_peaks
|
|
11
|
+
from tqdm import tqdm
|
|
12
|
+
from optuna.integration.botorch import BoTorchSampler
|
|
13
|
+
|
|
14
|
+
from pyfemtet.opt import OptunaOptimizer, FEMOpt
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SParameterCalculator:
|
|
18
|
+
"""This class is for calculating S-parameters and resonance frequencies."""
|
|
19
|
+
|
|
20
|
+
def __init__(self):
|
|
21
|
+
self.freq = []
|
|
22
|
+
self.S = []
|
|
23
|
+
self.interpolated_function = None
|
|
24
|
+
self.resonance_frequency = None
|
|
25
|
+
self.minimum_S = None
|
|
26
|
+
|
|
27
|
+
def get_result_from_Femtet(self, Femtet):
|
|
28
|
+
"""Obtain the relationship between frequency and S-parameter from the Femtet analysis results."""
|
|
29
|
+
|
|
30
|
+
# Preparation
|
|
31
|
+
Femtet.OpenCurrentResult(True)
|
|
32
|
+
Gogh = Femtet.Gogh
|
|
33
|
+
|
|
34
|
+
# Obtain the frequency and S(1,1) for each mode
|
|
35
|
+
mode = 0
|
|
36
|
+
freq_list = []
|
|
37
|
+
dB_S_list = []
|
|
38
|
+
for mode in tqdm(range(Gogh.Hertz.nMode), 'Obtaining frequency and S-parameter'):
|
|
39
|
+
# Femtet result screen mode settings
|
|
40
|
+
Gogh.Hertz.Mode = mode
|
|
41
|
+
sleep(0.01)
|
|
42
|
+
# Get frequency
|
|
43
|
+
freq = Gogh.Hertz.GetFreq().Real
|
|
44
|
+
# Get S-parameters
|
|
45
|
+
comp_S = Gogh.Hertz.GetSMatrix(0, 0)
|
|
46
|
+
norm = np.linalg.norm((comp_S.Real, comp_S.Imag))
|
|
47
|
+
dB_S = 20 * np.log10(norm)
|
|
48
|
+
# Get results
|
|
49
|
+
freq_list.append(freq)
|
|
50
|
+
dB_S_list.append(dB_S)
|
|
51
|
+
self.freq = freq_list
|
|
52
|
+
self.S = dB_S_list
|
|
53
|
+
|
|
54
|
+
def calc_resonance_frequency(self):
|
|
55
|
+
"""Compute the frequency that gives the first peak for S-parameter."""
|
|
56
|
+
x = -np.array(self.S)
|
|
57
|
+
peaks, _ = find_peaks(x, height=None, threshold=None, distance=None, prominence=0.5, width=None, wlen=None, rel_height=0.5, plateau_size=None)
|
|
58
|
+
from pyfemtet.core import SolveError
|
|
59
|
+
if len(peaks) == 0:
|
|
60
|
+
raise SolveError('No peaks detected.')
|
|
61
|
+
self.resonance_frequency = self.freq[peaks[0]]
|
|
62
|
+
self.minimum_S = self.S[peaks[0]]
|
|
63
|
+
|
|
64
|
+
def get_resonance_frequency(self, Femtet):
|
|
65
|
+
"""Calculate the resonant frequency.
|
|
66
|
+
|
|
67
|
+
Note:
|
|
68
|
+
The objective or constraint function
|
|
69
|
+
must take a Femtet as its first argument
|
|
70
|
+
and must return a single float.
|
|
71
|
+
|
|
72
|
+
Params:
|
|
73
|
+
Femtet: An instance for using Femtet macros. For more information, see "Femtet Macro Help / CFemtet Class".
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
float: A resonance frequency.
|
|
77
|
+
"""
|
|
78
|
+
self.get_result_from_Femtet(Femtet)
|
|
79
|
+
self.calc_resonance_frequency()
|
|
80
|
+
f = self.resonance_frequency * 1e-9
|
|
81
|
+
return f # GHz
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def antenna_is_smaller_than_substrate(Femtet):
|
|
85
|
+
"""Calculate the relationship between antenna size and board size.
|
|
86
|
+
|
|
87
|
+
This function is used to constrain the model
|
|
88
|
+
from breaking down while changing parameters.
|
|
89
|
+
|
|
90
|
+
Params:
|
|
91
|
+
Femtet: An instance for using Femtet macros.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
float: Difference between the board size and antenna size. Must be equal to or grater than 1 mm.
|
|
95
|
+
"""
|
|
96
|
+
ant_r = Femtet.GetVariableValue('ant_r')
|
|
97
|
+
Sx = Femtet.GetVariableValue('sx')
|
|
98
|
+
return Sx/2 - ant_r
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def port_is_inside_antenna(Femtet):
|
|
102
|
+
"""Calculate the relationship between the feed port location and antenna size.
|
|
103
|
+
|
|
104
|
+
This function is used to constrain the model
|
|
105
|
+
from breaking down while changing parameters.
|
|
106
|
+
|
|
107
|
+
Params:
|
|
108
|
+
Femtet: An instance for using Femtet macros.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
float: Difference between the antenna edge and the position of the feed port. Must be equal to or grater than 1 mm.
|
|
112
|
+
"""
|
|
113
|
+
ant_r = Femtet.GetVariableValue('ant_r')
|
|
114
|
+
xf = Femtet.GetVariableValue('xf')
|
|
115
|
+
return ant_r - xf
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
if __name__ == '__main__':
|
|
119
|
+
# Define the object for calculating S-parameters and resonance frequencies.
|
|
120
|
+
s = SParameterCalculator()
|
|
121
|
+
|
|
122
|
+
# Define mathematical optimization object.
|
|
123
|
+
opt = OptunaOptimizer(
|
|
124
|
+
sampler_class=BoTorchSampler,
|
|
125
|
+
sampler_kwargs=dict(
|
|
126
|
+
n_startup_trials=10,
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Define FEMOpt object (This process integrates mathematical optimization and FEM.).
|
|
131
|
+
femopt = FEMOpt(opt=opt)
|
|
132
|
+
|
|
133
|
+
# Add design variables (Use variable names set in Femtet) to the optimization problem.
|
|
134
|
+
femopt.add_parameter('ant_r', 10, 5, 20)
|
|
135
|
+
femopt.add_parameter('sx', 50, 40, 60)
|
|
136
|
+
femopt.add_parameter('xf', 5, 1, 20)
|
|
137
|
+
|
|
138
|
+
# Add constraint to the optimization problem.
|
|
139
|
+
femopt.add_constraint(antenna_is_smaller_than_substrate, 'board_antenna_clearance', lower_bound=1)
|
|
140
|
+
femopt.add_constraint(port_is_inside_antenna, 'antenna_port_clearance', lower_bound=1)
|
|
141
|
+
|
|
142
|
+
# Add objective to the optimization problem.
|
|
143
|
+
# The target frequency is 3 GHz.
|
|
144
|
+
femopt.add_objective(s.get_resonance_frequency, 'First_resonant_frequency(GHz)', direction=3.0)
|
|
145
|
+
|
|
146
|
+
femopt.set_random_seed(42)
|
|
147
|
+
femopt.optimize(n_trials=20)
|
|
148
|
+
femopt.terminate_all()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.3"
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""External CAD (NX) Integration
|
|
2
|
+
|
|
3
|
+
Using Femtet's stress analysis solver and Siemens' CAD software NX,
|
|
4
|
+
design a lightweight and high-strength H-shaped beam.
|
|
5
|
+
|
|
6
|
+
As a preliminary step, please perform the following procedures:
|
|
7
|
+
- Install NX
|
|
8
|
+
- Create a C:\temp folder
|
|
9
|
+
- Note: NX will save a .x_t file in this folder.
|
|
10
|
+
- Place the following files in the same folder:
|
|
11
|
+
- cad_ex01_NX.py (this file)
|
|
12
|
+
- cad_ex01_NX.prt
|
|
13
|
+
- cad_ex01_NX.femprj
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
from win32com.client import constants
|
|
19
|
+
|
|
20
|
+
from pyfemtet.opt import FEMOpt
|
|
21
|
+
from pyfemtet.opt.interface import FemtetWithNXInterface
|
|
22
|
+
from pyfemtet.core import ModelError
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
here, me = os.path.split(__file__)
|
|
26
|
+
os.chdir(here)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def von_mises(Femtet):
|
|
30
|
+
"""Obtain the maximum von Mises stress of the model.
|
|
31
|
+
|
|
32
|
+
Note:
|
|
33
|
+
The objective or constraint function should take Femtet
|
|
34
|
+
as its first argument and return a float as the output.
|
|
35
|
+
|
|
36
|
+
Warning:
|
|
37
|
+
CAD integration may assign boundary conditions to unintended locations.
|
|
38
|
+
|
|
39
|
+
In this example, if the boundary conditions are assigned as intended,
|
|
40
|
+
the maximum z displacement is always negative.
|
|
41
|
+
If the maximum displacement is not negative, it is assumed that
|
|
42
|
+
boundary condition assignment has failed.
|
|
43
|
+
Then this function raises a ModelError.
|
|
44
|
+
|
|
45
|
+
If a ModelError, MeshError, or SolveError occurs during optimization,
|
|
46
|
+
the optimization process considers the attempt a failure and skips to
|
|
47
|
+
the next trial.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# Simple check for the correctness of boundary conditions.
|
|
51
|
+
dx, dy, dz = Femtet.Gogh.Galileo.GetMaxDisplacement_py()
|
|
52
|
+
if dz >= 0:
|
|
53
|
+
raise ModelError('Assigning unintended boundary conditions.')
|
|
54
|
+
|
|
55
|
+
# Von Mises stress calculation.
|
|
56
|
+
Gogh = Femtet.Gogh
|
|
57
|
+
Gogh.Galileo.Potential = constants.GALILEO_VON_MISES_C
|
|
58
|
+
succeed, (x, y, z), mises = Gogh.Galileo.GetMAXPotentialPoint_py(constants.CMPX_REAL_C)
|
|
59
|
+
|
|
60
|
+
return mises
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def mass(Femtet):
|
|
64
|
+
"""Obtain model mass."""
|
|
65
|
+
return Femtet.Gogh.Galileo.GetMass('H_beam')
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def C_minus_B(Femtet, opt):
|
|
69
|
+
"""Calculate the difference between C and B dimensions.
|
|
70
|
+
|
|
71
|
+
Another example uses the following snippet to access design variables:
|
|
72
|
+
|
|
73
|
+
A = Femtet.GetVariableValue('A')
|
|
74
|
+
|
|
75
|
+
However, when performing CAD integration, this method does not work
|
|
76
|
+
because the variables are not set in the .femprj file.
|
|
77
|
+
|
|
78
|
+
In CAD integration, design variables are obtained in the following way.
|
|
79
|
+
|
|
80
|
+
# How to obtain a dictionary with the variable names of parameters
|
|
81
|
+
# added by add_parameter() as keys.
|
|
82
|
+
params: dict = opt.get_parameter()
|
|
83
|
+
A = params['A']
|
|
84
|
+
|
|
85
|
+
Or
|
|
86
|
+
|
|
87
|
+
# How to obtain an array of values of parameters added in the order
|
|
88
|
+
# by add_parameter().
|
|
89
|
+
values: np.ndarray = opt.get_parameter('values')
|
|
90
|
+
A, B, C = values
|
|
91
|
+
|
|
92
|
+
Objective functions and constraint functions can take arbitrary variables
|
|
93
|
+
after the first argument.
|
|
94
|
+
The FEMOpt member variable `opt` has a method called get_parameter().
|
|
95
|
+
This method allows you to retrieve design variables added by add_parameter().
|
|
96
|
+
By taking `opt` as the second argument, you can execute get_parameter()
|
|
97
|
+
within the objective or constraint function to retrieve design variables.
|
|
98
|
+
"""
|
|
99
|
+
A, B, C = opt.get_parameter('values')
|
|
100
|
+
return C - B
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == '__main__':
|
|
104
|
+
|
|
105
|
+
# Initialize NX-Femtet integration object.
|
|
106
|
+
# At this point, Python is connected to the Femtet.
|
|
107
|
+
fem = FemtetWithNXInterface(
|
|
108
|
+
prt_path='cad_ex01_NX.prt',
|
|
109
|
+
open_result_with_gui=False, # To calculate von Mises stress, set this argument to False. See Femtet Macro Help.
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Initialize the FEMOpt object.
|
|
113
|
+
# (establish connection between the optimization problem and Femtet)
|
|
114
|
+
femopt = FEMOpt(fem=fem)
|
|
115
|
+
|
|
116
|
+
# Add design variables to the optimization problem.
|
|
117
|
+
# (Specify the variables registered in the femprj file.)
|
|
118
|
+
femopt.add_parameter('A', 10, lower_bound=1, upper_bound=59)
|
|
119
|
+
femopt.add_parameter('B', 10, lower_bound=1, upper_bound=40)
|
|
120
|
+
femopt.add_parameter('C', 20, lower_bound=5, upper_bound=59)
|
|
121
|
+
|
|
122
|
+
# Add the constraint function to the optimization problem.
|
|
123
|
+
femopt.add_constraint(C_minus_B, 'C>B', lower_bound=1, args=femopt.opt)
|
|
124
|
+
|
|
125
|
+
# Add the objective function to the optimization problem.
|
|
126
|
+
femopt.add_objective(von_mises, name='von Mises (Pa)')
|
|
127
|
+
femopt.add_objective(mass, name='mass (kg)')
|
|
128
|
+
|
|
129
|
+
# Run optimization.
|
|
130
|
+
femopt.set_random_seed(42)
|
|
131
|
+
femopt.optimize(n_trials=20)
|
|
132
|
+
femopt.terminate_all()
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""External CAD (SOLIDWORKS) Integration
|
|
2
|
+
|
|
3
|
+
Using Femtet's stress analysis solver and Dassault Systemes' CAD software SOLIDWORKS,
|
|
4
|
+
design a lightweight and high-strength H-shaped beam.
|
|
5
|
+
|
|
6
|
+
As a preliminary step, please perform the following procedures:
|
|
7
|
+
- Install SOLIDWORKS
|
|
8
|
+
- Create a C:\temp folder
|
|
9
|
+
- Note: SOLIDWORKS will save a .x_t file in this folder.
|
|
10
|
+
- Place the following files in the same folder:
|
|
11
|
+
- cad_ex01_SW.py (this file)
|
|
12
|
+
- cad_ex01_SW.SLDPRT
|
|
13
|
+
- cad_ex01_SW.femprj
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
from win32com.client import constants
|
|
19
|
+
|
|
20
|
+
from pyfemtet.opt import FEMOpt
|
|
21
|
+
from pyfemtet.opt.interface import FemtetWithSolidworksInterface
|
|
22
|
+
from pyfemtet.core import ModelError
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
here, me = os.path.split(__file__)
|
|
26
|
+
os.chdir(here)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def von_mises(Femtet):
|
|
30
|
+
"""Obtain the maximum von Mises stress of the model.
|
|
31
|
+
|
|
32
|
+
Note:
|
|
33
|
+
The objective or constraint function should take Femtet
|
|
34
|
+
as its first argument and return a float as the output.
|
|
35
|
+
|
|
36
|
+
Warning:
|
|
37
|
+
CAD integration may assign boundary conditions to unintended locations.
|
|
38
|
+
|
|
39
|
+
In this example, if the boundary conditions are assigned as intended,
|
|
40
|
+
the maximum z displacement is always negative.
|
|
41
|
+
If the maximum displacement is not negative, it is assumed that
|
|
42
|
+
boundary condition assignment has failed.
|
|
43
|
+
Then this function raises a ModelError.
|
|
44
|
+
|
|
45
|
+
If a ModelError, MeshError, or SolveError occurs during optimization,
|
|
46
|
+
the optimization process considers the attempt a failure and skips to
|
|
47
|
+
the next trial.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# Simple check for the correctness of boundary conditions.
|
|
51
|
+
dx, dy, dz = Femtet.Gogh.Galileo.GetMaxDisplacement_py()
|
|
52
|
+
if dz >= 0:
|
|
53
|
+
raise ModelError('Assigning unintended boundary conditions.')
|
|
54
|
+
|
|
55
|
+
# Von Mises stress calculation.
|
|
56
|
+
Gogh = Femtet.Gogh
|
|
57
|
+
Gogh.Galileo.Potential = constants.GALILEO_VON_MISES_C
|
|
58
|
+
succeed, (x, y, z), mises = Gogh.Galileo.GetMAXPotentialPoint_py(constants.CMPX_REAL_C)
|
|
59
|
+
|
|
60
|
+
return mises
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def mass(Femtet):
|
|
64
|
+
"""Obtain model mass."""
|
|
65
|
+
return Femtet.Gogh.Galileo.GetMass('H_beam')
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def C_minus_B(Femtet, opt):
|
|
69
|
+
"""Calculate the difference between C and B dimensions.
|
|
70
|
+
|
|
71
|
+
Another example uses the following snippet to access design variables:
|
|
72
|
+
|
|
73
|
+
A = Femtet.GetVariableValue('A')
|
|
74
|
+
|
|
75
|
+
However, when performing CAD integration, this method does not work
|
|
76
|
+
because the variables are not set in the .femprj file.
|
|
77
|
+
|
|
78
|
+
In CAD integration, design variables are obtained in the following way.
|
|
79
|
+
|
|
80
|
+
# How to obtain a dictionary with the variable names of parameters
|
|
81
|
+
# added by add_parameter() as keys.
|
|
82
|
+
params: dict = opt.get_parameter()
|
|
83
|
+
A = params['A']
|
|
84
|
+
|
|
85
|
+
Or
|
|
86
|
+
|
|
87
|
+
# How to obtain an array of values of parameters added in the order
|
|
88
|
+
# by add_parameter().
|
|
89
|
+
values: np.ndarray = opt.get_parameter('values')
|
|
90
|
+
A, B, C = values
|
|
91
|
+
|
|
92
|
+
Objective functions and constraint functions can take arbitrary variables
|
|
93
|
+
after the first argument.
|
|
94
|
+
The FEMOpt member variable `opt` has a method called get_parameter().
|
|
95
|
+
This method allows you to retrieve design variables added by add_parameter().
|
|
96
|
+
By taking `opt` as the second argument, you can execute get_parameter()
|
|
97
|
+
within the objective or constraint function to retrieve design variables.
|
|
98
|
+
"""
|
|
99
|
+
A, B, C = opt.get_parameter('values')
|
|
100
|
+
return C - B
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == '__main__':
|
|
104
|
+
|
|
105
|
+
# Initialize NX-Femtet integration object.
|
|
106
|
+
# At this point, Python is connected to the Femtet.
|
|
107
|
+
fem = FemtetWithSolidworksInterface(
|
|
108
|
+
sldprt_path='cad_ex01_SW.SLDPRT',
|
|
109
|
+
open_result_with_gui=False, # To calculate von Mises stress, set this argument to False. See Femtet Macro Help.
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Initialize the FEMOpt object.
|
|
113
|
+
# (establish connection between the optimization problem and Femtet)
|
|
114
|
+
femopt = FEMOpt(fem=fem)
|
|
115
|
+
|
|
116
|
+
# Add design variables to the optimization problem.
|
|
117
|
+
# (Specify the variables registered in the femprj file.)
|
|
118
|
+
femopt.add_parameter('A', 10, lower_bound=1, upper_bound=59)
|
|
119
|
+
femopt.add_parameter('B', 10, lower_bound=1, upper_bound=40)
|
|
120
|
+
femopt.add_parameter('C', 20, lower_bound=5, upper_bound=59)
|
|
121
|
+
|
|
122
|
+
# Add the constraint function to the optimization problem.
|
|
123
|
+
femopt.add_constraint(C_minus_B, 'C>B', lower_bound=1, args=femopt.opt)
|
|
124
|
+
|
|
125
|
+
# Add the objective function to the optimization problem.
|
|
126
|
+
femopt.add_objective(von_mises, name='von Mises (Pa)')
|
|
127
|
+
femopt.add_objective(mass, name='mass (kg)')
|
|
128
|
+
|
|
129
|
+
# Run optimization.
|
|
130
|
+
femopt.set_random_seed(42)
|
|
131
|
+
femopt.optimize(n_trials=20)
|
|
132
|
+
femopt.terminate_all()
|
|
Binary file
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Single-objective optimization: bending with consideration for springback.
|
|
2
|
+
|
|
3
|
+
Using Femtet's stress analysis solver, we will determine the bending angle
|
|
4
|
+
to achieve the desired material bend angle with consideration for springback.
|
|
5
|
+
Elasto-plastic analysis is available in an optional package.
|
|
6
|
+
|
|
7
|
+
Corresponding project: gal_ex58_parametric.femprj
|
|
8
|
+
"""
|
|
9
|
+
import numpy as np
|
|
10
|
+
from win32com.client import constants
|
|
11
|
+
from optuna.integration.botorch import BoTorchSampler
|
|
12
|
+
|
|
13
|
+
from pyfemtet.opt import FEMOpt, OptunaOptimizer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def bending(Femtet):
|
|
17
|
+
"""Get the material bend angle.
|
|
18
|
+
|
|
19
|
+
Note:
|
|
20
|
+
The objective or constraint function should take Femtet
|
|
21
|
+
as its first argument and return a float as the output.
|
|
22
|
+
|
|
23
|
+
Params:
|
|
24
|
+
Femtet: This is an instance for manipulating Femtet with macros. For detailed information, please refer to "Femtet Macro Help".
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
float: material bend angle.
|
|
28
|
+
"""
|
|
29
|
+
Gogh = Femtet.Gogh
|
|
30
|
+
|
|
31
|
+
# Set the mode after unloading.
|
|
32
|
+
Gogh.Galileo.Mode = Gogh.Galileo.nMode - 1
|
|
33
|
+
|
|
34
|
+
# Obtain the displacement of the measurement target point.
|
|
35
|
+
Gogh.Galileo.Vector = constants.GALILEO_DISPLACEMENT_C
|
|
36
|
+
succeed, (x, y, z) = Gogh.Galileo.GetVectorAtPoint_py(200, 0, 0)
|
|
37
|
+
|
|
38
|
+
# Calculate the angle formed by the line segment
|
|
39
|
+
# connecting the bending origin (100, 0) and the
|
|
40
|
+
# deformed point with the X-axis.
|
|
41
|
+
bending_point = np.array((100, 0))
|
|
42
|
+
bended_point = np.array((200 + 1000 * x.Real, 1000 * z.Real))
|
|
43
|
+
dx, dz = bended_point - bending_point
|
|
44
|
+
degree = np.arctan2(-dz, dx)
|
|
45
|
+
|
|
46
|
+
return degree * 360 / (2*np.pi) # unit: degree
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == '__main__':
|
|
50
|
+
|
|
51
|
+
# Initialize the numerical optimization problem.
|
|
52
|
+
# (determine the optimization method)
|
|
53
|
+
opt = OptunaOptimizer(
|
|
54
|
+
sampler_class=BoTorchSampler,
|
|
55
|
+
sampler_kwargs=dict(
|
|
56
|
+
n_startup_trials=3,
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Initialize the FEMOpt object.
|
|
61
|
+
# (establish connection between the optimization problem and Femtet)
|
|
62
|
+
femopt = FEMOpt(opt=opt)
|
|
63
|
+
|
|
64
|
+
# Add design variables to the optimization problem.
|
|
65
|
+
# (Specify the variables registered in the femprj file.)
|
|
66
|
+
femopt.add_parameter("rot", 90, lower_bound=80, upper_bound=100)
|
|
67
|
+
|
|
68
|
+
# Add the objective function to the optimization problem.
|
|
69
|
+
# The target bending angle is 90 degrees.
|
|
70
|
+
femopt.add_objective(bending, name='final angle (degree)', direction=90)
|
|
71
|
+
|
|
72
|
+
# Run optimization.
|
|
73
|
+
femopt.set_random_seed(42)
|
|
74
|
+
femopt.optimize(n_trials=10)
|
|
75
|
+
femopt.terminate_all()
|
|
Binary file
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Single-objective optimization: Self-inductance of a finite-length helical coil.
|
|
2
|
+
|
|
3
|
+
Using Femtet's magnetic field analysis solver, design to achieve
|
|
4
|
+
the target value for the self-inductance of a finite-length helical coil.
|
|
5
|
+
|
|
6
|
+
Corresponding project: gau_ex08_parametric.femprj
|
|
7
|
+
"""
|
|
8
|
+
from optuna.integration.botorch import BoTorchSampler
|
|
9
|
+
from pyfemtet.opt import FEMOpt, OptunaOptimizer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def inductance(Femtet):
|
|
13
|
+
"""Obtain the self-inductance.
|
|
14
|
+
|
|
15
|
+
Note:
|
|
16
|
+
The objective or constraint function should take Femtet
|
|
17
|
+
as its first argument and return a float as the output.
|
|
18
|
+
|
|
19
|
+
Params:
|
|
20
|
+
Femtet: This is an instance for manipulating Femtet with macros. For detailed information, please refer to "Femtet Macro Help".
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
float: Self-inductance.
|
|
24
|
+
"""
|
|
25
|
+
Gogh = Femtet.Gogh
|
|
26
|
+
|
|
27
|
+
coil_name = Gogh.Gauss.GetCoilList()[0]
|
|
28
|
+
return Gogh.Gauss.GetL(coil_name, coil_name) # unit: F
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == '__main__':
|
|
32
|
+
|
|
33
|
+
# Initialize the numerical optimization problem.
|
|
34
|
+
# (determine the optimization method)
|
|
35
|
+
opt = OptunaOptimizer(
|
|
36
|
+
sampler_class=BoTorchSampler,
|
|
37
|
+
sampler_kwargs=dict(
|
|
38
|
+
n_startup_trials=5,
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Initialize the FEMOpt object.
|
|
43
|
+
# (establish connection between the optimization problem and Femtet)
|
|
44
|
+
femopt = FEMOpt(opt=opt)
|
|
45
|
+
|
|
46
|
+
# Add design variables to the optimization problem.
|
|
47
|
+
# (Specify the variables registered in the femprj file.)
|
|
48
|
+
femopt.add_parameter("helical_pitch", 6, lower_bound=4.2, upper_bound=8)
|
|
49
|
+
femopt.add_parameter("coil_radius", 10, lower_bound=1, upper_bound=10)
|
|
50
|
+
femopt.add_parameter("n_turns", 5, lower_bound=1, upper_bound=5)
|
|
51
|
+
|
|
52
|
+
# Add the objective function to the optimization problem.
|
|
53
|
+
# The target inductance is 0.1 uF.
|
|
54
|
+
femopt.add_objective(inductance, name='self-inductance (F)', direction=1e-7)
|
|
55
|
+
|
|
56
|
+
# Run optimization.
|
|
57
|
+
femopt.set_random_seed(42)
|
|
58
|
+
femopt.optimize(n_trials=20)
|
|
59
|
+
femopt.terminate_all()
|
|
Binary file
|