pyfemtet 0.4.13__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 (104) 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 +16 -14
  12. pyfemtet/opt/femprj_sample/ParametricIF_test_result.reccsv +13 -13
  13. pyfemtet/opt/femprj_sample/cad_ex01_NX_test_result.reccsv +13 -13
  14. pyfemtet/opt/femprj_sample/cad_ex01_SW_test_result.reccsv +13 -13
  15. pyfemtet/opt/femprj_sample/gal_ex58_parametric_test_result.reccsv +13 -13
  16. pyfemtet/opt/femprj_sample/gau_ex08_parametric_test_result.reccsv +23 -23
  17. pyfemtet/opt/femprj_sample/her_ex40_parametric_test_result.reccsv +18 -18
  18. pyfemtet/opt/femprj_sample/paswat_ex1_parametric_test_result.reccsv +18 -18
  19. pyfemtet/opt/femprj_sample/tutorial.femprj +0 -0
  20. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  21. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  22. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
  23. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  24. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
  25. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  26. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  27. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  28. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  29. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  30. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  31. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  32. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  33. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  34. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  35. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  36. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
  37. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  38. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
  39. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  40. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
  41. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  42. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
  43. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  44. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
  45. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  46. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
  47. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  48. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
  49. pyfemtet/opt/femprj_sample/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  50. pyfemtet/opt/{visualization/result_viewer/tutorial → femprj_sample}/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
  51. pyfemtet/opt/femprj_sample/wat_ex14_parametric_test_result.reccsv +18 -18
  52. pyfemtet/opt/interface/_femtet.py +42 -46
  53. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +4 -4
  54. pyfemtet/opt/interface/_femtet_with_nx/update_model.py +6 -6
  55. pyfemtet/opt/interface/_femtet_with_sldworks.py +5 -4
  56. pyfemtet/opt/opt/__init__.py +2 -0
  57. pyfemtet/opt/opt/_base.py +41 -20
  58. pyfemtet/opt/opt/_optuna.py +8 -13
  59. pyfemtet/opt/opt/_scipy.py +4 -8
  60. pyfemtet/opt/opt/_scipy_scalar.py +1 -5
  61. pyfemtet/opt/prediction/__init__.py +0 -0
  62. pyfemtet/opt/prediction/base.py +52 -0
  63. pyfemtet/opt/prediction/single_task_gp.py +82 -0
  64. pyfemtet/opt/visualization/complex_components/control_femtet.py +9 -11
  65. pyfemtet/opt/visualization/complex_components/main_figure_creator.py +24 -11
  66. pyfemtet/opt/visualization/complex_components/main_graph.py +3 -4
  67. pyfemtet/opt/visualization/complex_components/pm_graph.py +715 -0
  68. pyfemtet/opt/visualization/complex_components/pm_graph_creator.py +168 -0
  69. pyfemtet/opt/visualization/process_monitor/application.py +16 -12
  70. pyfemtet/opt/visualization/process_monitor/pages.py +22 -7
  71. pyfemtet/opt/visualization/result_viewer/application.py +8 -3
  72. pyfemtet/opt/visualization/result_viewer/pages.py +59 -47
  73. {pyfemtet-0.4.13.dist-info → pyfemtet-0.4.14.dist-info}/METADATA +2 -1
  74. {pyfemtet-0.4.13.dist-info → pyfemtet-0.4.14.dist-info}/RECORD +77 -70
  75. pyfemtet/opt/visualization/result_viewer/tutorial/tutorial.csv +0 -18
  76. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.jpg +0 -0
  77. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.log +0 -81
  78. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.pdt +0 -0
  79. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow.csv +0 -28
  80. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow_el.csv +0 -22
  81. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
  82. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
  83. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
  84. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
  85. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
  86. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
  87. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
  88. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
  89. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
  90. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
  91. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
  92. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
  93. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
  94. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
  95. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
  96. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
  97. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
  98. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
  99. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
  100. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
  101. pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.femprj +0 -0
  102. {pyfemtet-0.4.13.dist-info → pyfemtet-0.4.14.dist-info}/LICENSE +0 -0
  103. {pyfemtet-0.4.13.dist-info → pyfemtet-0.4.14.dist-info}/WHEEL +0 -0
  104. {pyfemtet-0.4.13.dist-info → pyfemtet-0.4.14.dist-info}/entry_points.txt +0 -0
@@ -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,11 @@ class FemtetInterface(FEMInterface):
291
290
  # API を実行
292
291
  try:
293
292
  # 解析結果を開いた状態で Gaudi.Activate して ReExecute する場合、ReExecute の前後にアクティブ化イベントが必要
293
+ # さらに、プロジェクトツリーが開いていないとアクティブ化イベントも意味がないらしい。
294
294
  if fun.__name__ == 'ReExecute':
295
295
  if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
296
- post_activate_message(self.Femtet.hWnd) # can raise pywintypes.error
297
- returns = fun(*args, **kwargs)
296
+ post_activate_message(self.Femtet.hWnd)
297
+ returns = fun(*args, **kwargs) # can raise pywintypes.error
298
298
  if self.open_result_with_gui or self.parametric_output_indexes_use_as_objective:
299
299
  post_activate_message(self.Femtet.hWnd)
300
300
  else:
@@ -333,20 +333,19 @@ class FemtetInterface(FEMInterface):
333
333
  # 再起動試行回数の上限に達していたら諦める
334
334
  logger.debug(' ' * print_indent + f'現在の Femtet 再起動回数: {recourse_depth}')
335
335
  if recourse_depth >= self.max_api_retry:
336
- raise Exception('Femtet のプロセスが異常終了し、正常に再起動できませんでした.')
336
+ raise Exception(Msg.ERR_FEMTET_CRASHED_AND_RESTART_FAILED)
337
337
 
338
338
  # 再起動
339
- logger.warn('Femtet プロセスの異常終了が検知されました. 回復を試みます.')
339
+ logger.warn(' ' * print_indent + Msg.WARN_FEMTET_CRASHED_AND_TRY_RESTART)
340
340
  CoInitialize()
341
341
  self.connect_femtet(connect_method='new')
342
342
  self.open(self.femprj_path, self.model_name)
343
343
 
344
344
  # 状態を復元するために一度変数を渡して解析を行う(fun.__name__がSolveなら2度手間だが)
345
- logger.info(' ' * print_indent + f'Femtet が再起動されました。解析を行い、状態回復を試みます。')
345
+ logger.info(' ' * print_indent + Msg.INFO_FEMTET_CRASHED_AND_RESTARTED)
346
346
  self.update(self.parameters)
347
347
 
348
348
  # 与えられた API の再帰的再試行
349
- logger.info(' ' * print_indent + f'Femtet が回復されました。コマンド {fun.__name__} を再試行します。')
350
349
  return self._call_femtet_api(
351
350
  fun,
352
351
  return_value_if_failed,
@@ -425,16 +424,15 @@ class FemtetInterface(FEMInterface):
425
424
  (self.connect_method == 'new')
426
425
  and (not self.allow_without_project)
427
426
  ):
428
- raise RuntimeError(
429
- 'femprj_path を指定せず Femtet の connect_method に "new" を指定する場合、"allow_without_project" 引数を True に設定してください。')
427
+ raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
428
+
430
429
  # さらに auto の場合は Femtet が存在しなければ new と同じ挙動になるので同様の処理
431
430
  if (
432
431
  (self.connect_method == 'auto')
433
432
  and (len(_get_pids(process_name='Femtet.exe')) == 0)
434
433
  and (not self.allow_without_project)
435
434
  ):
436
- raise RuntimeError(
437
- 'femprj_path を指定せず Femtet の connect_method を指定しない(又は "auto" に指定する)場合、Femtet を起動して処理したい .femprj ファイルを開いた状態にしてください。')
435
+ raise RuntimeError(Msg.ERR_NEW_FEMTET_BUT_NO_FEMPRJ)
438
436
  self.connect_femtet(self.connect_method)
439
437
 
440
438
  # 最終的に接続した Femtet の femprj_path と model を インスタンスに戻す
@@ -454,25 +452,22 @@ class FemtetInterface(FEMInterface):
454
452
  try:
455
453
  variable_names = self.Femtet.GetVariableNames_py()
456
454
  except AttributeError as e:
457
- message = 'GetVariableNames_py' + 'にアクセスできません。'
458
- f'Femtet {major}.{minor}.{bugfix} 以降で「マクロの有効化」が行われていない可能性があります。'
459
- 'スタートメニューから、インストールされいてる Femtet と同一バージョンの「マクロ機能を有効化する」コマンドを管理者権限で実行してください。'
460
455
  print('================')
461
- logger.error(message)
456
+ logger.error(Msg.ERR_CANNOT_ACCESS_API + 'GetVariableNames_py')
457
+ logger.error(Msg.CERTIFY_MACRO_VERSION)
462
458
  print('================')
463
- input('終了するには Enter を押してください。')
459
+ input(Msg.ENTER_TO_QUIT)
464
460
  raise e
465
461
 
466
462
  if variable_names is not None:
467
463
  if param_name in variable_names:
468
464
  return self.Femtet.GetVariableValue(param_name)
469
- message = f'Femtet 解析モデルに変数 {param_name} がありません.'
470
- message += f'現在のモデルに設定されている変数は {variable_names} です.'
471
- message += '大文字・小文字の区別に注意してください.'
465
+ message = Msg.ERR_NO_SUCH_PARAMETER_IN_FEMTET
472
466
  print('================')
473
467
  logger.error(message)
468
+ logger.error(f'`{param_name}` not in {variable_names}')
474
469
  print('================')
475
- input('終了するには Enter を押してください。')
470
+ input(Msg.ENTER_TO_QUIT)
476
471
  raise RuntimeError(message)
477
472
  else:
478
473
  return None
@@ -487,7 +482,7 @@ class FemtetInterface(FEMInterface):
487
482
  self.Femtet.Gaudi.Activate,
488
483
  True, # 戻り値を持たないのでここは無意味で None 以外なら何でもいい
489
484
  Exception, # 生きてるのに開けない場合
490
- error_message='解析モデルが開かれていません',
485
+ error_message=Msg.NO_ANALYSIS_MODEL_IS_OPEN,
491
486
  )
492
487
 
493
488
  major, minor, bugfix = 2023, 1, 1
@@ -497,14 +492,14 @@ class FemtetInterface(FEMInterface):
497
492
  fun=self.Femtet.GetVariableNames_py,
498
493
  return_value_if_failed=False, # 意味がない
499
494
  if_error=ModelError, # 生きてるのに失敗した場合
500
- error_message=f'GetVariableNames_py に失敗しました。',
495
+ error_message=f'GetVariableNames_py failed.',
501
496
  is_Gaudi_method=True,
502
497
  )
503
498
 
504
499
  # 変数を含まないプロジェクトである場合
505
500
  if existing_variable_names is None:
506
501
  if with_warning:
507
- return ['解析モデルに変数が含まれていません。']
502
+ return [Msg.FEMTET_ANALYSIS_MODEL_WITH_NO_PARAMETER]
508
503
  else:
509
504
  return None
510
505
 
@@ -518,12 +513,12 @@ class FemtetInterface(FEMInterface):
518
513
  fun=self.Femtet.UpdateVariable,
519
514
  return_value_if_failed=False,
520
515
  if_error=ModelError, # 生きてるのに失敗した場合
521
- error_message=f'変数の更新に失敗しました:変数{name}, {value}',
516
+ error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE + f'{value} -> {name}',
522
517
  is_Gaudi_method=True,
523
518
  args=(name, value),
524
519
  )
525
520
  else:
526
- msg = f'変数 {name} 解析モデル {self.model_name} に含まれていません。無視されます。'
521
+ msg = f'{name} not in {self.model_name}: ' + Msg.WARN_IGNORE_PARAMETER_NOT_CONTAINED
527
522
  warnings.append(msg)
528
523
  logger.warn(msg)
529
524
 
@@ -537,7 +532,7 @@ class FemtetInterface(FEMInterface):
537
532
  fun=self.Femtet.UpdateVariable,
538
533
  return_value_if_failed=False,
539
534
  if_error=ModelError, # 生きてるのに失敗した場合
540
- error_message=f'変数の更新に失敗しました:変数{name}, {value}',
535
+ error_message=Msg.ERR_FAILED_TO_UPDATE_VARIABLE + f'{value} -> {name}',
541
536
  is_Gaudi_method=True,
542
537
  args=(name, value),
543
538
  )
@@ -561,7 +556,7 @@ class FemtetInterface(FEMInterface):
561
556
  self.Femtet.Gaudi.ReExecute,
562
557
  False,
563
558
  ModelError, # 生きてるのに失敗した場合
564
- error_message=f'モデル再構築に失敗しました.',
559
+ error_message=Msg.ERR_RE_EXECUTE_MODEL_FAILED,
565
560
  is_Gaudi_method=True,
566
561
  )
567
562
 
@@ -570,7 +565,7 @@ class FemtetInterface(FEMInterface):
570
565
  self.Femtet.Redraw,
571
566
  False, # 戻り値は常に None なのでこの変数に意味はなく None 以外なら何でもいい
572
567
  ModelError, # 生きてるのに失敗した場合
573
- error_message=f'モデル再構築に失敗しました.',
568
+ error_message=Msg.ERR_MODEL_REDRAW_FAILED,
574
569
  is_Gaudi_method=True,
575
570
  )
576
571
 
@@ -584,7 +579,7 @@ class FemtetInterface(FEMInterface):
584
579
  self.Femtet.Gaudi.Mesh,
585
580
  0,
586
581
  MeshError,
587
- 'メッシュ生成に失敗しました',
582
+ Msg.ERR_MODEL_MESH_FAILED,
588
583
  is_Gaudi_method=True,
589
584
  )
590
585
 
@@ -594,7 +589,7 @@ class FemtetInterface(FEMInterface):
594
589
  fun=solve_via_parametric_dll,
595
590
  return_value_if_failed=False,
596
591
  if_error=SolveError,
597
- error_message='パラメトリック解析を用いたソルブに失敗しました',
592
+ error_message=Msg.ERR_PARAMETRIC_SOLVE_FAILED,
598
593
  is_Gaudi_method=True,
599
594
  args=(self.Femtet,),
600
595
  )
@@ -604,7 +599,7 @@ class FemtetInterface(FEMInterface):
604
599
  self.Femtet.Solve,
605
600
  False,
606
601
  SolveError,
607
- 'ソルブに失敗しました',
602
+ Msg.ERR_SOLVE_FAILED,
608
603
  is_Gaudi_method=True,
609
604
  )
610
605
 
@@ -613,7 +608,7 @@ class FemtetInterface(FEMInterface):
613
608
  self.Femtet.OpenCurrentResult,
614
609
  False,
615
610
  SolveError, # 生きてるのに開けない場合
616
- error_message='解析結果のオープンに失敗しました',
611
+ error_message=Msg.ERR_OPEN_RESULT_FAILED,
617
612
  is_Gaudi_method=True,
618
613
  args=(self.open_result_with_gui,),
619
614
  )
@@ -622,9 +617,12 @@ class FemtetInterface(FEMInterface):
622
617
  """See :func:`FEMInterface.update`"""
623
618
  self.parameters = parameters.copy()
624
619
  self.update_model(parameters)
625
- # TODO: CAD 連携における座標を基にした境界条件の割当直しなどの処理をここに挟めるようにする
620
+ self.preprocess(self.Femtet)
626
621
  self.solve()
627
622
 
623
+ def preprocess(self, Femtet):
624
+ pass
625
+
628
626
  def quit(self, timeout=1, force=True):
629
627
  """Force to terminate connected Femtet."""
630
628
  major, minor, bugfix = 2024, 0, 1
@@ -633,13 +631,11 @@ class FemtetInterface(FEMInterface):
633
631
  try:
634
632
  self.Femtet.Exit(True)
635
633
  except AttributeError as e:
636
- message = 'Femtet.Exit()' + 'にアクセスできません。'
637
- f'Femtet {major}.{minor}.{bugfix} 以降で「マクロの有効化」が行われていない可能性があります。'
638
- 'スタートメニューから、インストールされいてる Femtet と同一バージョンの「マクロ機能を有効化する」コマンドを管理者権限で実行してください。'
639
634
  print('================')
640
- logger.error(message)
635
+ logger.error(Msg.ERR_CANNOT_ACCESS_API + 'Femtet.Exit()')
636
+ logger.error(Msg.CERTIFY_MACRO_VERSION)
641
637
  print('================')
642
- input('終了するには Enter を押してください。')
638
+ input(Msg.ENTER_TO_QUIT)
643
639
  raise e
644
640
 
645
641
  else:
@@ -653,7 +649,7 @@ class FemtetInterface(FEMInterface):
653
649
  start = time()
654
650
  while psutil.pid_exists(pid):
655
651
  if time() - start > 30: # 30 秒経っても存在するのは何かおかしい
656
- logger.error('Femtet の終了に失敗しました。')
652
+ logger.error(Msg.ERR_CLOSE_FEMTET_FAILED)
657
653
  break
658
654
  sleep(1)
659
655
  sleep(1)
@@ -724,7 +720,7 @@ class FemtetInterface(FEMInterface):
724
720
  return content
725
721
 
726
722
  else:
727
- raise Exception('pdt ファイルの保存でエラーが発生しました。')
723
+ raise Exception(Msg.ERR_FAILED_TO_SAVE_PDT)
728
724
 
729
725
  else:
730
726
  return None
@@ -744,10 +740,10 @@ class FemtetInterface(FEMInterface):
744
740
  self.Femtet.RedrawMode = True # 逐一の描画をオン
745
741
 
746
742
  if not succeed:
747
- raise Exception('jpg ファイルの保存でエラーが発生しました。')
743
+ raise Exception(Msg.ERR_FAILED_TO_SAVE_JPG)
748
744
 
749
745
  if not os.path.exists(jpg_path):
750
- raise Exception('保存した jpg ファイルが見つかりませんでした。')
746
+ raise Exception(Msg.ERR_JPG_NOT_FOUND)
751
747
 
752
748
  with open(jpg_path, 'rb') as f:
753
749
  content = f.read()
@@ -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
@@ -14,6 +14,7 @@ from optuna.study import MaxTrialsCallback
14
14
  from pyfemtet.opt._femopt_core import OptimizationStatus, generate_lhs
15
15
  from pyfemtet.opt.opt import AbstractOptimizer, logger, OptimizationMethodChecker
16
16
  from pyfemtet.core import MeshError, ModelError, SolveError
17
+ from pyfemtet.message import Msg
17
18
 
18
19
  # filter warnings
19
20
  import warnings
@@ -86,18 +87,15 @@ class OptunaOptimizer(AbstractOptimizer):
86
87
  if cns.ub is not None:
87
88
  feasible = feasible and (cns.ub >= cns_value)
88
89
  if not feasible:
89
- logger.info(f'以下の変数で拘束 {cns.name} が満たされませんでした。')
90
- print(self.get_parameter('dict'))
90
+ logger.info(Msg.INFO_INFEASIBLE)
91
+ logger.info(f'Constraint: {cns.name}')
92
+ logger.info(self.get_parameter('dict'))
91
93
  raise optuna.TrialPruned() # set TrialState PRUNED because FAIL causes similar candidate loop.
92
94
 
93
95
  # 計算
94
96
  try:
95
- _, _y, c = self.f(x)
97
+ _, _y, c = self.f(x) # f の中で info は出している
96
98
  except (ModelError, MeshError, SolveError) as e:
97
- logger.info(e)
98
- logger.info('以下の変数で FEM 解析に失敗しました。')
99
- print(self.get_parameter('dict'))
100
-
101
99
  # 中断の確認 (解析中に interrupt されている場合対策)
102
100
  if self.entire_status.get() == OptimizationStatus.INTERRUPTING:
103
101
  self.worker_status.set(OptimizationStatus.INTERRUPTING)
@@ -171,9 +169,9 @@ class OptunaOptimizer(AbstractOptimizer):
171
169
  # add_initial_parameter で追加された初期値
172
170
  for prm, prm_set_name in self.additional_initial_parameter:
173
171
  if type(prm) is dict:
174
- assert prm.keys() == params.keys(), '設定されたパラメータ名と add_init_parameter で追加されたパラメータ名が一致しません。'
172
+ assert prm.keys() == params.keys(), Msg.ERR_INCONSISTENT_PARAMETER
175
173
  else:
176
- assert len(prm) == len(params.keys()), '設定されたパラメータ数と add_init_parameter で追加されたパラメータ数が一致しません。'
174
+ assert len(prm) == len(params.keys()), Msg.ERR_INCONSISTENT_PARAMETER
177
175
  prm = dict(zip(params.keys(), prm))
178
176
 
179
177
  self.study.enqueue_trial(
@@ -202,10 +200,7 @@ class OptunaOptimizer(AbstractOptimizer):
202
200
  # if is_restart, load study
203
201
  else:
204
202
  if not os.path.exists(storage_path):
205
- msg = f'{storage_path} が見つかりません。'
206
- msg += '.db ファイルは .csv ファイルと同じフォルダに生成されます。'
207
- msg += 'クラスター解析の場合は、スケジューラを起動したフォルダに生成されます。'
208
- raise FileNotFoundError(msg)
203
+ raise FileNotFoundError(storage_path)
209
204
  self.storage = optuna.integration.dask.DaskStorage(
210
205
  f'sqlite:///{storage_path}',
211
206
  )