pyfemtet 0.4.6__py3-none-any.whl → 0.4.8__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 (28) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/_test_util.py +115 -0
  3. pyfemtet/opt/_femopt.py +7 -1
  4. pyfemtet/opt/_femopt_core.py +20 -3
  5. pyfemtet/opt/femprj_sample/cad_ex01_NX.py +4 -0
  6. pyfemtet/opt/femprj_sample/cad_ex01_NX_test_result.reccsv +13 -0
  7. pyfemtet/opt/femprj_sample/cad_ex01_SW_test_result.reccsv +13 -0
  8. pyfemtet/opt/femprj_sample/gal_ex58_parametric.femprj +0 -0
  9. pyfemtet/opt/femprj_sample/gal_ex58_parametric_test_result.reccsv +13 -0
  10. pyfemtet/opt/femprj_sample/gau_ex08_parametric_test_result.reccsv +23 -0
  11. pyfemtet/opt/femprj_sample/her_ex40_parametric_test_result.reccsv +18 -0
  12. pyfemtet/opt/femprj_sample/paswat_ex1_parametric_test_result.reccsv +18 -0
  13. pyfemtet/opt/femprj_sample/wat_ex14_parametric_test_result.reccsv +18 -0
  14. pyfemtet/opt/femprj_sample_jp/cad_ex01_NX_jp.py +4 -0
  15. pyfemtet/opt/femprj_sample_jp/gal_ex58_parametric_jp.femprj +0 -0
  16. pyfemtet/opt/interface/_base.py +6 -0
  17. pyfemtet/opt/interface/_femtet.py +203 -27
  18. pyfemtet/opt/interface/_femtet_parametric.py +3 -3
  19. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +35 -2
  20. pyfemtet/opt/interface/_femtet_with_nx/update_model.py +36 -28
  21. pyfemtet/opt/opt/_base.py +2 -0
  22. pyfemtet/opt/visualization/_graphs.py +16 -13
  23. pyfemtet/opt/visualization/_monitor.py +88 -10
  24. {pyfemtet-0.4.6.dist-info → pyfemtet-0.4.8.dist-info}/METADATA +2 -1
  25. {pyfemtet-0.4.6.dist-info → pyfemtet-0.4.8.dist-info}/RECORD +28 -20
  26. {pyfemtet-0.4.6.dist-info → pyfemtet-0.4.8.dist-info}/LICENSE +0 -0
  27. {pyfemtet-0.4.6.dist-info → pyfemtet-0.4.8.dist-info}/WHEEL +0 -0
  28. {pyfemtet-0.4.6.dist-info → pyfemtet-0.4.8.dist-info}/entry_points.txt +0 -0
@@ -41,7 +41,7 @@ class FemtetInterface(FEMInterface):
41
41
  strictly_pid_specify (bool, optional): If True and connect_method=='new', search launched Femtet process strictly based on its process id.
42
42
  allow_without_project (bool, optional): Allow to launch Femtet with no project file. Default to False.
43
43
  open_result_with_gui (bool, optional): Open analysis result with Femtet GUI. Default to True.
44
- parametric_output_indexes_use_as_objective (list of int, optional): Parametric output indexes which will be used as objective functions. Parametric output should be set on Femtet parametric analysis dialog. Note that output 'No.' in dialog is starts with 1, but this 'index' is starts with 0. Default to None.
44
+ parametric_output_indexes_use_as_objective (dict, optional): Parametric output indexes and their directions which will be used as objective functions. Parametric output should be set on Femtet parametric analysis dialog. Note that output 'No.' in dialog is starts with 1, but this 'index' is starts with 0. The key is the 'index', the value is direction ('maximize', 'minimize' or float). Default to None.
45
45
 
46
46
  Warning:
47
47
  Even if you specify ``strictly_pid_specify=True`` on the constructor,
@@ -59,9 +59,10 @@ class FemtetInterface(FEMInterface):
59
59
  self,
60
60
  femprj_path=None,
61
61
  model_name=None,
62
- connect_method='auto',
63
- strictly_pid_specify=True,
64
- allow_without_project=False,
62
+ connect_method='auto', # dask worker では __init__ の中で 'new' にするので super() の引数にしない。(しても意味がない)
63
+ save_pdt='all', # 'all' or None
64
+ strictly_pid_specify=True, # dask worker では True にしたいので super() の引数にしない。
65
+ allow_without_project=False, # main でのみ True を許容したいので super() の引数にしない。
65
66
  open_result_with_gui=True,
66
67
  parametric_output_indexes_use_as_objective=None,
67
68
  **kwargs # 継承されたクラスからの引数
@@ -80,6 +81,7 @@ class FemtetInterface(FEMInterface):
80
81
  self.allow_without_project = allow_without_project
81
82
  self.original_femprj_path = self.femprj_path
82
83
  self.open_result_with_gui = open_result_with_gui
84
+ self.save_pdt = save_pdt
83
85
 
84
86
  # その他のメンバーの宣言や初期化
85
87
  self.Femtet = None
@@ -106,6 +108,15 @@ class FemtetInterface(FEMInterface):
106
108
  # 開かれたモデルに応じて femprj_path と model を更新する
107
109
  self._connect_and_open_femtet()
108
110
 
111
+ # original_fem_prj が None なら必ず
112
+ # dask worker でないプロセスがオリジナルファイルを開いている
113
+ if self.original_femprj_path is None:
114
+ # dask worker でなければ original のはず
115
+ try:
116
+ worker = get_worker()
117
+ except ValueError:
118
+ self.original_femprj_path = self.femprj_path
119
+
109
120
  # 接続した Femtet の種類に応じて del 時に quit するかどうか決める
110
121
  self.quit_when_destruct = self.connected_method == 'new'
111
122
 
@@ -117,26 +128,13 @@ class FemtetInterface(FEMInterface):
117
128
  model_name=self.model_name,
118
129
  open_result_with_gui=self.open_result_with_gui,
119
130
  parametric_output_indexes_use_as_objective=self.parametric_output_indexes_use_as_objective,
131
+ save_pdt=self.save_pdt,
120
132
  **kwargs
121
133
  )
122
134
 
123
135
  def __del__(self):
124
136
  if self.quit_when_destruct:
125
- try:
126
- # 強制終了 TODO: 自動保存を回避する
127
- hwnd = self.Femtet.hWnd
128
- pid = _get_pid(hwnd)
129
- util.close_femtet(hwnd, 1, True)
130
- start = time()
131
- while psutil.pid_exists(pid):
132
- if time() - start > 30: # 30 秒経っても存在するのは何かおかしい
133
- os.kill(pid, signal.SIGKILL)
134
- break
135
- sleep(1)
136
- sleep(1)
137
-
138
- except (AttributeError, OSError): # already dead
139
- pass
137
+ self.quit()
140
138
  # CoUninitialize() # Win32 exception occurred releasing IUnknown at 0x0000022427692748
141
139
 
142
140
  def _connect_new_femtet(self):
@@ -199,8 +197,12 @@ class FemtetInterface(FEMInterface):
199
197
  cmd = f'{sys.executable} -m win32com.client.makepy FemtetMacro'
200
198
  os.system(cmd)
201
199
  message = 'Femtet python マクロ定数の設定が完了してないことを検出しました.'
202
- message += '次のコマンドにより、設定は自動で行われました(python -m win32com.client.makepy FemtetMacro).'
203
- message += 'インタープリタを再起動してください.'
200
+ message += '設定は自動で行われました(python -m win32com.client.makepy FemtetMacro).'
201
+ message += 'プログラムを再起動してください.'
202
+ print('================')
203
+ print(message)
204
+ print('================')
205
+ input('終了するには Enter を押してください。')
204
206
  raise RuntimeError(message)
205
207
 
206
208
  if self.Femtet is None:
@@ -270,7 +272,7 @@ class FemtetInterface(FEMInterface):
270
272
  self.Femtet.Gaudi.Activate,
271
273
  False, # None 以外なら何でもいい
272
274
  Exception,
273
- '解析モデルのオープンに失敗しました',
275
+ 'Gaudi のオープンに失敗しました',
274
276
  print_indent=print_indent + 1
275
277
  )
276
278
  except com_error:
@@ -430,14 +432,30 @@ class FemtetInterface(FEMInterface):
430
432
  Otherwise, no check is performed.
431
433
 
432
434
  """
433
- if self._version() >= _version(2023, 1, 1):
434
- variable_names = self.Femtet.GetVariableNames_py()
435
+ major, minor, bugfix = 2023, 1, 1
436
+ if self._version() >= _version(major, minor, bugfix):
437
+ try:
438
+ variable_names = self.Femtet.GetVariableNames_py()
439
+ except AttributeError as e:
440
+ message = 'GetVariableNames_py' + 'にアクセスできません。'
441
+ f'Femtet {major}.{minor}.{bugfix} 以降で「マクロの有効化」が行われていない可能性があります。'
442
+ 'スタートメニューから、インストールされいてる Femtet と同一バージョンの「マクロ機能を有効化する」コマンドを管理者権限で実行してください。'
443
+ print('================')
444
+ logger.error(message)
445
+ print('================')
446
+ input('終了するには Enter を押してください。')
447
+ raise e
448
+
435
449
  if variable_names is not None:
436
450
  if param_name in variable_names:
437
451
  return self.Femtet.GetVariableValue(param_name)
438
452
  message = f'Femtet 解析モデルに変数 {param_name} がありません.'
439
453
  message += f'現在のモデルに設定されている変数は {variable_names} です.'
440
454
  message += '大文字・小文字の区別に注意してください.'
455
+ print('================')
456
+ logger.error(message)
457
+ print('================')
458
+ input('終了するには Enter を押してください。')
441
459
  raise RuntimeError(message)
442
460
  else:
443
461
  return None
@@ -455,8 +473,9 @@ class FemtetInterface(FEMInterface):
455
473
  error_message='解析モデルが開かれていません',
456
474
  )
457
475
 
458
- if self._version() >= _version(2023, 1, 1):
459
- # Femtet の設計変数の更新
476
+ major, minor, bugfix = 2023, 1, 1
477
+ if self._version() >= _version(major, minor, bugfix):
478
+ # Femtet の設計変数の更新(2023.1.1 以降でマクロだけ古い場合はcheck_param_valueで引っかかっているはずなのでここはAttributeError をチェックしない)
460
479
  existing_variable_names = self._call_femtet_api(
461
480
  fun=self.Femtet.GetVariableNames_py,
462
481
  return_value_if_failed=False, # 意味がない
@@ -591,7 +610,39 @@ class FemtetInterface(FEMInterface):
591
610
 
592
611
  def quit(self, timeout=1, force=True):
593
612
  """Force to terminate connected Femtet."""
594
- util.close_femtet(self.Femtet.hWnd, timeout, force)
613
+ major, minor, bugfix = 2024, 0, 1
614
+ if self._version() >= _version(major, minor, bugfix):
615
+ # gracefully termination method without save project available from 2024.0.1
616
+ try:
617
+ self.Femtet.Exit(True)
618
+ except AttributeError as e:
619
+ message = 'Femtet.Exit()' + 'にアクセスできません。'
620
+ f'Femtet {major}.{minor}.{bugfix} 以降で「マクロの有効化」が行われていない可能性があります。'
621
+ 'スタートメニューから、インストールされいてる Femtet と同一バージョンの「マクロ機能を有効化する」コマンドを管理者権限で実行してください。'
622
+ print('================')
623
+ logger.error(message)
624
+ print('================')
625
+ input('終了するには Enter を押してください。')
626
+ raise e
627
+
628
+ else:
629
+ hwnd = self.Femtet.hWnd
630
+
631
+ # terminate
632
+ util.close_femtet(hwnd, timeout, force)
633
+
634
+ try:
635
+ pid = _get_pid(hwnd)
636
+ start = time()
637
+ while psutil.pid_exists(pid):
638
+ if time() - start > 30: # 30 秒経っても存在するのは何かおかしい
639
+ logger.error('Femtet の終了に失敗しました。')
640
+ break
641
+ sleep(1)
642
+ sleep(1)
643
+
644
+ except (AttributeError, OSError): # already dead
645
+ pass
595
646
 
596
647
  def _setup_before_parallel(self, client):
597
648
  client.upload_file(
@@ -601,3 +652,128 @@ class FemtetInterface(FEMInterface):
601
652
 
602
653
  def _version(self):
603
654
  return _version(Femtet=self.Femtet)
655
+
656
+ def create_postprocess_args(self):
657
+ file_content = self.create_result_file_content()
658
+ jpg_content = self.create_jpg_content()
659
+
660
+ out = dict(
661
+ original_femprj_path=self.original_femprj_path,
662
+ model_name=self.model_name,
663
+ pdt_file_content=file_content,
664
+ jpg_file_content=jpg_content,
665
+ )
666
+ return out
667
+
668
+ @staticmethod
669
+ def postprocess_func(
670
+ trial: int,
671
+ original_femprj_path: str,
672
+ model_name: str,
673
+ pdt_file_content=None,
674
+ jpg_file_content=None,
675
+ dask_scheduler=None
676
+ ):
677
+ result_dir = original_femprj_path.replace('.femprj', '.Results')
678
+ if pdt_file_content is not None:
679
+ pdt_path = os.path.join(result_dir, model_name + f'_trial{trial}.pdt')
680
+ with open(pdt_path, 'wb') as f:
681
+ f.write(pdt_file_content)
682
+
683
+ if jpg_file_content is not None:
684
+ jpg_path = os.path.join(result_dir, model_name + f'_trial{trial}.jpg')
685
+ with open(jpg_path, 'wb') as f:
686
+ f.write(jpg_file_content)
687
+
688
+ def create_result_file_content(self):
689
+ """Called after solve"""
690
+ if self.save_pdt == 'all':
691
+ # save to worker space
692
+ result_dir = self.femprj_path.replace('.femprj', '.Results')
693
+ pdt_path = os.path.join(result_dir, self.model_name + '.pdt')
694
+ succeed = self.Femtet.SavePDT(pdt_path, True)
695
+
696
+ # convert .pdt to ByteIO
697
+ if succeed:
698
+ with open(pdt_path, 'rb') as f:
699
+ content = f.read()
700
+ return content
701
+
702
+ else:
703
+ raise Exception('pdt ファイルの保存でエラーが発生しました。')
704
+
705
+ else:
706
+ return None
707
+
708
+ def create_jpg_content(self):
709
+ result_dir = self.femprj_path.replace('.femprj', '.Results')
710
+ jpg_path = os.path.join(result_dir, self.model_name + '.jpg')
711
+
712
+ # モデル表示画面の設定
713
+ self.Femtet.SetWindowSize(200, 200)
714
+ self.Femtet.Fit()
715
+ self.Femtet.ViewNumeric.SetCoord(1, 1, 1)
716
+
717
+ # ---モデルの画面を保存---
718
+ self.Femtet.Redraw() # 再描画
719
+ succeed = self.Femtet.SavePicture(jpg_path, 200, 200, 80)
720
+
721
+ self.Femtet.RedrawMode = True # 逐一の描画をオン
722
+
723
+ if not succeed:
724
+ raise Exception('jpg ファイルの保存でエラーが発生しました。')
725
+
726
+ if not os.path.exists(jpg_path):
727
+ raise Exception('保存した jpg ファイルが見つかりませんでした。')
728
+
729
+ with open(jpg_path, 'rb') as f:
730
+ content = f.read()
731
+
732
+ return content
733
+
734
+
735
+ from win32com.client import Dispatch, constants
736
+
737
+
738
+ class _UnPicklableNoFEM(FemtetInterface):
739
+
740
+
741
+ original_femprj_path = 'dummy'
742
+ model_name = 'dummy'
743
+ parametric_output_indexes_use_as_objective = None
744
+ kwargs = dict()
745
+ Femtet = None
746
+ quit_when_destruct = False
747
+
748
+ def __init__(self):
749
+ CoInitialize()
750
+ self.unpicklable_member = Dispatch('FemtetMacro.Femtet')
751
+ self.cns = constants
752
+
753
+ def _setup_before_parallel(self, *args, **kwargs):
754
+ pass
755
+
756
+ def check_param_value(self, *args, **kwargs):
757
+ pass
758
+
759
+ def update_parameter(self, *args, **kwargs):
760
+ pass
761
+
762
+ def update(self, *args, **kwargs):
763
+ pass
764
+
765
+ def create_result_file_content(self):
766
+ """Called after solve"""
767
+
768
+ # save to worker space
769
+ with open(__file__, 'rb') as f:
770
+ content = f.read()
771
+
772
+ return content
773
+
774
+ def create_file_path(self, trial: int):
775
+ # return path of scheduler environment
776
+ here = os.path.dirname(__file__)
777
+ pdt_path = os.path.join(here, f'trial{trial}.pdt')
778
+ return pdt_path
779
+
@@ -55,20 +55,20 @@ def _get_prm_result_names(Femtet):
55
55
  return out
56
56
 
57
57
 
58
- def add_parametric_results_as_objectives(femopt, indexes) -> bool:
58
+ def add_parametric_results_as_objectives(femopt, indexes, directions) -> bool:
59
59
  # load dll and set target femtet
60
60
  dll = _get_dll_with_set_femtet(femopt.fem.Femtet)
61
61
 
62
62
  # get objective names
63
63
  dll.GetPrmnResult.restype = ctypes.c_int
64
64
  n = dll.GetPrmnResult()
65
- for i in indexes:
65
+ for i, direction in zip(indexes, directions):
66
66
  # objective name
67
67
  dll.GetPrmResultName.restype = ctypes.c_char_p
68
68
  result = dll.GetPrmResultName(i)
69
69
  name = result.decode('mbcs')
70
70
  # objective value function
71
- femopt.add_objective(_parametric_objective, name, args=(i,))
71
+ femopt.add_objective(_parametric_objective, name, direction=direction, args=(i,))
72
72
  return True # ここまで来たら成功
73
73
 
74
74
 
@@ -17,6 +17,10 @@ class FemtetWithNXInterface(FemtetInterface):
17
17
 
18
18
  Args:
19
19
  prt_path: The path to the prt file.
20
+ export_curves(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
21
+ export_surfaces(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
22
+ export_solids(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
23
+ export_flattened_assembly(bool or None): Parasolid export setting of NX. If None, PyFemtet does not change the setting of NX. Defaults to None.
20
24
 
21
25
  For details of The other arguments, see ``FemtetInterface``.
22
26
 
@@ -27,9 +31,12 @@ class FemtetWithNXInterface(FemtetInterface):
27
31
  def __init__(
28
32
  self,
29
33
  prt_path,
34
+ export_curves: bool or None = None,
35
+ export_surfaces: bool or None = None,
36
+ export_solids: bool or None = None,
37
+ export_flattened_assembly: bool or None = None,
30
38
  **kwargs
31
39
  ):
32
-
33
40
  # check NX installation
34
41
  self.run_journal_path = os.path.join(os.environ.get('UGII_BASE_DIR'), 'NXBIN', 'run_journal.exe')
35
42
  if not os.path.isfile(self.run_journal_path):
@@ -45,10 +52,19 @@ class FemtetWithNXInterface(FemtetInterface):
45
52
  except ValueError: # get_worker に失敗した場合
46
53
  self.prt_path = os.path.abspath(prt_path)
47
54
 
55
+ self.export_curves = export_curves
56
+ self.export_surfaces = export_surfaces
57
+ self.export_solids = export_solids
58
+ self.export_flattened_assembly = export_flattened_assembly
59
+
48
60
  # FemtetInterface の設定 (femprj_path, model_name の更新など)
49
61
  # + restore 情報の上書き
50
62
  super().__init__(
51
63
  prt_path=self.prt_path,
64
+ export_curves=self.export_curves,
65
+ export_surfaces=self.export_surfaces,
66
+ export_solids=self.export_solids,
67
+ export_flattened_assembly=self.export_flattened_assembly,
52
68
  **kwargs
53
69
  )
54
70
 
@@ -86,10 +102,27 @@ class FemtetWithNXInterface(FemtetInterface):
86
102
  tmp_dict[row['name']] = row['value']
87
103
  str_json = json.dumps(tmp_dict)
88
104
 
105
+ # create dumped json of export settings
106
+ tmp_dict = dict(
107
+ include_curves=self.export_curves,
108
+ include_surfaces=self.export_surfaces,
109
+ include_solids=self.export_solids,
110
+ flatten_assembly=self.export_flattened_assembly,
111
+ )
112
+ dumped_json_export_settings = json.dumps(tmp_dict)
113
+
89
114
  # NX journal を使ってモデルを編集する
90
115
  env = os.environ.copy()
91
116
  subprocess.run(
92
- [self.run_journal_path, self._JOURNAL_PATH, '-args', self.prt_path, str_json, x_t_path],
117
+ [
118
+ self.run_journal_path, # run_journal.exe
119
+ self._JOURNAL_PATH, # update_model.py
120
+ '-args',
121
+ self.prt_path,
122
+ str_json,
123
+ x_t_path,
124
+ dumped_json_export_settings,
125
+ ],
93
126
  env=env,
94
127
  shell=True,
95
128
  cwd=os.path.dirname(self.prt_path)
@@ -1,35 +1,34 @@
1
1
  import os
2
2
  import sys
3
3
  import json
4
- import NXOpen
5
-
4
+ from xml.etree.ElementInclude import include
6
5
 
7
- def main(prtPath:str, parameters:'dict as str', x_tPath:str = None):
8
- '''
9
- .prt ファイルのパスを受け取り、parameters に指定された変数を更新し、
10
- x_tPath が None のときは.prt と同じディレクトリに
11
- .x_t ファイルをエクスポートする
6
+ import NXOpen
12
7
 
13
- Parameters
14
- ----------
15
- prtPath : str
16
- DESCRIPTION.
17
- parameters : 'dict as str'
18
- DESCRIPTION.
19
8
 
20
- Returns
21
- -------
22
- None.
9
+ def main(
10
+ prtPath: str,
11
+ parameters: str, # dumped json
12
+ x_tPath: str,
13
+ dumped_json_export_settings: str,
14
+ ):
15
+ """Update the parameter of .prt file and export to .x_t file."""
23
16
 
24
- '''
25
17
  # 保存先の設定
26
- prtPath = os.path.abspath(prtPath) # 一応
18
+ prtPath = os.path.abspath(prtPath)
27
19
  if x_tPath is None:
28
20
  x_tPath = os.path.splitext(prtPath)[0] + '.x_t'
29
21
 
30
22
  # 辞書の作成
31
23
  parameters = json.loads(parameters)
32
-
24
+
25
+ # export 設定
26
+ settings = json.loads(dumped_json_export_settings)
27
+ include_curves = settings['include_curves']
28
+ include_surfaces = settings['include_surfaces']
29
+ include_solids = settings['include_solids']
30
+ flatten_assembly = settings['flatten_assembly']
31
+
33
32
  # session の取得とパートを開く
34
33
  theSession = NXOpen.Session.GetSession()
35
34
  theSession.Parts.OpenActiveDisplay(prtPath, NXOpen.DisplayPartOption.AllowAdditional)
@@ -40,7 +39,6 @@ def main(prtPath:str, parameters:'dict as str', x_tPath:str = None):
40
39
  displayPart = theSession.Parts.Display
41
40
 
42
41
  # 式を更新
43
- unit_mm = workPart.UnitCollection.FindObject("MilliMeter")
44
42
  for k, v in parameters.items():
45
43
  try:
46
44
  exp = workPart.Expressions.FindObject(k)
@@ -48,14 +46,15 @@ def main(prtPath:str, parameters:'dict as str', x_tPath:str = None):
48
46
  print(f'├ 変数{k}は .prt ファイルに含まれていません。無視されます。')
49
47
  continue
50
48
 
51
- workPart.Expressions.EditWithUnits(exp, unit_mm, str(v))
49
+ workPart.Expressions.Edit(exp, str(v))
52
50
  # 式の更新を適用
53
51
  id1 = theSession.NewestVisibleUndoMark
54
52
  try:
55
53
  nErrs1 = theSession.UpdateManager.DoUpdate(id1)
56
54
  # 更新に失敗
57
55
  except NXOpen.NXException as e:
58
- print(' 形状が破綻しました。操作を取り消します。')
56
+ print(f' ERROR! {e}')
57
+ print(f'└ 形状が破綻しました。操作を取り消します。')
59
58
  return None
60
59
 
61
60
  print('│ model 更新に成功しました。')
@@ -64,19 +63,28 @@ def main(prtPath:str, parameters:'dict as str', x_tPath:str = None):
64
63
  # parasolid のエクスポート
65
64
  parasolidExporter1 = theSession.DexManager.CreateParasolidExporter()
66
65
 
67
- parasolidExporter1.ObjectTypes.Curves = False
68
- parasolidExporter1.ObjectTypes.Surfaces = False
69
- parasolidExporter1.ObjectTypes.Solids = True
66
+ if include_curves is not None:
67
+ parasolidExporter1.ObjectTypes.Curves = include_curves
68
+
69
+ if include_surfaces is not None:
70
+ parasolidExporter1.ObjectTypes.Surfaces = include_surfaces
71
+
72
+ if include_solids is not None:
73
+ parasolidExporter1.ObjectTypes.Solids = include_solids
74
+
75
+ if flatten_assembly is not None:
76
+ parasolidExporter1.FlattenAssembly = flatten_assembly
70
77
 
71
78
  parasolidExporter1.InputFile = prtPath
72
79
  parasolidExporter1.ParasolidVersion = NXOpen.ParasolidExporter.ParasolidVersionOption.Current
73
80
  parasolidExporter1.OutputFile = x_tPath
74
81
 
75
82
  parasolidExporter1.Commit()
76
-
77
83
  parasolidExporter1.Destroy()
78
- except:
79
- print('└ parasolid 更新に失敗しました。')
84
+
85
+ except Exception as e:
86
+ print(f'├ ERROR! {e}')
87
+ print(f'└ parasolid 更新に失敗しました。')
80
88
  return None
81
89
 
82
90
  print('└ parasolid 更新が正常に終了しました。')
pyfemtet/opt/opt/_base.py CHANGED
@@ -88,6 +88,8 @@ class AbstractOptimizer(ABC):
88
88
  y,
89
89
  c,
90
90
  self.message,
91
+ postprocess_func=self.fem.postprocess_func,
92
+ postprocess_args=self.fem.create_postprocess_args(),
91
93
  )
92
94
 
93
95
  logger.debug('history.record end')
@@ -2,9 +2,6 @@ import plotly.graph_objs as go
2
2
  import plotly.express as px
3
3
 
4
4
 
5
- _CUSTOM_DATA_DICT = {'trial': 0} # 連番
6
-
7
-
8
5
  class _ColorSet:
9
6
  non_domi = {True: '#007bff', False: '#6c757d'} # color
10
7
 
@@ -49,7 +46,7 @@ def update_hypervolume_plot(history, df):
49
46
  x="trial",
50
47
  y="hypervolume",
51
48
  markers=True,
52
- custom_data=_CUSTOM_DATA_DICT.keys(),
49
+ custom_data=['trial'],
53
50
  )
54
51
 
55
52
  fig.update_layout(
@@ -67,13 +64,17 @@ def update_default_figure(history, df):
67
64
  obj_names = history.obj_names
68
65
 
69
66
  if len(obj_names) == 0:
70
- return go.Figure()
67
+ fig = go.Figure()
71
68
 
72
69
  elif len(obj_names) == 1:
73
- return update_single_objective_plot(history, df)
70
+ fig = update_single_objective_plot(history, df)
74
71
 
75
72
  elif len(obj_names) >= 2:
76
- return update_multi_objective_pairplot(history, df)
73
+ fig = update_multi_objective_pairplot(history, df)
74
+
75
+ fig.update_traces(hoverinfo="none", hovertemplate=None)
76
+
77
+ return fig
77
78
 
78
79
 
79
80
  def update_single_objective_plot(history, df):
@@ -81,6 +82,9 @@ def update_single_objective_plot(history, df):
81
82
  df = _ls.localize(df)
82
83
  obj_name = history.obj_names[0]
83
84
 
85
+ df.columns = [c.replace(' / ', '<BR>/ ') for c in df.columns]
86
+ obj_name = obj_name.replace(' / ', '<BR>/ ')
87
+
84
88
  fig = px.scatter(
85
89
  df,
86
90
  x='trial',
@@ -94,7 +98,7 @@ def update_single_objective_plot(history, df):
94
98
  _ls.feasible['label']: False,
95
99
  'trial': True,
96
100
  },
97
- custom_data=_CUSTOM_DATA_DICT.keys(),
101
+ custom_data=['trial'],
98
102
  )
99
103
 
100
104
  fig.add_trace(
@@ -126,6 +130,9 @@ def update_multi_objective_pairplot(history, df):
126
130
 
127
131
  obj_names = history.obj_names
128
132
 
133
+ df.columns = [c.replace(' / ', '<BR>/ ') for c in df.columns]
134
+ obj_names = [o.replace(' / ', '<BR>/ ') for o in obj_names]
135
+
129
136
  common_kwargs = dict(
130
137
  color=_ls.non_domi['label'],
131
138
  color_discrete_map={
@@ -137,11 +144,7 @@ def update_multi_objective_pairplot(history, df):
137
144
  _ls.feasible[True]: _ss.feasible[True],
138
145
  _ls.feasible[False]: _ss.feasible[False],
139
146
  },
140
- hover_data={
141
- _ls.feasible['label']: False,
142
- 'trial': True,
143
- },
144
- custom_data=_CUSTOM_DATA_DICT.keys(),
147
+ custom_data=['trial'],
145
148
  category_orders={
146
149
  _ls.feasible['label']: (_ls.feasible[False], _ls.feasible[True]),
147
150
  _ls.non_domi['label']: (_ls.non_domi[False], _ls.non_domi[True]),