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.

Files changed (62) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/{message → _message}/locales/ja/LC_MESSAGES/messages.po +89 -77
  3. pyfemtet/{message → _message}/locales/messages.pot +88 -76
  4. pyfemtet/{message → _message}/messages.py +1 -1
  5. pyfemtet/_warning.py +23 -0
  6. pyfemtet/dispatch_extensions/__init__.py +12 -0
  7. pyfemtet/{dispatch_extensions.py → dispatch_extensions/_impl.py} +45 -43
  8. pyfemtet/logger/__init__.py +3 -0
  9. pyfemtet/{logger.py → logger/_impl.py} +12 -6
  10. pyfemtet/opt/__init__.py +3 -0
  11. pyfemtet/opt/_femopt.py +265 -68
  12. pyfemtet/opt/_femopt_core.py +111 -68
  13. pyfemtet/opt/_test_utils/record_history.py +1 -1
  14. pyfemtet/opt/interface/__init__.py +0 -1
  15. pyfemtet/opt/interface/_base.py +3 -3
  16. pyfemtet/opt/interface/_femtet.py +116 -59
  17. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +35 -12
  18. pyfemtet/opt/interface/_femtet_with_sldworks.py +22 -2
  19. pyfemtet/opt/optimizer/__init__.py +5 -1
  20. pyfemtet/opt/optimizer/_base.py +81 -55
  21. pyfemtet/opt/optimizer/{_optuna_botorchsampler_parameter_constraint_helper.py → _optuna/_botorch_patch/enable_nonlinear_constraint.py} +10 -127
  22. pyfemtet/opt/optimizer/{_optuna.py → _optuna/_optuna.py} +122 -19
  23. pyfemtet/opt/optimizer/_optuna/_pof_botorch.py +1833 -0
  24. pyfemtet/opt/optimizer/_scipy.py +20 -5
  25. pyfemtet/opt/optimizer/_scipy_scalar.py +20 -5
  26. pyfemtet/opt/prediction/{base.py → _base.py} +3 -2
  27. pyfemtet/opt/prediction/single_task_gp.py +10 -5
  28. pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +2 -2
  29. pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.py +2 -2
  30. pyfemtet/opt/visualization/{base.py → _base.py} +1 -1
  31. pyfemtet/opt/visualization/{complex_components → _complex_components}/alert_region.py +2 -2
  32. pyfemtet/opt/visualization/{complex_components → _complex_components}/control_femtet.py +3 -3
  33. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_figure_creator.py +1 -1
  34. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_graph.py +5 -5
  35. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph.py +5 -5
  36. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph_creator.py +2 -2
  37. pyfemtet/opt/visualization/_create_wrapped_components.py +2 -2
  38. pyfemtet/opt/visualization/_process_monitor/__init__.py +0 -0
  39. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/application.py +3 -3
  40. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/pages.py +10 -10
  41. pyfemtet/opt/visualization/_wrapped_components/__init__.py +0 -0
  42. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dbc.py +1 -1
  43. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dcc.py +1 -1
  44. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/html.py +1 -1
  45. pyfemtet/opt/visualization/result_viewer/application.py +4 -4
  46. pyfemtet/opt/visualization/result_viewer/pages.py +9 -9
  47. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/METADATA +2 -2
  48. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/RECORD +60 -56
  49. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/WHEEL +1 -1
  50. pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo +0 -0
  51. pyfemtet/opt/samples/femprj_sample/.gitignore +0 -2
  52. /pyfemtet/{message → _message}/1. make_pot.bat +0 -0
  53. /pyfemtet/{message → _message}/2. make_mo.bat +0 -0
  54. /pyfemtet/{message → _message}/__init__.py +0 -0
  55. /pyfemtet/{message → _message}/babel.cfg +0 -0
  56. /pyfemtet/opt/{visualization/complex_components → optimizer/_optuna}/__init__.py +0 -0
  57. /pyfemtet/opt/{visualization/process_monitor → optimizer/_optuna/_botorch_patch}/__init__.py +0 -0
  58. /pyfemtet/opt/{parameter.py → optimizer/parameter.py} +0 -0
  59. /pyfemtet/opt/visualization/{wrapped_components → _complex_components}/__init__.py +0 -0
  60. /pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/str_enum.py +0 -0
  61. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/LICENSE +0 -0
  62. {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, Worker
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.process_monitor.application import main as process_monitor_main
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.message import Msg, encoding
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
- def add_worker(client, worker_name):
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 1 '
46
- f'--name {worker_name} '
47
- f'--no-nanny',
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 + 1)
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): The finite element method interface. Defaults to None. If None, automatically set to FemtetInterface.
63
- opt (AbstractOptimizer):
64
- history_path (str, optional): The path to the history file. Defaults to None. If None, '%Y_%m_%d_%H_%M_%S.csv' is created in current directory.
65
- scheduler_address (str or None): If cluster processing, set this parameter like "tcp://xxx.xxx.xxx.xxx:xxxx".
66
-
67
- Attributes:
68
- fem (FEMInterface): The interface of FEM system.
69
- opt (AbstractOptimizer): The optimizer.
70
- scheduler_address (str or None): Dask scheduler address. If None, LocalCluster will be used.
71
- client (Client): Dask client. For detail, see dask documentation.
72
- status (OptimizationStatus): Entire process status. This contains dask actor.
73
- history(History): History of optimization process. This contains dask actor.
74
- history_path (str): The path to the history (.csv) file.
75
- worker_status_list([OptimizationStatus]): Process status of each dask worker.
76
- monitor_process_future(Future): Future of monitor server process. This is dask future.
77
- monitor_server_kwargs(dict): Monitor server parameter. Currently, the valid arguments are hostname and port.
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 or None = None,
137
- lower_bound: float or None = None,
138
- upper_bound: float or None = None,
139
- step: float or None = None,
140
- properties: Optional[dict] = None,
141
- pass_to_fem: Optional[bool] = True,
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 or None, optional): The initial value of the parameter. Defaults to None. If None, try to get initial value from FEMInterface.
148
- lower_bound (float or None, optional): The lower bound of the parameter. Defaults to None. However, this argument is required for some algorithms.
149
- upper_bound (float or None, optional): The upper bound of the parameter. Defaults to None. However, this argument is required for some algorithms.
150
- step (float or None, optional): The step of parameter. Defaults to None.
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=property,
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 ([type], optional): Property names and their values of the variable. Defaults to property.
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
- raise DeprecationWarning('FEMOpt.get_parameter() was deprecated. Use Femopt.opt.get_parameter() instead.')
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 up the monitor server with the specified host and port.
482
+ """Sets the host IP address and the port of the process monitor.
337
483
 
338
484
  Args:
339
- host (str): The hostname or IP address of the monitor server.
340
- port (int or None, optional): The port number of the monitor server. If None, ``8080`` will be used. Defaults to None.
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 from all computers on the local network.
493
+ Specifying host ``0.0.0.0`` allows viewing monitor
494
+ from all computers on the local network.
344
495
 
345
- However, please note that in this case,
346
- it will be visible to all users on the local network.
496
+ If no hostname is specified, the monitor server
497
+ will be hosted on ``localhost``.
347
498
 
348
- If no hostname is specified, the monitor server will be hosted on ``localhost``.
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 or None, optional): The number of trials. Defaults to None.
368
- n_parallel (int, optional): The number of parallel processes. Defaults to 1.
369
- timeout (float or None, optional): The maximum amount of time in seconds that each trial can run. Defaults to None.
370
- wait_setup (bool, optional): Wait for all workers launching FEM system. Defaults to True.
371
- confirm_before_exit (bool, optional): Insert stop before exit to continue to show process monitor.
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, a local server for monitoring will be started at localhost:8080.
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, it runs forever until interrupting by the user.
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, ``n_trials`` may be exceeded by up to ``n_parallel-1`` times.
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 ``FemtetInterface``, the ``strictly_pid_specify`` of subprocess is set to ``False``.
384
- So **it is recommended to close all other Femtet processes before running.**
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. This may take tens of seconds.')
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, # n_parallel = n_parallel - 1 + 1; main 分減らし、monitor 分増やす
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. "