pyfemtet 0.4.12__py3-none-any.whl → 0.4.14__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 (111) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/dispatch_extensions.py +4 -0
  3. pyfemtet/message/1. make_pot.bat +12 -0
  4. pyfemtet/message/2. make_mo.bat +6 -0
  5. pyfemtet/message/__init__.py +5 -0
  6. pyfemtet/message/babel.cfg +2 -0
  7. pyfemtet/message/locales/ja/LC_MESSAGES/messages.po +449 -0
  8. pyfemtet/message/locales/messages.pot +439 -0
  9. pyfemtet/message/messages.py +174 -0
  10. pyfemtet/opt/_femopt.py +9 -9
  11. pyfemtet/opt/_femopt_core.py +22 -17
  12. pyfemtet/opt/femprj_sample/ParametricIF - True.femprj +0 -0
  13. pyfemtet/opt/femprj_sample/ParametricIF.femprj +0 -0
  14. pyfemtet/opt/femprj_sample/ParametricIF.py +31 -0
  15. pyfemtet/opt/femprj_sample/ParametricIF_test_result.reccsv +13 -0
  16. pyfemtet/opt/femprj_sample/cad_ex01_NX_test_result.reccsv +13 -13
  17. pyfemtet/opt/femprj_sample/cad_ex01_SW_test_result.reccsv +13 -13
  18. pyfemtet/opt/femprj_sample/gal_ex58_parametric_test_result.reccsv +13 -13
  19. pyfemtet/opt/femprj_sample/gau_ex08_parametric_test_result.reccsv +23 -23
  20. pyfemtet/opt/femprj_sample/her_ex40_parametric_test_result.reccsv +18 -18
  21. pyfemtet/opt/femprj_sample/paswat_ex1_parametric_test_result.reccsv +18 -18
  22. pyfemtet/opt/femprj_sample/tutorial.femprj +0 -0
  23. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  24. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  25. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
  26. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  27. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
  28. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  29. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  30. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  31. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  32. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  33. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  34. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  35. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  36. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  37. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  38. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  39. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
  40. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  41. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
  42. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  43. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
  44. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  45. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
  46. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  47. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
  48. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  49. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
  50. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  51. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
  52. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  53. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
  54. pyfemtet/opt/femprj_sample/wat_ex14_parametric_test_result.reccsv +18 -18
  55. pyfemtet/opt/femprj_sample_jp/ParametricIF_jp.femprj +0 -0
  56. pyfemtet/opt/femprj_sample_jp/ParametricIF_jp.py +31 -0
  57. pyfemtet/opt/interface/_femtet.py +45 -47
  58. pyfemtet/opt/interface/_femtet_parametric.py +7 -2
  59. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +4 -4
  60. pyfemtet/opt/interface/_femtet_with_nx/update_model.py +6 -6
  61. pyfemtet/opt/interface/_femtet_with_sldworks.py +5 -4
  62. pyfemtet/opt/opt/__init__.py +2 -0
  63. pyfemtet/opt/opt/_base.py +41 -20
  64. pyfemtet/opt/opt/_optuna.py +8 -13
  65. pyfemtet/opt/opt/_scipy.py +4 -8
  66. pyfemtet/opt/opt/_scipy_scalar.py +1 -5
  67. pyfemtet/opt/prediction/__init__.py +0 -0
  68. pyfemtet/opt/prediction/base.py +52 -0
  69. pyfemtet/opt/prediction/single_task_gp.py +82 -0
  70. pyfemtet/opt/visualization/complex_components/control_femtet.py +9 -11
  71. pyfemtet/opt/visualization/complex_components/main_figure_creator.py +24 -11
  72. pyfemtet/opt/visualization/complex_components/main_graph.py +3 -4
  73. pyfemtet/opt/visualization/complex_components/pm_graph.py +715 -0
  74. pyfemtet/opt/visualization/complex_components/pm_graph_creator.py +168 -0
  75. pyfemtet/opt/visualization/process_monitor/application.py +16 -12
  76. pyfemtet/opt/visualization/process_monitor/pages.py +22 -7
  77. pyfemtet/opt/visualization/result_viewer/application.py +8 -3
  78. pyfemtet/opt/visualization/result_viewer/pages.py +59 -47
  79. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/METADATA +2 -1
  80. pyfemtet-0.4.14.dist-info/RECORD +151 -0
  81. pyfemtet/opt/visualization/result_viewer/tutorial/tutorial.csv +0 -18
  82. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.jpg +0 -0
  83. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.log +0 -81
  84. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  85. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow.csv +0 -28
  86. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow_el.csv +0 -22
  87. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  88. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  89. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  90. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  91. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  92. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  93. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  94. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  95. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  96. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  97. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  98. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  99. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  100. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  101. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  102. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  103. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  104. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  105. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  106. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  107. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.femprj +0 -0
  108. pyfemtet-0.4.12.dist-info/RECORD +0 -138
  109. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/LICENSE +0 -0
  110. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/WHEEL +0 -0
  111. {pyfemtet-0.4.12.dist-info → pyfemtet-0.4.14.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,31 @@
1
+ from pyfemtet.opt import FemtetInterface, FEMOpt, AbstractOptimizer
2
+
3
+
4
+ def ex_in(_, opt: AbstractOptimizer):
5
+ ex_r, in_r = opt.get_parameter('values')
6
+ return ex_r - in_r
7
+
8
+
9
+
10
+ if __name__ == '__main__':
11
+
12
+ fem = FemtetInterface(
13
+ parametric_output_indexes_use_as_objective={
14
+ 0: "minimize",
15
+ 1: "minimize",
16
+ 2: "minimize",
17
+ },
18
+ )
19
+
20
+ femopt = FEMOpt(fem=fem)
21
+
22
+ femopt.add_parameter("external_radius", 10, 1, 10)
23
+ femopt.add_parameter("internal_radius", 5, 1, 10)
24
+ femopt.add_constraint(ex_in, lower_bound=1, strict=True, args=(femopt.opt,))
25
+ femopt.set_random_seed(42)
26
+ femopt.optimize(
27
+ n_trials=10,
28
+ n_parallel=1,
29
+ )
30
+ input('enter to quit') # required to tests script
31
+ femopt.terminate_all()
@@ -33,6 +33,7 @@ from pyfemtet.dispatch_extensions import (
33
33
  DispatchExtensionException,
34
34
  )
35
35
  from pyfemtet.opt.interface import FEMInterface, logger
36
+ from pyfemtet.message import Msg
36
37
 
37
38
 
38
39
  def post_activate_message(hwnd):
@@ -204,17 +205,15 @@ class FemtetInterface(FEMInterface):
204
205
  if not hasattr(constants, 'STATIC_C'):
205
206
  cmd = f'{sys.executable} -m win32com.client.makepy FemtetMacro'
206
207
  os.system(cmd)
207
- message = 'Femtet python マクロ定数の設定が完了してないことを検出しました.'
208
- message += '設定は自動で行われました(python -m win32com.client.makepy FemtetMacro).'
209
- message += 'プログラムを再起動してください.'
208
+ message = Msg.ERR_NO_MAKEPY
210
209
  print('================')
211
210
  print(message)
212
211
  print('================')
213
- input('終了するには Enter を押してください。')
212
+ input('Press enter to finish...')
214
213
  raise RuntimeError(message)
215
214
 
216
215
  if self.Femtet is None:
217
- raise RuntimeError('Femtet との接続に失敗しました.')
216
+ raise RuntimeError(Msg.ERR_FEMTET_CONNECTION_FAILED)
218
217
 
219
218
  def _call_femtet_api(
220
219
  self,
@@ -291,10 +290,13 @@ class FemtetInterface(FEMInterface):
291
290
  # API を実行
292
291
  try:
293
292
  # 解析結果を開いた状態で Gaudi.Activate して ReExecute する場合、ReExecute の前後にアクティブ化イベントが必要
293
+ # さらに、プロジェクトツリーが開いていないとアクティブ化イベントも意味がないらしい。
294
294
  if fun.__name__ == 'ReExecute':
295
- post_activate_message(self.Femtet.hWnd) # can raise pywintypes.error
296
- returns = fun(*args, **kwargs)
297
- post_activate_message(self.Femtet.hWnd)
295
+ if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
296
+ post_activate_message(self.Femtet.hWnd)
297
+ returns = fun(*args, **kwargs) # can raise pywintypes.error
298
+ if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
299
+ post_activate_message(self.Femtet.hWnd)
298
300
  else:
299
301
  returns = fun(*args, **kwargs)
300
302
  except (com_error, error):
@@ -331,20 +333,19 @@ class FemtetInterface(FEMInterface):
331
333
  # 再起動試行回数の上限に達していたら諦める
332
334
  logger.debug(' ' * print_indent + f'現在の Femtet 再起動回数: {recourse_depth}')
333
335
  if recourse_depth >= self.max_api_retry:
334
- raise Exception('Femtet のプロセスが異常終了し、正常に再起動できませんでした.')
336
+ raise Exception(Msg.ERR_FEMTET_CRASHED_AND_RESTART_FAILED)
335
337
 
336
338
  # 再起動
337
- logger.warn('Femtet プロセスの異常終了が検知されました. 回復を試みます.')
339
+ logger.warn(' ' * print_indent + Msg.WARN_FEMTET_CRASHED_AND_TRY_RESTART)
338
340
  CoInitialize()
339
341
  self.connect_femtet(connect_method='new')
340
342
  self.open(self.femprj_path, self.model_name)
341
343
 
342
344
  # 状態を復元するために一度変数を渡して解析を行う(fun.__name__がSolveなら2度手間だが)
343
- logger.info(' ' * print_indent + f'Femtet が再起動されました。解析を行い、状態回復を試みます。')
345
+ logger.info(' ' * print_indent + Msg.INFO_FEMTET_CRASHED_AND_RESTARTED)
344
346
  self.update(self.parameters)
345
347
 
346
348
  # 与えられた API の再帰的再試行
347
- logger.info(' ' * print_indent + f'Femtet が回復されました。コマンド {fun.__name__} を再試行します。')
348
349
  return self._call_femtet_api(
349
350
  fun,
350
351
  return_value_if_failed,
@@ -423,16 +424,15 @@ class FemtetInterface(FEMInterface):
423
424
  (self.connect_method == 'new')
424
425
  and (not self.allow_without_project)
425
426
  ):
426
- raise RuntimeError(
427
- 'femprj_path を指定せず Femtet の connect_method に "new" を指定する場合、"allow_without_project" 引数を True に設定してください。')
427
+ raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
428
+
428
429
  # さらに auto の場合は Femtet が存在しなければ new と同じ挙動になるので同様の処理
429
430
  if (
430
431
  (self.connect_method == 'auto')
431
432
  and (len(_get_pids(process_name='Femtet.exe')) == 0)
432
433
  and (not self.allow_without_project)
433
434
  ):
434
- raise RuntimeError(
435
- 'femprj_path を指定せず Femtet の connect_method を指定しない(又は "auto" に指定する)場合、Femtet を起動して処理したい .femprj ファイルを開いた状態にしてください。')
435
+ raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
436
436
  self.connect_femtet(self.connect_method)
437
437
 
438
438
  # 最終的に接続した Femtet の femprj_path と model を インスタンスに戻す
@@ -452,25 +452,22 @@ class FemtetInterface(FEMInterface):
452
452
  try:
453
453
  variable_names = self.Femtet.GetVariableNames_py()
454
454
  except AttributeError as e:
455
- message = 'GetVariableNames_py' + 'にアクセスできません。'
456
- f'Femtet {major}.{minor}.{bugfix} 以降で「マクロの有効化」が行われていない可能性があります。'
457
- 'スタートメニューから、インストールされいてる Femtet と同一バージョンの「マクロ機能を有効化する」コマンドを管理者権限で実行してください。'
458
455
  print('================')
459
- logger.error(message)
456
+ logger.error(Msg.ERR_CANNOT_ACCESS_API + 'GetVariableNames_py')
457
+ logger.error(Msg.CERTIFY_MACRO_VERSION)
460
458
  print('================')
461
- input('終了するには Enter を押してください。')
459
+ input(Msg.ENTER_TO_QUIT)
462
460
  raise e
463
461
 
464
462
  if variable_names is not None:
465
463
  if param_name in variable_names:
466
464
  return self.Femtet.GetVariableValue(param_name)
467
- message = f'Femtet 解析モデルに変数 {param_name} がありません.'
468
- message += f'現在のモデルに設定されている変数は {variable_names} です.'
469
- message += '大文字・小文字の区別に注意してください.'
465
+ message = Msg.ERR_NO_SUCH_PARAMETER_IN_FEMTET
470
466
  print('================')
471
467
  logger.error(message)
468
+ logger.error(f'`{param_name}` not in {variable_names}')
472
469
  print('================')
473
- input('終了するには Enter を押してください。')
470
+ input(Msg.ENTER_TO_QUIT)
474
471
  raise RuntimeError(message)
475
472
  else:
476
473
  return None
@@ -485,7 +482,7 @@ class FemtetInterface(FEMInterface):
485
482
  self.Femtet.Gaudi.Activate,
486
483
  True, # 戻り値を持たないのでここは無意味で None 以外なら何でもいい
487
484
  Exception, # 生きてるのに開けない場合
488
- error_message='解析モデルが開かれていません',
485
+ error_message=Msg.NO_ANALYSIS_MODEL_IS_OPEN,
489
486
  )
490
487
 
491
488
  major, minor, bugfix = 2023, 1, 1
@@ -495,14 +492,14 @@ class FemtetInterface(FEMInterface):
495
492
  fun=self.Femtet.GetVariableNames_py,
496
493
  return_value_if_failed=False, # 意味がない
497
494
  if_error=ModelError, # 生きてるのに失敗した場合
498
- error_message=f'GetVariableNames_py に失敗しました。',
495
+ error_message=f'GetVariableNames_py failed.',
499
496
  is_Gaudi_method=True,
500
497
  )
501
498
 
502
499
  # 変数を含まないプロジェクトである場合
503
500
  if existing_variable_names is None:
504
501
  if with_warning:
505
- return ['解析モデルに変数が含まれていません。']
502
+ return [Msg.FEMTET_ANALYSIS_MODEL_WITH_NO_PARAMETER]
506
503
  else:
507
504
  return None
508
505
 
@@ -516,12 +513,12 @@ class FemtetInterface(FEMInterface):
516
513
  fun=self.Femtet.UpdateVariable,
517
514
  return_value_if_failed=False,
518
515
  if_error=ModelError, # 生きてるのに失敗した場合
519
- error_message=f'変数の更新に失敗しました:変数{name}, {value}',
516
+ error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE + f'{value} -> {name}',
520
517
  is_Gaudi_method=True,
521
518
  args=(name, value),
522
519
  )
523
520
  else:
524
- msg = f'変数 {name} 解析モデル {self.model_name} に含まれていません。無視されます。'
521
+ msg = f'{name} not in {self.model_name}: ' + Msg.WARN_IGNORE_PARAMETER_NOT_CONTAINED
525
522
  warnings.append(msg)
526
523
  logger.warn(msg)
527
524
 
@@ -535,7 +532,7 @@ class FemtetInterface(FEMInterface):
535
532
  fun=self.Femtet.UpdateVariable,
536
533
  return_value_if_failed=False,
537
534
  if_error=ModelError, # 生きてるのに失敗した場合
538
- error_message=f'変数の更新に失敗しました:変数{name}, {value}',
535
+ error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE + f'{value} -> {name}',
539
536
  is_Gaudi_method=True,
540
537
  args=(name, value),
541
538
  )
@@ -559,7 +556,7 @@ class FemtetInterface(FEMInterface):
559
556
  self.Femtet.Gaudi.ReExecute,
560
557
  False,
561
558
  ModelError, # 生きてるのに失敗した場合
562
- error_message=f'モデル再構築に失敗しました.',
559
+ error_message=Msg.ERR_RE_EXECUTE_MODEL_FAILED,
563
560
  is_Gaudi_method=True,
564
561
  )
565
562
 
@@ -568,7 +565,7 @@ class FemtetInterface(FEMInterface):
568
565
  self.Femtet.Redraw,
569
566
  False, # 戻り値は常に None なのでこの変数に意味はなく None 以外なら何でもいい
570
567
  ModelError, # 生きてるのに失敗した場合
571
- error_message=f'モデル再構築に失敗しました.',
568
+ error_message=Msg.ERR_MODEL_REDRAW_FAILED,
572
569
  is_Gaudi_method=True,
573
570
  )
574
571
 
@@ -582,7 +579,7 @@ class FemtetInterface(FEMInterface):
582
579
  self.Femtet.Gaudi.Mesh,
583
580
  0,
584
581
  MeshError,
585
- 'メッシュ生成に失敗しました',
582
+ Msg.ERR_MODEL_MESH_FAILED,
586
583
  is_Gaudi_method=True,
587
584
  )
588
585
 
@@ -592,7 +589,7 @@ class FemtetInterface(FEMInterface):
592
589
  fun=solve_via_parametric_dll,
593
590
  return_value_if_failed=False,
594
591
  if_error=SolveError,
595
- error_message='パラメトリック解析を用いたソルブに失敗しました',
592
+ error_message=Msg.ERR_PARAMETRIC_SOLVE_FAILED,
596
593
  is_Gaudi_method=True,
597
594
  args=(self.Femtet,),
598
595
  )
@@ -602,7 +599,7 @@ class FemtetInterface(FEMInterface):
602
599
  self.Femtet.Solve,
603
600
  False,
604
601
  SolveError,
605
- 'ソルブに失敗しました',
602
+ Msg.ERR_SOLVE_FAILED,
606
603
  is_Gaudi_method=True,
607
604
  )
608
605
 
@@ -611,7 +608,7 @@ class FemtetInterface(FEMInterface):
611
608
  self.Femtet.OpenCurrentResult,
612
609
  False,
613
610
  SolveError, # 生きてるのに開けない場合
614
- error_message='解析結果のオープンに失敗しました',
611
+ error_message=Msg.ERR_OPEN_RESULT_FAILED,
615
612
  is_Gaudi_method=True,
616
613
  args=(self.open_result_with_gui,),
617
614
  )
@@ -620,9 +617,12 @@ class FemtetInterface(FEMInterface):
620
617
  """See :func:`FEMInterface.update`"""
621
618
  self.parameters = parameters.copy()
622
619
  self.update_model(parameters)
623
- # TODO: CAD 連携における座標を基にした境界条件の割当直しなどの処理をここに挟めるようにする
620
+ self.preprocess(self.Femtet)
624
621
  self.solve()
625
622
 
623
+ def preprocess(self, Femtet):
624
+ pass
625
+
626
626
  def quit(self, timeout=1, force=True):
627
627
  """Force to terminate connected Femtet."""
628
628
  major, minor, bugfix = 2024, 0, 1
@@ -631,13 +631,11 @@ class FemtetInterface(FEMInterface):
631
631
  try:
632
632
  self.Femtet.Exit(True)
633
633
  except AttributeError as e:
634
- message = 'Femtet.Exit()' + 'にアクセスできません。'
635
- f'Femtet {major}.{minor}.{bugfix} 以降で「マクロの有効化」が行われていない可能性があります。'
636
- 'スタートメニューから、インストールされいてる Femtet と同一バージョンの「マクロ機能を有効化する」コマンドを管理者権限で実行してください。'
637
634
  print('================')
638
- logger.error(message)
635
+ logger.error(Msg.ERR_CANNOT_ACCESS_API + 'Femtet.Exit()')
636
+ logger.error(Msg.CERTIFY_MACRO_VERSION)
639
637
  print('================')
640
- input('終了するには Enter を押してください。')
638
+ input(Msg.ENTER_TO_QUIT)
641
639
  raise e
642
640
 
643
641
  else:
@@ -651,7 +649,7 @@ class FemtetInterface(FEMInterface):
651
649
  start = time()
652
650
  while psutil.pid_exists(pid):
653
651
  if time() - start > 30: # 30 秒経っても存在するのは何かおかしい
654
- logger.error('Femtet の終了に失敗しました。')
652
+ logger.error(Msg.ERR_CLOSE_FEMTET_FAILED)
655
653
  break
656
654
  sleep(1)
657
655
  sleep(1)
@@ -722,7 +720,7 @@ class FemtetInterface(FEMInterface):
722
720
  return content
723
721
 
724
722
  else:
725
- raise Exception('pdt ファイルの保存でエラーが発生しました。')
723
+ raise Exception(Msg.ERR_FAILED_TO_SAVE_PDT)
726
724
 
727
725
  else:
728
726
  return None
@@ -742,10 +740,10 @@ class FemtetInterface(FEMInterface):
742
740
  self.Femtet.RedrawMode = True # 逐一の描画をオン
743
741
 
744
742
  if not succeed:
745
- raise Exception('jpg ファイルの保存でエラーが発生しました。')
743
+ raise Exception(Msg.ERR_FAILED_TO_SAVE_JPG)
746
744
 
747
745
  if not os.path.exists(jpg_path):
748
- raise Exception('保存した jpg ファイルが見つかりませんでした。')
746
+ raise Exception(Msg.ERR_JPG_NOT_FOUND)
749
747
 
750
748
  with open(jpg_path, 'rb') as f:
751
749
  content = f.read()
@@ -1,9 +1,14 @@
1
- from femtetutils import util
1
+ import logging
2
+
3
+ from femtetutils import util, logger
2
4
  from pyfemtet.dispatch_extensions import _get_pid
3
5
 
4
6
  import ctypes
5
7
 
6
8
 
9
+ logger.setLevel(logging.ERROR)
10
+
11
+
7
12
  def _get_dll():
8
13
  femtet_exe_path = util.get_femtet_exe_path()
9
14
  dll_path = femtet_exe_path.replace('Femtet.exe', 'ParametricIF.dll')
@@ -11,7 +16,7 @@ def _get_dll():
11
16
 
12
17
 
13
18
  def _get_dll_with_set_femtet(Femtet):
14
- dll = _get_dll(Femtet)
19
+ dll = _get_dll()
15
20
  pid = _get_pid(Femtet.hWnd)
16
21
  dll.SetCurrentFemtet.restype = ctypes.c_bool
17
22
  dll.SetCurrentFemtet(pid)
@@ -7,6 +7,7 @@ from dask.distributed import get_worker
7
7
 
8
8
  from pyfemtet.core import ModelError
9
9
  from pyfemtet.opt.interface import FemtetInterface, logger
10
+ from pyfemtet.message import Msg
10
11
 
11
12
 
12
13
  here, me = os.path.split(__file__)
@@ -40,8 +41,7 @@ class FemtetWithNXInterface(FemtetInterface):
40
41
  # check NX installation
41
42
  self.run_journal_path = os.path.join(os.environ.get('UGII_BASE_DIR'), 'NXBIN', 'run_journal.exe')
42
43
  if not os.path.isfile(self.run_journal_path):
43
- raise FileNotFoundError(
44
- r'"%UGII_BASE_DIR%\NXBIN\run_journal.exe" が見つかりませんでした。環境変数 UGII_BASE_DIR 又は NX のインストール状態を確認してください。')
44
+ raise FileNotFoundError(Msg.ERR_RUN_JOURNAL_NOT_FOUND)
45
45
 
46
46
  # 引数の処理
47
47
  # dask サブプロセスのときは prt_path を worker space から取るようにする
@@ -137,7 +137,7 @@ class FemtetWithNXInterface(FemtetInterface):
137
137
  self.Femtet.Gaudi.ReExecute,
138
138
  False,
139
139
  ModelError, # 生きてるのに失敗した場合
140
- error_message=f'モデル再構築に失敗しました.',
140
+ error_message=Msg.ERR_MODEL_RECONSTRUCTION_FAILED,
141
141
  is_Gaudi_method=True,
142
142
  )
143
143
 
@@ -146,7 +146,7 @@ class FemtetWithNXInterface(FemtetInterface):
146
146
  self.Femtet.Redraw,
147
147
  False, # 戻り値は常に None なのでこの変数に意味はなく None 以外なら何でもいい
148
148
  ModelError, # 生きてるのに失敗した場合
149
- error_message=f'モデル再構築に失敗しました.',
149
+ error_message=Msg.ERR_MODEL_UPDATE_FAILED,
150
150
  is_Gaudi_method=True,
151
151
  )
152
152
 
@@ -43,7 +43,7 @@ def main(
43
43
  try:
44
44
  exp = workPart.Expressions.FindObject(k)
45
45
  except NXOpen.NXException:
46
- print(f'├ 変数{k} .prt ファイルに含まれていません。無視されます。')
46
+ print(f'├ .prt does not contain parameter{k}. {k} is ignored.')
47
47
  continue
48
48
 
49
49
  workPart.Expressions.Edit(exp, str(v))
@@ -54,10 +54,10 @@ def main(
54
54
  # 更新に失敗
55
55
  except NXOpen.NXException as e:
56
56
  print(f'├ ERROR! {e}')
57
- print(f'└ 形状が破綻しました。操作を取り消します。')
57
+ print(f'└ Failed to update model.')
58
58
  return None
59
59
 
60
- print('│ model 更新に成功しました。')
60
+ print('│ Model updated successfully.')
61
61
 
62
62
  try:
63
63
  # parasolid のエクスポート
@@ -84,17 +84,17 @@ def main(
84
84
 
85
85
  except Exception as e:
86
86
  print(f'├ ERROR! {e}')
87
- print(f'└ parasolid 更新に失敗しました。')
87
+ print(f'└ Failed to update parasolid file.')
88
88
  return None
89
89
 
90
- print('└ parasolid 更新が正常に終了しました。')
90
+ print('└ Parasolid file updates successfully.')
91
91
  return None
92
92
 
93
93
 
94
94
 
95
95
  if __name__ == "__main__":
96
96
  print('---NX started---')
97
- print('current directory: ', os.getcwd())
97
+ # print('current directory: ', os.getcwd())
98
98
  print('arguments: ')
99
99
  for arg in sys.argv[1:]:
100
100
  print('│ ', arg)
@@ -10,6 +10,7 @@ from pythoncom import CoInitialize, CoUninitialize
10
10
 
11
11
  from pyfemtet.core import ModelError
12
12
  from pyfemtet.opt.interface import FemtetInterface, logger
13
+ from pyfemtet.message import Msg
13
14
 
14
15
 
15
16
  class FemtetWithSolidworksInterface(FemtetInterface):
@@ -100,7 +101,7 @@ class FemtetWithSolidworksInterface(FemtetInterface):
100
101
  if os.path.isfile(x_t_path):
101
102
  break
102
103
  if time() - start > timeout:
103
- raise ModelError('モデル再構築に失敗しました')
104
+ raise ModelError(Msg.ERR_MODEL_UPDATE_FAILED)
104
105
  sleep(1)
105
106
 
106
107
  # モデルの再インポート
@@ -108,7 +109,7 @@ class FemtetWithSolidworksInterface(FemtetInterface):
108
109
  self.Femtet.Gaudi.ReExecute,
109
110
  False,
110
111
  ModelError, # 生きてるのに失敗した場合
111
- error_message=f'モデル再構築に失敗しました.',
112
+ error_message=Msg.ERR_RE_EXECUTE_MODEL_FAILED,
112
113
  is_Gaudi_method=True,
113
114
  )
114
115
 
@@ -117,7 +118,7 @@ class FemtetWithSolidworksInterface(FemtetInterface):
117
118
  self.Femtet.Redraw,
118
119
  False, # 戻り値は常に None なのでこの変数に意味はなく None 以外なら何でもいい
119
120
  ModelError, # 生きてるのに失敗した場合
120
- error_message=f'モデル再構築に失敗しました.',
121
+ error_message=Msg.ERR_MODEL_REDRAW_FAILED,
121
122
  is_Gaudi_method=True,
122
123
  )
123
124
 
@@ -157,7 +158,7 @@ class FemtetWithSolidworksInterface(FemtetInterface):
157
158
  # 更新する(ここで失敗はしうる)
158
159
  result = self.swModel.EditRebuild3 # モデル再構築
159
160
  if not result:
160
- raise ModelError('モデル再構築に失敗しました')
161
+ raise ModelError(Msg.ERR_UPDATE_SOLIDWORKS_MODEL_FAILED)
161
162
 
162
163
  def _get_name_from_equation(self, equation: str):
163
164
  pattern = r'^\s*"(.+?)"\s*$'
@@ -1,8 +1,10 @@
1
1
  from pyfemtet.opt.opt._base import AbstractOptimizer, logger, OptimizationMethodChecker
2
2
  from pyfemtet.opt.opt._optuna import OptunaOptimizer
3
3
  from pyfemtet.opt.opt._scipy import ScipyOptimizer
4
+ from pyfemtet.opt.opt._scipy_scalar import ScipyScalarOptimizer
4
5
 
5
6
  __all__ = [
7
+ 'ScipyScalarOptimizer',
6
8
  'ScipyOptimizer',
7
9
  'OptunaOptimizer',
8
10
  'AbstractOptimizer',
pyfemtet/opt/opt/_base.py CHANGED
@@ -2,7 +2,7 @@
2
2
  from abc import ABC, abstractmethod
3
3
 
4
4
  # built-in
5
- import json
5
+ import traceback
6
6
  from time import sleep
7
7
 
8
8
  # 3rd-party
@@ -12,6 +12,7 @@ import pandas as pd
12
12
  # pyfemtet relative
13
13
  from pyfemtet.opt.interface import FemtetInterface
14
14
  from pyfemtet.opt._femopt_core import OptimizationStatus
15
+ from pyfemtet.message import Msg
15
16
 
16
17
  # logger
17
18
  import logging
@@ -27,8 +28,10 @@ class OptimizationMethodChecker:
27
28
  self.opt = opt
28
29
 
29
30
  def check_parallel(self, raise_error=True):
30
- function = 'parallel computing'
31
- message = f'{type(self.opt)} is not implement {function}'
31
+ function = 'parallel-processing'
32
+ method = str(type(self.opt))
33
+ message = (Msg.ERR_NOT_IMPLEMENTED
34
+ + f'method:{method}, function:{function}')
32
35
  if raise_error:
33
36
  raise NotImplementedError(message)
34
37
  else:
@@ -36,7 +39,9 @@ class OptimizationMethodChecker:
36
39
 
37
40
  def check_timeout(self, raise_error=True):
38
41
  function = 'timeout'
39
- message = f'{type(self.opt)} is not implement {function}'
42
+ method = str(type(self.opt))
43
+ message = (Msg.ERR_NOT_IMPLEMENTED
44
+ + f'method:{method}, function:{function}')
40
45
  if raise_error:
41
46
  raise NotImplementedError(message)
42
47
  else:
@@ -44,23 +49,29 @@ class OptimizationMethodChecker:
44
49
 
45
50
  def check_multi_objective(self, raise_error=True):
46
51
  function = 'multi-objective'
47
- message = f'{type(self.opt)} is not implement {function}'
52
+ method = str(type(self.opt))
53
+ message = (Msg.ERR_NOT_IMPLEMENTED
54
+ + f'method:{method}, function:{function}')
48
55
  if raise_error:
49
56
  raise NotImplementedError(message)
50
57
  else:
51
58
  logger.warning(message)
52
59
 
53
60
  def check_strict_constraint(self, raise_error=True):
54
- function = 'strict_constraint'
55
- message = f'{type(self.opt)} is not implement {function}'
61
+ function = 'strict-constraint'
62
+ method = str(type(self.opt))
63
+ message = (Msg.ERR_NOT_IMPLEMENTED
64
+ + f'method:{method}, function:{function}')
56
65
  if raise_error:
57
66
  raise NotImplementedError(message)
58
67
  else:
59
68
  logger.warning(message)
60
69
 
61
70
  def check_constraint(self, raise_error=True):
62
- function = 'strict_constraint'
63
- message = f'{type(self.opt)} is not implement {function}'
71
+ function = 'constraint'
72
+ method = str(type(self.opt))
73
+ message = (Msg.ERR_NOT_IMPLEMENTED
74
+ + f'method:{method}, function:{function}')
64
75
  if raise_error:
65
76
  raise NotImplementedError(message)
66
77
  else:
@@ -68,7 +79,9 @@ class OptimizationMethodChecker:
68
79
 
69
80
  def check_skip(self, raise_error=True):
70
81
  function = 'skip'
71
- message = f'{type(self.opt)} is not implement {function}'
82
+ method = str(type(self.opt))
83
+ message = (Msg.ERR_NOT_IMPLEMENTED
84
+ + f'method:{method}, function:{function}')
72
85
  if raise_error:
73
86
  raise NotImplementedError(message)
74
87
  else:
@@ -76,7 +89,9 @@ class OptimizationMethodChecker:
76
89
 
77
90
  def check_seed(self, raise_error=True):
78
91
  function = 'random seed setting'
79
- message = f'{type(self.opt)} is not implement {function}'
92
+ method = str(type(self.opt))
93
+ message = (Msg.ERR_NOT_IMPLEMENTED
94
+ + f'method:{method}, function:{function}')
80
95
  if raise_error:
81
96
  raise NotImplementedError(message)
82
97
  else:
@@ -84,7 +99,9 @@ class OptimizationMethodChecker:
84
99
 
85
100
  def check_incomplete_bounds(self, raise_error=True):
86
101
  function = 'optimize with no or incomplete bounds'
87
- message = f'{type(self.opt)} is not implement "{function}"'
102
+ method = str(type(self.opt))
103
+ message = (Msg.ERR_NOT_IMPLEMENTED
104
+ + f'method:{method}, function:{function}')
88
105
  if raise_error:
89
106
  raise NotImplementedError(message)
90
107
  else:
@@ -137,15 +154,18 @@ class AbstractOptimizer(ABC):
137
154
 
138
155
  # x の更新
139
156
  self.parameters['value'] = x
140
- logger.info(f'Start calculation with input: {x}')
157
+ logger.info('---------------------')
158
+ logger.info(f'input: {x}')
141
159
 
142
160
  # FEM の更新
143
161
  logger.debug('fem.update() start')
144
162
  try:
145
163
  self.fem.update(self.parameters)
146
164
  except Exception as e:
147
- logger.warning('An exception has occurred during FEM update.')
148
- raise e
165
+ logger.info(f'{type(e).__name__} : {e}')
166
+ logger.info(Msg.INFO_EXCEPTION_DURING_FEM_ANALYSIS)
167
+ logger.info(x)
168
+ raise e # may be just a ModelError, etc.
149
169
 
150
170
  # y, _y, c の更新
151
171
  logger.debug('calculate y start')
@@ -171,7 +191,7 @@ class AbstractOptimizer(ABC):
171
191
 
172
192
  logger.debug('history.record end')
173
193
 
174
- logger.info(f'End calculation with output: {_y}')
194
+ logger.info(f'output: {_y}')
175
195
 
176
196
  return np.array(y), np.array(_y), np.array(c)
177
197
 
@@ -191,7 +211,7 @@ class AbstractOptimizer(ABC):
191
211
  """Returns the parameters in the specified format.
192
212
 
193
213
  Args:
194
- format (str, optional): The desired format of the parameters. Can be 'df' (DataFrame), 'values', or 'dict'. Defaults to 'dict'.
214
+ format (str, optional): The desired format of the parameters. Can be 'df' (DataFrame), 'value' (alias of values), 'values' (np.ndarray), or 'dict'. Defaults to 'dict'.
195
215
 
196
216
  Returns:
197
217
  object: The parameters in the specified format.
@@ -210,7 +230,7 @@ class AbstractOptimizer(ABC):
210
230
  ret[row['name']] = row.value
211
231
  return ret
212
232
  else:
213
- raise ValueError('get_parameter() got invalid format: {format}')
233
+ raise ValueError(f'get_parameter() got invalid format: {format}')
214
234
 
215
235
  def _check_interruption(self):
216
236
  """"""
@@ -274,7 +294,8 @@ class AbstractOptimizer(ABC):
274
294
  logger.error("=================================")
275
295
  logger.error("An unexpected error has occurred!")
276
296
  logger.error("=================================")
277
- logger.error(f'{type(e)}: {e}')
297
+ logger.error(f'{type(e).__name__}: {e}')
298
+ traceback.print_exc()
278
299
  self._is_error_exit = True
279
300
  self.worker_status.set(OptimizationStatus.CRASHED)
280
301
  finally:
@@ -284,7 +305,7 @@ class AbstractOptimizer(ABC):
284
305
 
285
306
  @abstractmethod
286
307
  def run(self) -> None:
287
- """Start calcuration using optimization library."""
308
+ """Start calculation using optimization library."""
288
309
  pass
289
310
 
290
311
  @abstractmethod