pyfemtet 0.5.3__py3-none-any.whl → 0.6.0__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 → _message}/locales/ja/LC_MESSAGES/messages.po +89 -77
- pyfemtet/{message → _message}/locales/messages.pot +88 -76
- pyfemtet/{message → _message}/messages.py +1 -1
- pyfemtet/_warning.py +23 -0
- pyfemtet/dispatch_extensions/__init__.py +12 -0
- pyfemtet/{dispatch_extensions.py → dispatch_extensions/_impl.py} +45 -43
- pyfemtet/logger/__init__.py +3 -0
- pyfemtet/{logger.py → logger/_impl.py} +12 -6
- pyfemtet/opt/__init__.py +3 -0
- pyfemtet/opt/_femopt.py +265 -68
- pyfemtet/opt/_femopt_core.py +111 -68
- pyfemtet/opt/_test_utils/record_history.py +1 -1
- pyfemtet/opt/interface/__init__.py +0 -1
- pyfemtet/opt/interface/_base.py +3 -3
- pyfemtet/opt/interface/_femtet.py +116 -59
- pyfemtet/opt/interface/_femtet_with_nx/_interface.py +35 -12
- pyfemtet/opt/interface/_femtet_with_sldworks.py +22 -2
- pyfemtet/opt/optimizer/__init__.py +5 -1
- pyfemtet/opt/optimizer/_base.py +81 -55
- pyfemtet/opt/optimizer/{_optuna_botorchsampler_parameter_constraint_helper.py → _optuna/_botorch_patch/enable_nonlinear_constraint.py} +10 -127
- pyfemtet/opt/optimizer/{_optuna.py → _optuna/_optuna.py} +122 -19
- pyfemtet/opt/optimizer/_optuna/_pof_botorch.py +1833 -0
- pyfemtet/opt/optimizer/_scipy.py +20 -5
- pyfemtet/opt/optimizer/_scipy_scalar.py +20 -5
- pyfemtet/opt/prediction/{base.py → _base.py} +3 -2
- pyfemtet/opt/prediction/single_task_gp.py +10 -5
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +2 -2
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.py +2 -2
- pyfemtet/opt/visualization/{base.py → _base.py} +1 -1
- pyfemtet/opt/visualization/{complex_components → _complex_components}/alert_region.py +2 -2
- pyfemtet/opt/visualization/{complex_components → _complex_components}/control_femtet.py +3 -3
- pyfemtet/opt/visualization/{complex_components → _complex_components}/main_figure_creator.py +1 -1
- pyfemtet/opt/visualization/{complex_components → _complex_components}/main_graph.py +5 -5
- pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph.py +5 -5
- pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph_creator.py +2 -2
- pyfemtet/opt/visualization/_create_wrapped_components.py +2 -2
- pyfemtet/opt/visualization/_process_monitor/__init__.py +0 -0
- pyfemtet/opt/visualization/{process_monitor → _process_monitor}/application.py +3 -3
- pyfemtet/opt/visualization/{process_monitor → _process_monitor}/pages.py +10 -10
- pyfemtet/opt/visualization/_wrapped_components/__init__.py +0 -0
- pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dbc.py +1 -1
- pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dcc.py +1 -1
- pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/html.py +1 -1
- pyfemtet/opt/visualization/result_viewer/application.py +4 -4
- pyfemtet/opt/visualization/result_viewer/pages.py +9 -9
- {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/METADATA +2 -2
- {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/RECORD +60 -56
- {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/WHEEL +1 -1
- pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo +0 -0
- pyfemtet/opt/samples/femprj_sample/.gitignore +0 -2
- /pyfemtet/{message → _message}/1. make_pot.bat +0 -0
- /pyfemtet/{message → _message}/2. make_mo.bat +0 -0
- /pyfemtet/{message → _message}/__init__.py +0 -0
- /pyfemtet/{message → _message}/babel.cfg +0 -0
- /pyfemtet/opt/{visualization/complex_components → optimizer/_optuna}/__init__.py +0 -0
- /pyfemtet/opt/{visualization/process_monitor → optimizer/_optuna/_botorch_patch}/__init__.py +0 -0
- /pyfemtet/opt/{parameter.py → optimizer/parameter.py} +0 -0
- /pyfemtet/opt/visualization/{wrapped_components → _complex_components}/__init__.py +0 -0
- /pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/str_enum.py +0 -0
- {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/LICENSE +0 -0
- {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/entry_points.txt +0 -0
pyfemtet/opt/_femopt.py
CHANGED
|
@@ -12,12 +12,12 @@ from traceback import print_exception
|
|
|
12
12
|
# 3rd-party
|
|
13
13
|
import numpy as np
|
|
14
14
|
import pandas as pd
|
|
15
|
-
from dask.distributed import LocalCluster, Client
|
|
15
|
+
from dask.distributed import LocalCluster, Client
|
|
16
16
|
|
|
17
17
|
# pyfemtet relative
|
|
18
18
|
from pyfemtet.opt.interface import FEMInterface, FemtetInterface
|
|
19
19
|
from pyfemtet.opt.optimizer import AbstractOptimizer, OptunaOptimizer
|
|
20
|
-
from pyfemtet.opt.visualization.
|
|
20
|
+
from pyfemtet.opt.visualization._process_monitor.application import main as process_monitor_main
|
|
21
21
|
from pyfemtet.opt._femopt_core import (
|
|
22
22
|
_check_bound,
|
|
23
23
|
_is_access_gogh,
|
|
@@ -28,13 +28,17 @@ from pyfemtet.opt._femopt_core import (
|
|
|
28
28
|
OptimizationStatus,
|
|
29
29
|
logger,
|
|
30
30
|
)
|
|
31
|
-
from pyfemtet.
|
|
32
|
-
from pyfemtet.opt.parameter import Parameter, Expression
|
|
31
|
+
from pyfemtet._message import Msg, encoding
|
|
32
|
+
from pyfemtet.opt.optimizer.parameter import Parameter, Expression
|
|
33
|
+
from pyfemtet._warning import experimental_feature
|
|
33
34
|
|
|
35
|
+
from dask import config as cfg
|
|
36
|
+
cfg.set({'distributed.scheduler.worker-ttl': None})
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
|
|
39
|
+
def add_worker(client, worker_name, n_workers=1):
|
|
36
40
|
import sys
|
|
37
|
-
from subprocess import Popen, DEVNULL
|
|
41
|
+
from subprocess import Popen, DEVNULL, PIPE
|
|
38
42
|
|
|
39
43
|
current_n_workers = len(client.nthreads().keys())
|
|
40
44
|
|
|
@@ -42,39 +46,59 @@ def add_worker(client, worker_name):
|
|
|
42
46
|
f'{sys.executable} -m dask worker '
|
|
43
47
|
f'{client.scheduler.address} '
|
|
44
48
|
f'--nthreads 1 '
|
|
45
|
-
f'--nworkers
|
|
46
|
-
f'--name {worker_name} '
|
|
47
|
-
|
|
49
|
+
f'--nworkers {n_workers} '
|
|
50
|
+
f'--name {worker_name} ', # A unique name for this worker like ‘worker-1’. If used with -nworkers then the process number will be appended like name-0, name-1, name-2, …
|
|
51
|
+
# --no-nanny option は --nworkers と併用できない
|
|
48
52
|
shell=True,
|
|
49
53
|
stderr=DEVNULL,
|
|
50
54
|
stdout=DEVNULL,
|
|
51
55
|
)
|
|
52
56
|
|
|
53
57
|
# worker が増えるまで待つ
|
|
54
|
-
client.wait_for_workers(n_workers=current_n_workers +
|
|
55
|
-
|
|
58
|
+
client.wait_for_workers(n_workers=current_n_workers + n_workers)
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
class FEMOpt:
|
|
59
62
|
"""Class to control FEM interface and optimizer.
|
|
60
63
|
|
|
61
64
|
Args:
|
|
62
|
-
fem (FEMInterface, optional):
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
fem (FEMInterface, optional):
|
|
66
|
+
The FEM software interface.
|
|
67
|
+
Defaults to None (automatically set to :class:`FemtetInterface`).
|
|
68
|
+
|
|
69
|
+
opt (AbstractOptimizer, optional):
|
|
70
|
+
The numerical optimizer object.
|
|
71
|
+
Defaults to None (automatically set to :class:`OptunaOptimizer`
|
|
72
|
+
with :class:`optuna.samplers.TPESampler`).
|
|
73
|
+
|
|
74
|
+
history_path (str, optional):
|
|
75
|
+
The path to the history file.
|
|
76
|
+
Defaults to None.
|
|
77
|
+
If None, '%Y_%m_%d_%H_%M_%S.csv' is created in current directory.
|
|
78
|
+
|
|
79
|
+
scheduler_address (str, optional):
|
|
80
|
+
When performing cluster computing, please specify the address
|
|
81
|
+
of the scheduler computer here.
|
|
82
|
+
|
|
83
|
+
See Also:
|
|
84
|
+
https://pyfemtet.readthedocs.io/en/stable/pages/usage_pages/how_to_deploy_cluster.html
|
|
85
|
+
|
|
86
|
+
.. Example の中について、reST ではリストだと改行できないので、リストにしない
|
|
87
|
+
|
|
88
|
+
Examples:
|
|
89
|
+
|
|
90
|
+
When specifying and opening a femprj and model, we write
|
|
91
|
+
|
|
92
|
+
>>> from pyfemtet.opt import FEMOpt, FemtetInterface # doctest: +SKIP
|
|
93
|
+
>>> fem = FemtetInterface(femprj_path='path/to/project.femprj', model_name='NewModel') # doctest: +SKIP
|
|
94
|
+
>>> femopt = FEMOpt(fem=fem) # doctest: +SKIP
|
|
95
|
+
|
|
96
|
+
When specifying optimization algorithm, we write
|
|
97
|
+
|
|
98
|
+
>>> from optuna.samplers import TPESampler # doctest: +SKIP
|
|
99
|
+
>>> from pyfemtet.opt import FEMOpt, OptunaOptimizer # doctest: +SKIP
|
|
100
|
+
>>> opt = OptunaOptimizer(sampler_class=TPESampler, sampler_kwargs=dict(n_startup_trials=10)) # doctest: +SKIP
|
|
101
|
+
>>> femopt = FEMOpt(opt=opt) # doctest: +SKIP
|
|
78
102
|
|
|
79
103
|
"""
|
|
80
104
|
|
|
@@ -111,6 +135,7 @@ class FEMOpt:
|
|
|
111
135
|
self.monitor_process_future = None
|
|
112
136
|
self.monitor_server_kwargs = dict()
|
|
113
137
|
self.monitor_process_worker_name = None
|
|
138
|
+
self._hv_reference = None
|
|
114
139
|
|
|
115
140
|
# multiprocess 時に pickle できないオブジェクト参照の削除
|
|
116
141
|
def __getstate__(self):
|
|
@@ -133,25 +158,40 @@ class FEMOpt:
|
|
|
133
158
|
def add_parameter(
|
|
134
159
|
self,
|
|
135
160
|
name: str,
|
|
136
|
-
initial_value: float
|
|
137
|
-
lower_bound: float
|
|
138
|
-
upper_bound: float
|
|
139
|
-
step: float
|
|
140
|
-
properties:
|
|
141
|
-
pass_to_fem:
|
|
161
|
+
initial_value: float = None,
|
|
162
|
+
lower_bound: float = None,
|
|
163
|
+
upper_bound: float = None,
|
|
164
|
+
step: float = None,
|
|
165
|
+
properties: dict[str, str or float] = None,
|
|
166
|
+
pass_to_fem: bool = True,
|
|
142
167
|
):
|
|
168
|
+
# noinspection PyUnresolvedReferences
|
|
143
169
|
"""Adds a parameter to the optimization problem.
|
|
144
170
|
|
|
145
171
|
Args:
|
|
146
172
|
name (str): The name of the parameter.
|
|
147
|
-
initial_value (float
|
|
148
|
-
lower_bound (float
|
|
149
|
-
upper_bound (float or None, optional): The upper bound of the parameter. Defaults to None.
|
|
150
|
-
step (float
|
|
151
|
-
properties (dict, optional): Additional information about the parameter. Defaults to None.
|
|
173
|
+
initial_value (float, optional): The initial value of the parameter. Defaults to None. If None, try to get initial value from FEMInterface.
|
|
174
|
+
lower_bound (float, optional): The lower bound of the parameter. Defaults to None. Some optimization algorithms require this.
|
|
175
|
+
upper_bound (float or None, optional): The upper bound of the parameter. Defaults to None. Some optimization algorithms require this.
|
|
176
|
+
step (float, optional): The step of parameter. If specified, parameter is used as discrete. Defaults to None.
|
|
177
|
+
properties (dict[str, str or float], optional): Additional information about the parameter. Defaults to None.
|
|
152
178
|
pass_to_fem (bool, optional): If this variable is used directly in FEM model update or not. If False, this parameter can be just used as inpt of expressions. Defaults to True.
|
|
179
|
+
|
|
153
180
|
Raises:
|
|
154
|
-
ValueError: If initial_value is not specified and the value for the given name is also not specified.
|
|
181
|
+
ValueError: If initial_value is not specified and the value for the given name is also not specified in FEM.
|
|
182
|
+
|
|
183
|
+
Examples:
|
|
184
|
+
|
|
185
|
+
When adding parameter a (-1 <= a <= 1; initial value is 0), we write
|
|
186
|
+
|
|
187
|
+
>>> femopt.add_parameter('parameter_a', 0, -1, 1) # doctest: +SKIP
|
|
188
|
+
|
|
189
|
+
Note that the ```note``` argument can be set any name in this case.
|
|
190
|
+
|
|
191
|
+
When adding discrete parameter a (-1 <= a <= 1; initial value is 0,
|
|
192
|
+
step 0.5), we write
|
|
193
|
+
|
|
194
|
+
>>> femopt.add_parameter('parameter a', 0, -1, 1, 0.5) # doctest: +SKIP
|
|
155
195
|
|
|
156
196
|
"""
|
|
157
197
|
|
|
@@ -179,23 +219,73 @@ class FEMOpt:
|
|
|
179
219
|
)
|
|
180
220
|
self.opt.variables.add_parameter(prm)
|
|
181
221
|
|
|
222
|
+
@experimental_feature
|
|
182
223
|
def add_expression(
|
|
183
224
|
self,
|
|
184
225
|
name: str,
|
|
185
226
|
fun: Callable[[Any], float],
|
|
186
|
-
properties=
|
|
227
|
+
properties: dict[str, str or float] = None,
|
|
187
228
|
kwargs: Optional[dict] = None,
|
|
188
229
|
pass_to_fem=True,
|
|
189
230
|
):
|
|
231
|
+
# noinspection PyUnresolvedReferences
|
|
190
232
|
"""Add expression to the optimization problem.
|
|
191
233
|
|
|
234
|
+
Warnings:
|
|
235
|
+
This feature is highly experimental and
|
|
236
|
+
may change in the future.
|
|
237
|
+
|
|
192
238
|
Args:
|
|
193
239
|
name (str): The name of the variable.
|
|
194
240
|
fun (Callable[[Any], float]): An expression function. The arguments that you want to use as input variables must be the same with ``name`` of Variable objects added by ``add_parameter()`` or ``add_expression()``. If you use other objects as argument of the function, you must specify ``kwargs``.
|
|
195
|
-
properties ([
|
|
241
|
+
properties (dict[str, str or float], optional): Additional information about the parameter. Defaults to None.
|
|
196
242
|
kwargs (Optional[dict], optional): Remaining arguments of ``fun``. Defaults to None.
|
|
197
243
|
pass_to_fem (bool, optional): If this variable is used directly in FEM model update or not. If False, this variable can be just used as inpt of other expressions. Defaults to True.
|
|
244
|
+
|
|
245
|
+
Examples:
|
|
246
|
+
|
|
247
|
+
When adding variable a and b; a is not directly included as model
|
|
248
|
+
variables but an optimization parameter, b is not a parameter but
|
|
249
|
+
a model variable and the relationship of these 2 variables is
|
|
250
|
+
```b = a ** 2```, we write:
|
|
251
|
+
|
|
252
|
+
>>> def calc_b(parameter_a): # doctest: +SKIP
|
|
253
|
+
... return parameter_a ** 2 # doctest: +SKIP
|
|
254
|
+
...
|
|
255
|
+
>>> femopt.add_parameter('parameter_a', 0, -1, 1, pass_to_fem=False) # doctest: +SKIP
|
|
256
|
+
>>> femopt.add_expression('variable_b', calc_b) # doctest: +SKIP
|
|
257
|
+
|
|
258
|
+
Notes:
|
|
259
|
+
The argument names of function to calculate variable
|
|
260
|
+
must match the ```name``` of the parameter.
|
|
261
|
+
|
|
262
|
+
Notes:
|
|
263
|
+
In this case, only strings that can be used as Python variables are valid
|
|
264
|
+
for ```name``` argument of :func:`FEMOpt.add_parameter`.
|
|
265
|
+
|
|
266
|
+
When adding variable r, theta and x, y; r, theta is an optimization
|
|
267
|
+
parameter and x, y is an intermediate variable to calculate constraint
|
|
268
|
+
function, we write
|
|
269
|
+
|
|
270
|
+
>>> def calc_x(r, theta): # doctest: +SKIP
|
|
271
|
+
... return r * cos(theta) # doctest: +SKIP
|
|
272
|
+
...
|
|
273
|
+
>>> def calc_y(r, theta): # doctest: +SKIP
|
|
274
|
+
... return r * cos(theta) # doctest: +SKIP
|
|
275
|
+
...
|
|
276
|
+
>>> def constraint(Femtet, opt: AbstractOptimizer): # doctest: +SKIP
|
|
277
|
+
... d = opt.variables.get_variables() # doctest: +SKIP
|
|
278
|
+
... x, y = d['x'], d['y'] # doctest: +SKIP
|
|
279
|
+
... return min(x, y) # doctest: +SKIP
|
|
280
|
+
...
|
|
281
|
+
>>> femopt.add_parameter('r', 0, 0, 1) # doctest: +SKIP
|
|
282
|
+
>>> femopt.add_parameter('theta', 0, 0, 2*pi) # doctest: +SKIP
|
|
283
|
+
>>> femopt.add_expression('x', calc_x, pass_to_fem=False) # doctest: +SKIP
|
|
284
|
+
>>> femopt.add_expression('y', calc_y, pass_to_fem=False) # doctest: +SKIP
|
|
285
|
+
>>> femopt.add_constraint(constraint, lower_bound=0.5, args=(femopt.opt,)) # doctest: +SKIP
|
|
286
|
+
|
|
198
287
|
"""
|
|
288
|
+
|
|
199
289
|
exp = Expression(
|
|
200
290
|
name=name,
|
|
201
291
|
value=None,
|
|
@@ -214,18 +304,39 @@ class FEMOpt:
|
|
|
214
304
|
args: tuple or None = None,
|
|
215
305
|
kwargs: dict or None = None
|
|
216
306
|
):
|
|
307
|
+
# noinspection PyUnresolvedReferences
|
|
217
308
|
"""Adds an objective to the optimization problem.
|
|
218
309
|
|
|
219
310
|
Args:
|
|
220
311
|
fun (callable): The objective function.
|
|
221
312
|
name (str or None, optional): The name of the objective. Defaults to None.
|
|
222
|
-
direction (str or float, optional): The optimization direction. Defaults to 'minimize'.
|
|
313
|
+
direction (str or float, optional): The optimization direction. Varid values are 'maximize', 'minimize' or a float value. Defaults to 'minimize'.
|
|
223
314
|
args (tuple or None, optional): Additional arguments for the objective function. Defaults to None.
|
|
224
315
|
kwargs (dict or None, optional): Additional keyword arguments for the objective function. Defaults to None.
|
|
225
316
|
|
|
226
317
|
Note:
|
|
227
318
|
If the FEMInterface is FemtetInterface, the 1st argument of fun should be Femtet (IPyDispatch) object.
|
|
228
319
|
|
|
320
|
+
Examples:
|
|
321
|
+
|
|
322
|
+
When add a complex objective (for example, want to dynamically set body
|
|
323
|
+
to calculate temperature and use product of the temperature and one of
|
|
324
|
+
the parameters as objective) , we write
|
|
325
|
+
|
|
326
|
+
>>> class MyClass: # doctest: +SKIP
|
|
327
|
+
... def get_body_name(self): # doctest: +SKIP
|
|
328
|
+
... ... # process something and detect body name # doctest: +SKIP
|
|
329
|
+
... return body_name # doctest: +SKIP
|
|
330
|
+
...
|
|
331
|
+
>>> def complex_objective(Femtet, opt, some_object): # doctest: +SKIP
|
|
332
|
+
... body_name = some_object.get_body_name() # dynamically get body name to calculate temperature # doctest: +SKIP
|
|
333
|
+
... temp, _, _ = Femtet.Gogh.Watt.GetTemp(body_name) # calculate temperature # doctest: +SKIP
|
|
334
|
+
... some_param = opt.get_parameter()['some_param'] # get ome parameter # doctest: +SKIP
|
|
335
|
+
... return temp * some_param # calculate something and return it # doctest: +SKIP
|
|
336
|
+
...
|
|
337
|
+
>>> my_obj = MyClass() # doctest: +SKIP
|
|
338
|
+
>>> femopt.add_objective(complex_objective, args=(femopt.opt, my_obj,)) # doctest: +SKIP
|
|
339
|
+
|
|
229
340
|
Tip:
|
|
230
341
|
If name is None, name is a string with the prefix `"obj_"` followed by a sequential number.
|
|
231
342
|
|
|
@@ -263,6 +374,7 @@ class FEMOpt:
|
|
|
263
374
|
kwargs: dict or None = None,
|
|
264
375
|
using_fem: bool = None,
|
|
265
376
|
):
|
|
377
|
+
# noinspection PyUnresolvedReferences
|
|
266
378
|
"""Adds a constraint to the optimization problem.
|
|
267
379
|
|
|
268
380
|
Args:
|
|
@@ -275,6 +387,36 @@ class FEMOpt:
|
|
|
275
387
|
kwargs (dict): Additional arguments for the constraint function. Defaults to None.
|
|
276
388
|
using_fem (bool, optional): Using FEM or not in the constraint function. It may make the processing time in strict constraints in BoTorchSampler. Defaults to None. If None, PyFemtet checks the access to Femtet and estimate using Femtet or not automatically.
|
|
277
389
|
|
|
390
|
+
Warnings:
|
|
391
|
+
|
|
392
|
+
When ```strict``` == True and using OptunaOptimizer along with :class:`PoFBoTorchSampler`,
|
|
393
|
+
PyFemtet will solve an optimization subproblem to propose new variables.
|
|
394
|
+
During this process, the constraint function ```fun``` will be executed at each
|
|
395
|
+
iteration of the subproblem, which may include time-consuming operations such
|
|
396
|
+
as retrieving 3D model information via FEMInterface.
|
|
397
|
+
As a result, it may not be feasible to complete the overall optimization within
|
|
398
|
+
a realistic timeframe.
|
|
399
|
+
|
|
400
|
+
Examples:
|
|
401
|
+
For example, in a case where the bottom area of the model is constrained,
|
|
402
|
+
the following approach may require a very long time.
|
|
403
|
+
|
|
404
|
+
>>> def bottom_area(Femtet, opt): # doctest: +SKIP
|
|
405
|
+
... w = Femtet.GetVariableValue('width') # doctest: +SKIP
|
|
406
|
+
... d = Femtet.GetVariableValue('depth') # doctest: +SKIP
|
|
407
|
+
... return w * d # doctest: +SKIP
|
|
408
|
+
...
|
|
409
|
+
>>> femopt.add_constraint(constraint, lower_bound=5) # doctest: +SKIP
|
|
410
|
+
|
|
411
|
+
Instead, please do the following.
|
|
412
|
+
|
|
413
|
+
>>> def bottom_area(_, opt): # Not to access the 1st argument. # doctest: +SKIP
|
|
414
|
+
... params = opt.get_parameter() # doctest: +SKIP
|
|
415
|
+
... w, d = params['width'], params['depth'] # doctest: +SKIP
|
|
416
|
+
... return w * d # doctest: +SKIP
|
|
417
|
+
...
|
|
418
|
+
>>> femopt.add_constraint(constraint, lower_bound=5, args=(femopt.opt,)) # doctest: +SKIP
|
|
419
|
+
|
|
278
420
|
Note:
|
|
279
421
|
If the FEMInterface is FemtetInterface, the 1st argument of fun should be Femtet (IPyDispatch) object.
|
|
280
422
|
|
|
@@ -330,22 +472,32 @@ class FEMOpt:
|
|
|
330
472
|
self.opt.constraints[name] = Constraint(fun, name, lower_bound, upper_bound, strict, args, kwargs, using_fem)
|
|
331
473
|
|
|
332
474
|
def get_parameter(self, format='dict'):
|
|
333
|
-
|
|
475
|
+
"""Deprecated method.
|
|
476
|
+
|
|
477
|
+
Planed to remove in future version. Use FEMOpt.opt.get_parameter() instead.
|
|
478
|
+
"""
|
|
479
|
+
raise DeprecationWarning('FEMOpt.get_parameter() was deprecated. Use FEMOpt.opt.get_parameter() instead.')
|
|
334
480
|
|
|
335
481
|
def set_monitor_host(self, host=None, port=None):
|
|
336
|
-
"""Sets
|
|
482
|
+
"""Sets the host IP address and the port of the process monitor.
|
|
337
483
|
|
|
338
484
|
Args:
|
|
339
|
-
host (str):
|
|
340
|
-
|
|
485
|
+
host (str):
|
|
486
|
+
The hostname or IP address of the monitor server.
|
|
487
|
+
port (int, optional):
|
|
488
|
+
The port number of the monitor server.
|
|
489
|
+
If None, ``8080`` will be used.
|
|
490
|
+
Defaults to None.
|
|
341
491
|
|
|
342
492
|
Tip:
|
|
343
|
-
Specifying host ``0.0.0.0`` allows viewing monitor
|
|
493
|
+
Specifying host ``0.0.0.0`` allows viewing monitor
|
|
494
|
+
from all computers on the local network.
|
|
344
495
|
|
|
345
|
-
|
|
346
|
-
|
|
496
|
+
If no hostname is specified, the monitor server
|
|
497
|
+
will be hosted on ``localhost``.
|
|
347
498
|
|
|
348
|
-
|
|
499
|
+
We can access process monitor by accessing
|
|
500
|
+
```localhost:8080``` on our browser by default.
|
|
349
501
|
|
|
350
502
|
"""
|
|
351
503
|
self.monitor_server_kwargs = dict(
|
|
@@ -355,33 +507,57 @@ class FEMOpt:
|
|
|
355
507
|
|
|
356
508
|
def optimize(
|
|
357
509
|
self,
|
|
358
|
-
n_trials=None,
|
|
359
|
-
n_parallel=1,
|
|
360
|
-
timeout=None,
|
|
361
|
-
wait_setup=True,
|
|
362
|
-
confirm_before_exit=True,
|
|
510
|
+
n_trials: int = None,
|
|
511
|
+
n_parallel: int = 1,
|
|
512
|
+
timeout: float = None,
|
|
513
|
+
wait_setup: bool = True,
|
|
514
|
+
confirm_before_exit: bool = True,
|
|
363
515
|
):
|
|
364
516
|
"""Runs the main optimization process.
|
|
365
517
|
|
|
366
518
|
Args:
|
|
367
|
-
n_trials (int
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
519
|
+
n_trials (int, optional):
|
|
520
|
+
The number of trials.
|
|
521
|
+
Defaults to None.
|
|
522
|
+
n_parallel (int, optional):
|
|
523
|
+
The number of parallel processes.
|
|
524
|
+
Defaults to 1.
|
|
525
|
+
Note that even if this argument is 1,
|
|
526
|
+
:class:`FEMOpt` makes some child processes
|
|
527
|
+
to run process monitor, status monitor, etc.
|
|
528
|
+
timeout (float, optional):
|
|
529
|
+
The maximum amount of time in seconds
|
|
530
|
+
that each trial can run.
|
|
531
|
+
Defaults to None.
|
|
532
|
+
wait_setup (bool, optional):
|
|
533
|
+
Wait for all workers launching FEM system.
|
|
534
|
+
Defaults to True.
|
|
535
|
+
confirm_before_exit (bool, optional):
|
|
536
|
+
Insert stop before exit to continue to
|
|
537
|
+
show process monitor.
|
|
372
538
|
|
|
373
539
|
Tip:
|
|
374
|
-
If set_monitor_host() is not executed,
|
|
540
|
+
If set_monitor_host() is not executed,
|
|
541
|
+
a local server for monitoring will be
|
|
542
|
+
started at localhost:8080.
|
|
543
|
+
|
|
544
|
+
See Also:
|
|
545
|
+
:func:`FEMOpt.set_monitor_host`
|
|
375
546
|
|
|
376
547
|
Note:
|
|
377
|
-
If ``n_trials`` and ``timeout`` are both None,
|
|
548
|
+
If ``n_trials`` and ``timeout`` are both None,
|
|
549
|
+
it runs forever until interrupting by the user.
|
|
378
550
|
|
|
379
551
|
Note:
|
|
380
|
-
If ``n_parallel`` >= 2, depending on the end timing,
|
|
552
|
+
If ``n_parallel`` >= 2, depending on the end timing,
|
|
553
|
+
``n_trials`` may be exceeded by up to ``n_parallel-1`` times.
|
|
381
554
|
|
|
382
555
|
Warning:
|
|
383
|
-
If ``n_parallel`` >= 2 and ``fem`` is a subclass of
|
|
384
|
-
|
|
556
|
+
If ``n_parallel`` >= 2 and ``fem`` is a subclass of
|
|
557
|
+
``FemtetInterface``, the ``strictly_pid_specify`` of
|
|
558
|
+
subprocess is set to ``False``.
|
|
559
|
+
So **it is recommended to close all other Femtet processes
|
|
560
|
+
before running.**
|
|
385
561
|
|
|
386
562
|
"""
|
|
387
563
|
|
|
@@ -451,14 +627,21 @@ class FEMOpt:
|
|
|
451
627
|
|
|
452
628
|
else:
|
|
453
629
|
# ローカルクラスターを構築
|
|
454
|
-
logger.info('Launching single machine cluster
|
|
630
|
+
logger.info('Launching single machine cluster... This may take tens of seconds.')
|
|
631
|
+
|
|
632
|
+
# Fixed:
|
|
633
|
+
# Nanny の管理機能は必要ないが、Python API では worker_class を Worker にすると
|
|
634
|
+
# processes 引数が無視されて Thread worker が立てられる。
|
|
635
|
+
# これは CLI の --no-nanny オプションも同様らしい。
|
|
636
|
+
|
|
637
|
+
# クラスターの構築
|
|
455
638
|
cluster = LocalCluster(
|
|
456
639
|
processes=True,
|
|
457
|
-
n_workers=n_parallel,
|
|
640
|
+
n_workers=n_parallel,
|
|
458
641
|
threads_per_worker=1,
|
|
459
|
-
worker_class=Worker,
|
|
460
642
|
)
|
|
461
643
|
logger.info('LocalCluster launched successfully.')
|
|
644
|
+
|
|
462
645
|
self.client = Client(cluster, direct_to_workers=False)
|
|
463
646
|
self.scheduler_address = self.client.scheduler.address
|
|
464
647
|
logger.info('Client launched successfully.')
|
|
@@ -483,6 +666,7 @@ class FEMOpt:
|
|
|
483
666
|
model_name=self.fem.model_name
|
|
484
667
|
)
|
|
485
668
|
)
|
|
669
|
+
|
|
486
670
|
# Femtet の parametric 設定を目的関数に用いるかどうか
|
|
487
671
|
if self.fem.parametric_output_indexes_use_as_objective is not None:
|
|
488
672
|
from pyfemtet.opt.interface._femtet_parametric import add_parametric_results_as_objectives
|
|
@@ -493,8 +677,14 @@ class FEMOpt:
|
|
|
493
677
|
indexes,
|
|
494
678
|
directions,
|
|
495
679
|
)
|
|
680
|
+
|
|
681
|
+
# Femtet の confirm_before_exit のセット
|
|
682
|
+
self.fem.confirm_before_exit = confirm_before_exit
|
|
683
|
+
self.fem.kwargs['confirm_before_exit'] = confirm_before_exit
|
|
684
|
+
|
|
496
685
|
logger.info('Femtet loaded successfully.')
|
|
497
686
|
|
|
687
|
+
|
|
498
688
|
# actor の設定
|
|
499
689
|
self.status = OptimizationStatus(_client)
|
|
500
690
|
self.worker_status_list = [OptimizationStatus(_client, name) for name in worker_addresses] # tqdm 検討
|
|
@@ -506,10 +696,12 @@ class FEMOpt:
|
|
|
506
696
|
list(self.opt.constraints.keys()),
|
|
507
697
|
_client,
|
|
508
698
|
metadata,
|
|
699
|
+
self._hv_reference
|
|
509
700
|
)
|
|
510
701
|
logger.info('Status Actor initialized successfully.')
|
|
511
702
|
|
|
512
703
|
# launch monitor
|
|
704
|
+
# noinspection PyTypeChecker
|
|
513
705
|
self.monitor_process_future = _client.submit(
|
|
514
706
|
# func
|
|
515
707
|
_start_monitor_server,
|
|
@@ -634,6 +826,11 @@ class FEMOpt:
|
|
|
634
826
|
|
|
635
827
|
@staticmethod
|
|
636
828
|
def terminate_all():
|
|
829
|
+
"""Deprecated method. We plan to remove this in future version.
|
|
830
|
+
|
|
831
|
+
In current version, the termination processes are
|
|
832
|
+
automatically execute in the last of :func:`FEMOpt.optimize`.
|
|
833
|
+
"""
|
|
637
834
|
warnings.warn(
|
|
638
835
|
"terminate_all() is deprecated and will be removed in a future version. "
|
|
639
836
|
"In current and later versions, the equivalent of terminate_all() will be executed when optimize() finishes. "
|