pyfemtet 0.5.2__py3-none-any.whl → 0.5.4__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 (54) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/{message → _message}/locales/ja/LC_MESSAGES/messages.po +88 -76
  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/_femopt.py +236 -58
  11. pyfemtet/opt/_femopt_core.py +21 -8
  12. pyfemtet/opt/_test_utils/record_history.py +1 -1
  13. pyfemtet/opt/interface/__init__.py +0 -1
  14. pyfemtet/opt/interface/_base.py +3 -3
  15. pyfemtet/opt/interface/_femtet.py +101 -55
  16. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +35 -12
  17. pyfemtet/opt/interface/_femtet_with_sldworks.py +22 -2
  18. pyfemtet/opt/optimizer/_base.py +76 -42
  19. pyfemtet/opt/optimizer/_optuna.py +33 -1
  20. pyfemtet/opt/optimizer/_optuna_botorchsampler_parameter_constraint_helper.py +1 -2
  21. pyfemtet/opt/optimizer/_scipy.py +20 -5
  22. pyfemtet/opt/optimizer/_scipy_scalar.py +20 -5
  23. pyfemtet/opt/prediction/{base.py → _base.py} +3 -2
  24. pyfemtet/opt/prediction/single_task_gp.py +10 -5
  25. pyfemtet/opt/visualization/{base.py → _base.py} +1 -1
  26. pyfemtet/opt/visualization/{complex_components → _complex_components}/alert_region.py +2 -2
  27. pyfemtet/opt/visualization/{complex_components → _complex_components}/control_femtet.py +3 -3
  28. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_figure_creator.py +1 -1
  29. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_graph.py +5 -5
  30. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph.py +5 -5
  31. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph_creator.py +2 -2
  32. pyfemtet/opt/visualization/_create_wrapped_components.py +2 -2
  33. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/application.py +3 -3
  34. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/pages.py +10 -10
  35. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dbc.py +1 -1
  36. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dcc.py +1 -1
  37. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/html.py +1 -1
  38. pyfemtet/opt/visualization/result_viewer/application.py +4 -4
  39. pyfemtet/opt/visualization/result_viewer/pages.py +9 -9
  40. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/METADATA +2 -2
  41. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/RECORD +53 -51
  42. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/WHEEL +1 -1
  43. pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo +0 -0
  44. /pyfemtet/{message → _message}/1. make_pot.bat +0 -0
  45. /pyfemtet/{message → _message}/2. make_mo.bat +0 -0
  46. /pyfemtet/{message → _message}/__init__.py +0 -0
  47. /pyfemtet/{message → _message}/babel.cfg +0 -0
  48. /pyfemtet/opt/{parameter.py → optimizer/parameter.py} +0 -0
  49. /pyfemtet/opt/visualization/{complex_components → _complex_components}/__init__.py +0 -0
  50. /pyfemtet/opt/visualization/{process_monitor → _process_monitor}/__init__.py +0 -0
  51. /pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/__init__.py +0 -0
  52. /pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/str_enum.py +0 -0
  53. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/LICENSE +0 -0
  54. {pyfemtet-0.5.2.dist-info → pyfemtet-0.5.4.dist-info}/entry_points.txt +0 -0
pyfemtet/opt/_femopt.py CHANGED
@@ -17,7 +17,7 @@ from dask.distributed import LocalCluster, Client, Worker
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,8 +28,9 @@ 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
 
34
35
 
35
36
  def add_worker(client, worker_name):
@@ -54,27 +55,47 @@ def add_worker(client, worker_name):
54
55
  client.wait_for_workers(n_workers=current_n_workers + 1)
55
56
 
56
57
 
57
-
58
58
  class FEMOpt:
59
59
  """Class to control FEM interface and optimizer.
60
60
 
61
61
  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.
62
+ fem (FEMInterface, optional):
63
+ The FEM software interface.
64
+ Defaults to None (automatically set to :class:`FemtetInterface`).
65
+
66
+ opt (AbstractOptimizer, optional):
67
+ The numerical optimizer object.
68
+ Defaults to None (automatically set to :class:`OptunaOptimizer`
69
+ with :class:`optuna.samplers.TPESampler`).
70
+
71
+ history_path (str, optional):
72
+ The path to the history file.
73
+ Defaults to None.
74
+ If None, '%Y_%m_%d_%H_%M_%S.csv' is created in current directory.
75
+
76
+ scheduler_address (str, optional):
77
+ When performing cluster computing, please specify the address
78
+ of the scheduler computer here.
79
+
80
+ See Also:
81
+ https://pyfemtet.readthedocs.io/en/stable/pages/usage_pages/how_to_deploy_cluster.html
82
+
83
+ .. Example の中について、reST ではリストだと改行できないので、リストにしない
84
+
85
+ Examples:
86
+
87
+ When specifying and opening a femprj and model, we write
88
+
89
+ >>> from pyfemtet.opt import FEMOpt, FemtetInterface # doctest: +SKIP
90
+ >>> fem = FemtetInterface(femprj_path='path/to/project.femprj', model_name='NewModel') # doctest: +SKIP
91
+ >>> femopt = FEMOpt(fem=fem) # doctest: +SKIP
92
+
93
+ When specifying optimization algorithm, we write
94
+
95
+ >>> from optuna.samplers import TPESampler # doctest: +SKIP
96
+ >>> from pyfemtet.opt import FEMOpt, OptunaOptimizer # doctest: +SKIP
97
+ >>> opt = OptunaOptimizer(sampler_class=TPESampler, sampler_kwargs=dict(n_startup_trials=10)) # doctest: +SKIP
98
+ >>> femopt = FEMOpt(opt=opt) # doctest: +SKIP
78
99
 
79
100
  """
80
101
 
@@ -133,25 +154,40 @@ class FEMOpt:
133
154
  def add_parameter(
134
155
  self,
135
156
  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,
157
+ initial_value: float = None,
158
+ lower_bound: float = None,
159
+ upper_bound: float = None,
160
+ step: float = None,
161
+ properties: dict[str, str or float] = None,
162
+ pass_to_fem: bool = True,
142
163
  ):
164
+ # noinspection PyUnresolvedReferences
143
165
  """Adds a parameter to the optimization problem.
144
166
 
145
167
  Args:
146
168
  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.
169
+ initial_value (float, optional): The initial value of the parameter. Defaults to None. If None, try to get initial value from FEMInterface.
170
+ lower_bound (float, optional): The lower bound of the parameter. Defaults to None. Some optimization algorithms require this.
171
+ upper_bound (float or None, optional): The upper bound of the parameter. Defaults to None. Some optimization algorithms require this.
172
+ step (float, optional): The step of parameter. If specified, parameter is used as discrete. Defaults to None.
173
+ properties (dict[str, str or float], optional): Additional information about the parameter. Defaults to None.
152
174
  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.
175
+
153
176
  Raises:
154
- ValueError: If initial_value is not specified and the value for the given name is also not specified.
177
+ ValueError: If initial_value is not specified and the value for the given name is also not specified in FEM.
178
+
179
+ Examples:
180
+
181
+ When adding parameter a (-1 <= a <= 1; initial value is 0), we write
182
+
183
+ >>> femopt.add_parameter('parameter_a', 0, -1, 1) # doctest: +SKIP
184
+
185
+ Note that the ```note``` argument can be set any name in this case.
186
+
187
+ When adding discrete parameter a (-1 <= a <= 1; initial value is 0,
188
+ step 0.5), we write
189
+
190
+ >>> femopt.add_parameter('parameter a', 0, -1, 1, 0.5) # doctest: +SKIP
155
191
 
156
192
  """
157
193
 
@@ -179,23 +215,73 @@ class FEMOpt:
179
215
  )
180
216
  self.opt.variables.add_parameter(prm)
181
217
 
218
+ @experimental_feature
182
219
  def add_expression(
183
220
  self,
184
221
  name: str,
185
222
  fun: Callable[[Any], float],
186
- properties=property,
223
+ properties: dict[str, str or float] = None,
187
224
  kwargs: Optional[dict] = None,
188
225
  pass_to_fem=True,
189
226
  ):
227
+ # noinspection PyUnresolvedReferences
190
228
  """Add expression to the optimization problem.
191
229
 
230
+ Warnings:
231
+ This feature is highly experimental and
232
+ may change in the future.
233
+
192
234
  Args:
193
235
  name (str): The name of the variable.
194
236
  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.
237
+ properties (dict[str, str or float], optional): Additional information about the parameter. Defaults to None.
196
238
  kwargs (Optional[dict], optional): Remaining arguments of ``fun``. Defaults to None.
197
239
  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.
240
+
241
+ Examples:
242
+
243
+ When adding variable a and b; a is not directly included as model
244
+ variables but an optimization parameter, b is not a parameter but
245
+ a model variable and the relationship of these 2 variables is
246
+ ```b = a ** 2```, we write:
247
+
248
+ >>> def calc_b(parameter_a): # doctest: +SKIP
249
+ ... return parameter_a ** 2 # doctest: +SKIP
250
+ ...
251
+ >>> femopt.add_parameter('parameter_a', 0, -1, 1, pass_to_fem=False) # doctest: +SKIP
252
+ >>> femopt.add_expression('variable_b', calc_b) # doctest: +SKIP
253
+
254
+ Notes:
255
+ The argument names of function to calculate variable
256
+ must match the ```name``` of the parameter.
257
+
258
+ Notes:
259
+ In this case, only strings that can be used as Python variables are valid
260
+ for ```name``` argument of :func:`FEMOpt.add_parameter`.
261
+
262
+ When adding variable r, theta and x, y; r, theta is an optimization
263
+ parameter and x, y is an intermediate variable to calculate constraint
264
+ function, we write
265
+
266
+ >>> def calc_x(r, theta): # doctest: +SKIP
267
+ ... return r * cos(theta) # doctest: +SKIP
268
+ ...
269
+ >>> def calc_y(r, theta): # doctest: +SKIP
270
+ ... return r * cos(theta) # doctest: +SKIP
271
+ ...
272
+ >>> def constraint(Femtet, opt: AbstractOptimizer): # doctest: +SKIP
273
+ ... d = opt.variables.get_variables() # doctest: +SKIP
274
+ ... x, y = d['x'], d['y'] # doctest: +SKIP
275
+ ... return min(x, y) # doctest: +SKIP
276
+ ...
277
+ >>> femopt.add_parameter('r', 0, 0, 1) # doctest: +SKIP
278
+ >>> femopt.add_parameter('theta', 0, 0, 2*pi) # doctest: +SKIP
279
+ >>> femopt.add_expression('x', calc_x, pass_to_fem=False) # doctest: +SKIP
280
+ >>> femopt.add_expression('y', calc_y, pass_to_fem=False) # doctest: +SKIP
281
+ >>> femopt.add_constraint(constraint, lower_bound=0.5, args=(femopt.opt,)) # doctest: +SKIP
282
+
198
283
  """
284
+
199
285
  exp = Expression(
200
286
  name=name,
201
287
  value=None,
@@ -214,18 +300,39 @@ class FEMOpt:
214
300
  args: tuple or None = None,
215
301
  kwargs: dict or None = None
216
302
  ):
303
+ # noinspection PyUnresolvedReferences
217
304
  """Adds an objective to the optimization problem.
218
305
 
219
306
  Args:
220
307
  fun (callable): The objective function.
221
308
  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'.
309
+ direction (str or float, optional): The optimization direction. Varid values are 'maximize', 'minimize' or a float value. Defaults to 'minimize'.
223
310
  args (tuple or None, optional): Additional arguments for the objective function. Defaults to None.
224
311
  kwargs (dict or None, optional): Additional keyword arguments for the objective function. Defaults to None.
225
312
 
226
313
  Note:
227
314
  If the FEMInterface is FemtetInterface, the 1st argument of fun should be Femtet (IPyDispatch) object.
228
315
 
316
+ Examples:
317
+
318
+ When add a complex objective (for example, want to dynamically set body
319
+ to calculate temperature and use product of the temperature and one of
320
+ the parameters as objective) , we write
321
+
322
+ >>> class MyClass: # doctest: +SKIP
323
+ ... def get_body_name(self): # doctest: +SKIP
324
+ ... ... # process something and detect body name # doctest: +SKIP
325
+ ... return body_name # doctest: +SKIP
326
+ ...
327
+ >>> def complex_objective(Femtet, opt, some_object): # doctest: +SKIP
328
+ ... body_name = some_object.get_body_name() # dynamically get body name to calculate temperature # doctest: +SKIP
329
+ ... temp, _, _ = Femtet.Gogh.Watt.GetTemp(body_name) # calculate temperature # doctest: +SKIP
330
+ ... some_param = opt.get_parameter()['some_param'] # get ome parameter # doctest: +SKIP
331
+ ... return temp * some_param # calculate something and return it # doctest: +SKIP
332
+ ...
333
+ >>> my_obj = MyClass() # doctest: +SKIP
334
+ >>> femopt.add_objective(complex_objective, args=(femopt.opt, my_obj,)) # doctest: +SKIP
335
+
229
336
  Tip:
230
337
  If name is None, name is a string with the prefix `"obj_"` followed by a sequential number.
231
338
 
@@ -263,6 +370,7 @@ class FEMOpt:
263
370
  kwargs: dict or None = None,
264
371
  using_fem: bool = None,
265
372
  ):
373
+ # noinspection PyUnresolvedReferences
266
374
  """Adds a constraint to the optimization problem.
267
375
 
268
376
  Args:
@@ -275,6 +383,36 @@ class FEMOpt:
275
383
  kwargs (dict): Additional arguments for the constraint function. Defaults to None.
276
384
  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
385
 
386
+ Warnings:
387
+
388
+ When ```strict``` == True and using OptunaOptimizer along with BoTorchSampler,
389
+ Pyfemtet will solve an optimization subproblem to propose new variables.
390
+ During this process, the constraint function fun will be executed at each
391
+ iteration of the subproblem, which may include time-consuming operations such
392
+ as retrieving 3D model information via FEMInterface.
393
+ As a result, it may not be feasible to complete the overall optimization within
394
+ a realistic timeframe.
395
+
396
+ Examples:
397
+ For example, in a case where the bottom area of the model is constrained,
398
+ the following approach may require a very long time.
399
+
400
+ >>> def bottom_area(Femtet, opt): # doctest: +SKIP
401
+ ... w = Femtet.GetVariableValue('width') # doctest: +SKIP
402
+ ... d = Femtet.GetVariableValue('depth') # doctest: +SKIP
403
+ ... return w * d # doctest: +SKIP
404
+ ...
405
+ >>> femopt.add_constraint(constraint, lower_bound=5) # doctest: +SKIP
406
+
407
+ Instead, please do the following.
408
+
409
+ >>> def bottom_area(_, opt): # 第一引数 Femtet にはアクセスしないようにします。 # doctest: +SKIP
410
+ ... params = opt.get_parameter() # doctest: +SKIP
411
+ ... w, d = params['width'], params['depth'] # doctest: +SKIP
412
+ ... return w * d # doctest: +SKIP
413
+ ...
414
+ >>> femopt.add_constraint(constraint, lower_bound=5, args=(femopt.opt,)) # doctest: +SKIP
415
+
278
416
  Note:
279
417
  If the FEMInterface is FemtetInterface, the 1st argument of fun should be Femtet (IPyDispatch) object.
280
418
 
@@ -330,22 +468,32 @@ class FEMOpt:
330
468
  self.opt.constraints[name] = Constraint(fun, name, lower_bound, upper_bound, strict, args, kwargs, using_fem)
331
469
 
332
470
  def get_parameter(self, format='dict'):
333
- raise DeprecationWarning('FEMOpt.get_parameter() was deprecated. Use Femopt.opt.get_parameter() instead.')
471
+ """Deprecated method.
472
+
473
+ Planed to remove in future version. Use FEMOpt.opt.get_parameter() instead.
474
+ """
475
+ raise DeprecationWarning('FEMOpt.get_parameter() was deprecated. Use FEMOpt.opt.get_parameter() instead.')
334
476
 
335
477
  def set_monitor_host(self, host=None, port=None):
336
- """Sets up the monitor server with the specified host and port.
478
+ """Sets the host IP address and the port of the process monitor.
337
479
 
338
480
  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.
481
+ host (str):
482
+ The hostname or IP address of the monitor server.
483
+ port (int, optional):
484
+ The port number of the monitor server.
485
+ If None, ``8080`` will be used.
486
+ Defaults to None.
341
487
 
342
488
  Tip:
343
- Specifying host ``0.0.0.0`` allows viewing monitor from all computers on the local network.
489
+ Specifying host ``0.0.0.0`` allows viewing monitor
490
+ from all computers on the local network.
344
491
 
345
- However, please note that in this case,
346
- it will be visible to all users on the local network.
492
+ If no hostname is specified, the monitor server
493
+ will be hosted on ``localhost``.
347
494
 
348
- If no hostname is specified, the monitor server will be hosted on ``localhost``.
495
+ We can access process monitor by accessing
496
+ ```localhost:8080``` on our browser by default.
349
497
 
350
498
  """
351
499
  self.monitor_server_kwargs = dict(
@@ -355,33 +503,57 @@ class FEMOpt:
355
503
 
356
504
  def optimize(
357
505
  self,
358
- n_trials=None,
359
- n_parallel=1,
360
- timeout=None,
361
- wait_setup=True,
362
- confirm_before_exit=True,
506
+ n_trials: int = None,
507
+ n_parallel: int = 1,
508
+ timeout: float = None,
509
+ wait_setup: bool = True,
510
+ confirm_before_exit: bool = True,
363
511
  ):
364
512
  """Runs the main optimization process.
365
513
 
366
514
  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.
515
+ n_trials (int, optional):
516
+ The number of trials.
517
+ Defaults to None.
518
+ n_parallel (int, optional):
519
+ The number of parallel processes.
520
+ Defaults to 1.
521
+ Note that even if this argument is 1,
522
+ :class:`FEMOpt` makes some child processes
523
+ to run process monitor, status monitor, etc.
524
+ timeout (float, optional):
525
+ The maximum amount of time in seconds
526
+ that each trial can run.
527
+ Defaults to None.
528
+ wait_setup (bool, optional):
529
+ Wait for all workers launching FEM system.
530
+ Defaults to True.
531
+ confirm_before_exit (bool, optional):
532
+ Insert stop before exit to continue to
533
+ show process monitor.
372
534
 
373
535
  Tip:
374
- If set_monitor_host() is not executed, a local server for monitoring will be started at localhost:8080.
536
+ If set_monitor_host() is not executed,
537
+ a local server for monitoring will be
538
+ started at localhost:8080.
539
+
540
+ See Also:
541
+ :func:`FEMOpt.set_monitor_host`
375
542
 
376
543
  Note:
377
- If ``n_trials`` and ``timeout`` are both None, it runs forever until interrupting by the user.
544
+ If ``n_trials`` and ``timeout`` are both None,
545
+ it runs forever until interrupting by the user.
378
546
 
379
547
  Note:
380
- If ``n_parallel`` >= 2, depending on the end timing, ``n_trials`` may be exceeded by up to ``n_parallel-1`` times.
548
+ If ``n_parallel`` >= 2, depending on the end timing,
549
+ ``n_trials`` may be exceeded by up to ``n_parallel-1`` times.
381
550
 
382
551
  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.**
552
+ If ``n_parallel`` >= 2 and ``fem`` is a subclass of
553
+ ``FemtetInterface``, the ``strictly_pid_specify`` of
554
+ subprocess is set to ``False``.
555
+ So **it is recommended to close all other Femtet processes
556
+ before running.**
385
557
 
386
558
  """
387
559
 
@@ -510,6 +682,7 @@ class FEMOpt:
510
682
  logger.info('Status Actor initialized successfully.')
511
683
 
512
684
  # launch monitor
685
+ # noinspection PyTypeChecker
513
686
  self.monitor_process_future = _client.submit(
514
687
  # func
515
688
  _start_monitor_server,
@@ -634,6 +807,11 @@ class FEMOpt:
634
807
 
635
808
  @staticmethod
636
809
  def terminate_all():
810
+ """Deprecated method. We plan to remove this in future version.
811
+
812
+ In current version, the termination processes are
813
+ automatically execute in the last of :func:`FEMOpt.optimize`.
814
+ """
637
815
  warnings.warn(
638
816
  "terminate_all() is deprecated and will be removed in a future version. "
639
817
  "In current and later versions, the equivalent of terminate_all() will be executed when optimize() finishes. "
@@ -8,13 +8,20 @@ import inspect
8
8
  import ast
9
9
  import csv
10
10
  import ctypes
11
+ from packaging import version
11
12
 
12
13
  # 3rd-party
13
14
  import numpy as np
14
15
  import pandas as pd
15
16
  from scipy.stats.qmc import LatinHypercube
16
17
  import optuna
17
- from optuna._hypervolume import WFG
18
+ if version.parse(optuna.version.__version__) < version.parse('4.0.0'):
19
+ from optuna._hypervolume import WFG
20
+ wfg = WFG()
21
+ compute_hypervolume = wfg.compute
22
+ else:
23
+ from optuna._hypervolume import wfg
24
+ compute_hypervolume = wfg.compute_hypervolume
18
25
  from dask.distributed import Lock, get_client
19
26
 
20
27
  # win32com
@@ -22,7 +29,7 @@ from win32com.client import constants, Constants
22
29
 
23
30
  # pyfemtet relative
24
31
  from pyfemtet.opt.interface import FEMInterface, FemtetInterface
25
- from pyfemtet.message import encoding, Msg
32
+ from pyfemtet._message import encoding, Msg
26
33
 
27
34
  # logger
28
35
  import logging
@@ -708,20 +715,27 @@ class History:
708
715
 
709
716
  def _calc_non_domi(self, objectives, df):
710
717
 
718
+ # feasible のもののみ取り出してくる
719
+ idx = df['feasible'].values
720
+ pdf = df[idx]
721
+
711
722
  # 目的関数の履歴を取り出してくる
712
- solution_set = df[self.obj_names]
723
+ solution_set = pdf[self.obj_names]
713
724
 
714
725
  # 最小化問題の座標空間に変換する
715
726
  for obj_column, (_, objective) in zip(self.obj_names, objectives.items()):
716
727
  solution_set.loc[:, obj_column] = solution_set[obj_column].map(objective.convert)
717
728
 
718
729
  # 非劣解の計算
719
- non_domi = []
730
+ non_domi: list[bool] = []
720
731
  for i, row in solution_set.iterrows():
721
732
  non_domi.append((row > solution_set).product(axis=1).sum(axis=0) == 0)
722
733
 
723
- # 非劣解の登録
724
- df['non_domi'] = non_domi
734
+ # feasible も infeasible も一旦劣解にする
735
+ df['non_domi'] = False
736
+
737
+ # feasible のものに non_domi の評価結果を代入する
738
+ df.loc[idx, 'non_domi'] = non_domi
725
739
 
726
740
  def _calc_hypervolume(self, objectives, df):
727
741
 
@@ -753,10 +767,9 @@ class History:
753
767
  reference_point = r * (maximum - minimum) + minimum
754
768
 
755
769
  #### hv 履歴の計算
756
- wfg = WFG()
757
770
  hvs = []
758
771
  for i in range(n):
759
- hv = wfg.compute(pareto_set[:i], reference_point)
772
+ hv = compute_hypervolume(pareto_set[:i], reference_point)
760
773
  if np.isnan(hv):
761
774
  hv = 0
762
775
  hvs.append(hv)
@@ -7,7 +7,7 @@ import numpy as np
7
7
  import pandas as pd
8
8
 
9
9
  from pyfemtet.opt import FEMOpt
10
- from pyfemtet.message import encoding as ENCODING
10
+ from pyfemtet._message import encoding as ENCODING
11
11
 
12
12
 
13
13
  def find_latest_csv(dir_path=None):
@@ -11,5 +11,4 @@ __all__ = [
11
11
  'FemtetInterface',
12
12
  'FemtetWithNXInterface',
13
13
  'FemtetWithSolidworksInterface',
14
- 'logger',
15
14
  ]
@@ -68,15 +68,15 @@ class FEMInterface(ABC):
68
68
  """Preprocessing after launching a dask worker and before run optimization (if implemented in concrete class)."""
69
69
  pass
70
70
 
71
- def postprocess_func(self, trial: int, *args, dask_scheduler=None, **kwargs):
71
+ def _postprocess_func(self, trial: int, *args, dask_scheduler=None, **kwargs):
72
72
  pass
73
73
 
74
- def create_postprocess_args(self):
74
+ def _create_postprocess_args(self):
75
75
  pass
76
76
 
77
77
 
78
78
  class NoFEM(FEMInterface):
79
- """Interface with no FEM for debug."""
79
+ """Dummy interface without FEM. Intended for debugging purposes."""
80
80
 
81
81
  def update(self, parameters: pd.DataFrame) -> None:
82
82
  pass