pyfemtet 1.1.6__py3-none-any.whl → 1.2.1__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.

@@ -59,7 +59,6 @@ class Message:
59
59
  ERR_RUN_JOURNAL_NOT_FOUND = _(r'"%UGII_BASE_DIR%\NXBIN\run_journal.exe" is not found. Make sure you have NX installed and the environment variable UGII_BASE_DIR is set.')
60
60
  ERR_MODEL_RECONSTRUCTION_FAILED = _('Model reconstruction failed.')
61
61
  ERR_MODEL_UPDATE_FAILED = _('Model update failed.')
62
- ERR_NO_MAKEPY = _('It was detected that the configuration of Femtet python macro constants has not been completed. The configuration was done automatically (python -m win32com.client.makepy FemtetMacro). Please restart the program. If the error persists, please run "py -m win32com.client.makepy FemtetMacro" or "python -m win32com.client.makepy FemtetMacro" on the command prompt.')
63
62
  ERR_FEMTET_CONNECTION_FAILED = _('Failed to connect to Femtet.')
64
63
 
65
64
  @staticmethod
@@ -0,0 +1,169 @@
1
+ from typing import TypeAlias
2
+
3
+ SWVariables: TypeAlias = dict[str, str]
4
+ """<prm_name>: <expression>. Note that the <prm_name> does not contain `"`."""
5
+
6
+
7
+ class EquationContext:
8
+ def __init__(self, swModel) -> None:
9
+ self.swModel = swModel
10
+ self.swEqnMgr = None
11
+
12
+ def __enter__(self):
13
+ # プロパティを退避
14
+ self.swEqnMgr = self.swModel.GetEquationMgr
15
+ self.buffer_aso = self.swEqnMgr.AutomaticSolveOrder
16
+ self.buffer_ar = self.swEqnMgr.AutomaticRebuild
17
+ self.swEqnMgr.AutomaticSolveOrder = False
18
+ self.swEqnMgr.AutomaticRebuild = False
19
+ return self.swEqnMgr
20
+
21
+ def __exit__(self, exc_type, exc_val, exc_tb):
22
+ # プロパティをもとに戻す
23
+ assert self.swEqnMgr is not None
24
+ self.swEqnMgr.AutomaticSolveOrder = self.buffer_aso
25
+ self.swEqnMgr.AutomaticRebuild = self.buffer_ar
26
+
27
+
28
+ class EditPartContext:
29
+ def __init__(self, swModel, component) -> None:
30
+ self.swModel = swModel
31
+ self.component = component
32
+
33
+ def __enter__(self):
34
+ swSelMgr = self.swModel.SelectionManager
35
+ swSelData = swSelMgr.CreateSelectData
36
+ swSelMgr.AddSelectionListObject(self.component, swSelData)
37
+ # self.swModel.EditPart() # 対象がアセンブリの場合動作しない
38
+ self.swModel.AssemblyPartToggle() # Obsolete だが代わりにこれを使う
39
+
40
+ def __exit__(self, exc_type, exc_val, exc_tb):
41
+ self.swModel.EditAssembly()
42
+
43
+
44
+ def is_assembly(swModel_or_name):
45
+ if isinstance(swModel_or_name, str):
46
+ return swModel_or_name.lower().endswith('.sldasm')
47
+ else:
48
+ return swModel_or_name.GetPathName.lower().endswith('.sldasm')
49
+
50
+
51
+ def _iter_parts(swModel):
52
+ components = swModel.GetComponents(
53
+ False # TopOnly
54
+ )
55
+ return components
56
+
57
+
58
+ # Used by pyfemtet-opt-gui
59
+ class SolidworksVariableManager:
60
+
61
+ def __init__(self, logger=None):
62
+ # Used by pyfemtet-opt-gui
63
+ self.updated_objects = set()
64
+ """Updated variable names, sldprt file paths and linked .txt equation file paths."""
65
+ if logger is None:
66
+ from logging import getLogger
67
+ logger = getLogger('solidworks_variable_manager')
68
+ self.logger = logger
69
+
70
+ # Used by pyfemtet-opt-gui
71
+ def update_global_variables_recourse(self, swModel, x: SWVariables):
72
+ # まず自身のパラメータを更新
73
+ self.logger.debug(f'Processing `{swModel.GetPathName}`')
74
+ self._update_global_variables_core(swModel, x)
75
+
76
+ # アセンブリならば、構成部品のパラメータを更新
77
+ if is_assembly(swModel):
78
+ components = _iter_parts(swModel)
79
+ for component in components:
80
+ swPartModel = component.GetModelDoc2
81
+ self.logger.debug(f'Checking `{swPartModel.GetPathName}`')
82
+ if swPartModel.GetPathName.lower() not in self.updated_objects:
83
+ self.logger.debug(f'Processing `{swPartModel.GetPathName}`')
84
+ with EditPartContext(swModel, component):
85
+ self._update_global_variables_core(swPartModel, x)
86
+ self.updated_objects.add(swPartModel.GetPathName.lower())
87
+
88
+ def _update_global_variables_core(self, swModel, x: SWVariables):
89
+ with EquationContext(swModel) as swEqnMgr:
90
+ # txt にリンクされている場合は txt を更新
91
+ if swEqnMgr.LinkToFile:
92
+ self._update_global_variables_linked_txt(swEqnMgr, x)
93
+ self._update_global_variables_simple(swEqnMgr, x)
94
+ # noinspection PyStatementEffect
95
+ swEqnMgr.EvaluateAll
96
+
97
+ def _update_global_variables_linked_txt(self, swEqnMgr, x: SWVariables):
98
+ txt_path = swEqnMgr.FilePath
99
+ if txt_path in self.updated_objects:
100
+ return
101
+ with open(txt_path, 'r', encoding='utf_8_sig') as f:
102
+ equations = [line.strip() for line in f.readlines() if line.strip() != '']
103
+ for i, eq in enumerate(equations):
104
+ equations[i] = self._update_equation(eq, x)
105
+ with open(txt_path, 'w', encoding='utf_8_sig') as f:
106
+ f.writelines([eq + '\n' for eq in equations])
107
+ self.logger.debug(f'`{txt_path}` is updated.')
108
+ self.updated_objects.add(txt_path)
109
+
110
+ def _update_global_variables_simple(self, swEqnMgr, x: SWVariables):
111
+ nEquation = swEqnMgr.GetCount
112
+
113
+ # equation を列挙
114
+ self.logger.debug(f'{nEquation} equations detected.')
115
+ for i in range(nEquation):
116
+ # name, equation の取得
117
+ eq = swEqnMgr.Equation(i)
118
+ prm_name = self._get_left(eq)
119
+ # COM 経由なので必要な時以外は触らない
120
+ self.logger.debug(f'Checking `{prm_name}`')
121
+ if (prm_name in x) and (prm_name not in self.updated_objects):
122
+ self.logger.debug(f'Processing `{prm_name}`')
123
+ # 特定の Equation がテキストリンク有効か
124
+ # どうかを判定する術がないので、一旦更新する
125
+ new_eq = self._update_equation(eq, x)
126
+ swEqnMgr.Equation(i, new_eq)
127
+ # テキストリンクの場合、COM インスタンスに
128
+ # 更新された値が残ってしまうのでテキストを再読み込み
129
+ if swEqnMgr.LinkToFile:
130
+ # noinspection PyStatementEffect
131
+ swEqnMgr.UpdateValuesFromExternalEquationFile
132
+ self.updated_objects.add(prm_name)
133
+
134
+ def _update_equation(self, equation: str, x: SWVariables):
135
+ prm_name = self._get_left(equation)
136
+ if prm_name not in x:
137
+ return equation
138
+ new_eq = f'"{prm_name}" = {x[prm_name]}'
139
+ self.logger.debug(f'New eq.: `{new_eq}`')
140
+ return new_eq
141
+
142
+ @staticmethod
143
+ def _get_left(equation: str):
144
+ tmp = equation.split('=')
145
+ if len(tmp) == 0:
146
+ raise RuntimeError(f'Invalid solidworks equation: {equation} (no `=` contained)')
147
+ return tmp[0].strip('" ')
148
+
149
+ # Used by pyfemtet-opt-gui
150
+ @staticmethod
151
+ def get_equations_recourse(swModel, global_variables_only=False) -> list[str]:
152
+ out = list()
153
+ swEqnMgr = swModel.GetEquationMgr
154
+ for i in range(swEqnMgr.GetCount):
155
+ if global_variables_only and not swEqnMgr.GlobalVariable(i):
156
+ continue
157
+ eq = swEqnMgr.Equation(i)
158
+ out.append(eq)
159
+ if is_assembly(swModel):
160
+ components = _iter_parts(swModel)
161
+ for component in components:
162
+ swPartModel = component.GetModelDoc2
163
+ swEqnMgr = swPartModel.GetEquationMgr
164
+ for i in range(swEqnMgr.GetCount):
165
+ if global_variables_only and not swEqnMgr.GlobalVariable(i):
166
+ continue
167
+ eq = swEqnMgr.Equation(i)
168
+ out.append(eq)
169
+ return out
@@ -0,0 +1,15 @@
1
+ at = '@'
2
+ AT = '_at_'
3
+ hyphen = '-'
4
+ HYPHEN = '_hyphen_'
5
+ dot = '.'
6
+ DOT = '_dot_'
7
+
8
+
9
+ def convert_symbols(name):
10
+ return (
11
+ name
12
+ .replace(dot, DOT)
13
+ .replace(at, AT)
14
+ .replace(hyphen, HYPHEN)
15
+ )
pyfemtet/opt/femopt.py CHANGED
@@ -375,19 +375,20 @@ class FEMOpt:
375
375
  def save_history():
376
376
  while True:
377
377
  sleep(2)
378
- try:
379
- self.opt.history.save()
380
- logger.debug('History saved!')
381
- except PermissionError:
382
- logger.error(
383
- _('Cannot save history. '
384
- 'The most common reason is '
385
- 'that the csv is opened by '
386
- 'another program (such as Excel). '
387
- 'Please free {path} or lost the '
388
- 'optimization history.',
389
- path=self.opt.history.path)
390
- )
378
+ if len(self.opt.history.get_df()) > 0:
379
+ try:
380
+ self.opt.history.save()
381
+ logger.debug('History saved!')
382
+ except PermissionError:
383
+ logger.error(
384
+ _('Cannot save history. '
385
+ 'The most common reason is '
386
+ 'that the csv is opened by '
387
+ 'another program (such as Excel). '
388
+ 'Please free {path} or lost the '
389
+ 'optimization history.',
390
+ path=self.opt.history.path)
391
+ )
391
392
  if entire_status.value >= WorkerStatus.finished:
392
393
  break
393
394
  logger.debug('History save thread finished!')
@@ -505,8 +505,10 @@ class ExcelInterface(COMInterface):
505
505
  if not os.path.exists(xla_file_path):
506
506
  raise FileNotFoundError(
507
507
  _(
508
- en_message='Femtet XLA file not found: {xla_file_path}',
509
- jp_message='Femtet XLA ファイルが見つかりません: {xla_file_path}',
508
+ en_message='Femtet XLA file ({xla_file_path}) not found. '
509
+ 'Please run `Enable Macros` command.',
510
+ jp_message='Femtet XLA ファイル ({xla_file_path}) が見つかりません。'
511
+ '「マクロ機能の有効化」を実行してください。',
510
512
  xla_file_path=xla_file_path
511
513
  )
512
514
  )
@@ -7,13 +7,13 @@ import sys
7
7
  import subprocess
8
8
  from time import sleep
9
9
  from contextlib import nullcontext
10
+ import importlib
10
11
 
11
12
  # noinspection PyUnresolvedReferences
12
13
  from pywintypes import com_error, error
13
14
  # noinspection PyUnresolvedReferences
14
15
  from pythoncom import CoInitialize, CoUninitialize
15
- # noinspection PyUnresolvedReferences
16
- from win32com.client import constants
16
+ from win32com.client import constants, Dispatch
17
17
  import win32con
18
18
  import win32gui
19
19
 
@@ -353,6 +353,8 @@ class FemtetInterface(COMInterface):
353
353
  it will not try existing another Femtet process.
354
354
 
355
355
  """
356
+ # noinspection PyGlobalUndefined
357
+ global constants
356
358
 
357
359
  if connect_method == "new":
358
360
  self._connect_new_femtet()
@@ -373,32 +375,39 @@ class FemtetInterface(COMInterface):
373
375
  if not hasattr(constants, "STATIC_C"):
374
376
  cmd = f"{sys.executable} -m win32com.client.makepy FemtetMacro"
375
377
  subprocess.run(cmd, shell=True)
378
+ sleep(1)
379
+
380
+ import win32com.client
381
+ importlib.reload(win32com.client)
382
+ from win32com.client import Dispatch, constants
383
+ Dispatch('FemtetMacro.Femtet')
384
+
385
+ if not hasattr(constants, "STATIC_C"):
386
+ message = _(
387
+ en_message='It was detected that the configuration of '
388
+ 'Femtet python macro constants has not been '
389
+ 'completed. The configuration was done '
390
+ 'automatically '
391
+ '(python -m win32com.client.makepy FemtetMacro). '
392
+ 'Please restart the program. '
393
+ 'If the error persists, please run '
394
+ '"py -m win32com.client.makepy FemtetMacro" '
395
+ 'or "python -m win32com.client.makepy FemtetMacro" '
396
+ 'on the command prompt.',
397
+ jp_message='Femtet Pythonマクロ定数の設定が完了していない'
398
+ 'ことが検出されました。設定は自動で行われました'
399
+ '(py -m win32com.client.makepy FemtetMacro)。 '
400
+ 'プログラムを再起動してください。'
401
+ 'エラーが解消されない場合は、'
402
+ '"py -m win32com.client.makepy FemtetMacro" か '
403
+ '"python -m win32com.client.makepy FemtetMacro" '
404
+ 'コマンドをコマンドプロンプトで実行してください。'
405
+ )
376
406
 
377
- message = _(
378
- en_message='It was detected that the configuration of '
379
- 'Femtet python macro constants has not been '
380
- 'completed. The configuration was done '
381
- 'automatically '
382
- '(python -m win32com.client.makepy FemtetMacro). '
383
- 'Please restart the program. '
384
- 'If the error persists, please run '
385
- '"py -m win32com.client.makepy FemtetMacro" '
386
- 'or "python -m win32com.client.makepy FemtetMacro" '
387
- 'on the command prompt.',
388
- jp_message='Femtet Pythonマクロ定数の設定が完了していない'
389
- 'ことが検出されました。設定は自動で行われました'
390
- '(py -m win32com.client.makepy FemtetMacro)。 '
391
- 'プログラムを再起動してください。'
392
- 'エラーが解消されない場合は、'
393
- '"py -m win32com.client.makepy FemtetMacro" か '
394
- '"python -m win32com.client.makepy FemtetMacro" '
395
- 'コマンドをコマンドプロンプトで実行してください。'
396
- )
397
-
398
- logger.error("================")
399
- logger.error(message)
400
- logger.error("================")
401
- raise RuntimeError(message)
407
+ logger.error("================")
408
+ logger.error(message)
409
+ logger.error("================")
410
+ raise RuntimeError(message)
402
411
 
403
412
  if self.Femtet is None:
404
413
  raise RuntimeError(_(
@@ -4,7 +4,7 @@ from time import sleep
4
4
  from typing import TYPE_CHECKING, Any
5
5
  import os
6
6
 
7
- from win32com.client import Dispatch, DispatchEx
7
+ from win32com.client import Dispatch
8
8
  from pythoncom import com_error, CoInitialize
9
9
 
10
10
  from pyfemtet._util.dask_util import *
@@ -14,6 +14,8 @@ from pyfemtet._i18n import _
14
14
  from pyfemtet.opt.problem.problem import *
15
15
  from pyfemtet.logger import get_module_logger
16
16
 
17
+ from pyfemtet._util.solidworks_variable import SolidworksVariableManager, is_assembly, SWVariables
18
+
17
19
  if TYPE_CHECKING:
18
20
  from pyfemtet.opt.optimizer import AbstractOptimizer
19
21
 
@@ -36,43 +38,6 @@ class FileNotOpenedError(Exception):
36
38
  pass
37
39
 
38
40
 
39
- class EquationContext:
40
- def __init__(self, swModel) -> None:
41
- self.swModel = swModel
42
- self.swEqnMgr = None
43
-
44
- def __enter__(self):
45
- # プロパティを退避
46
- self.swEqnMgr = self.swModel.GetEquationMgr
47
- self.buffer_aso = self.swEqnMgr.AutomaticSolveOrder
48
- self.buffer_ar = self.swEqnMgr.AutomaticRebuild
49
- self.swEqnMgr.AutomaticSolveOrder = False
50
- self.swEqnMgr.AutomaticRebuild = False
51
- return self.swEqnMgr
52
-
53
- def __exit__(self, exc_type, exc_val, exc_tb):
54
- # プロパティをもとに戻す
55
- assert self.swEqnMgr is not None
56
- self.swEqnMgr.AutomaticSolveOrder = self.buffer_aso
57
- self.swEqnMgr.AutomaticRebuild = self.buffer_ar
58
-
59
-
60
- class EditPartContext:
61
- def __init__(self, swModel, component) -> None:
62
- self.swModel = swModel
63
- self.component = component
64
-
65
- def __enter__(self):
66
- swSelMgr = self.swModel.SelectionManager
67
- swSelData = swSelMgr.CreateSelectData
68
- swSelMgr.AddSelectionListObject(self.component, swSelData)
69
- # self.swModel.EditPart() # 対象がアセンブリの場合動作しない
70
- self.swModel.AssemblyPartToggle() # Obsolete だが代わりにこれを使う
71
-
72
- def __exit__(self, exc_type, exc_val, exc_tb):
73
- self.swModel.EditAssembly()
74
-
75
-
76
41
  # noinspection PyPep8Naming
77
42
  class SolidworksInterface(COMInterface):
78
43
  """
@@ -132,13 +97,13 @@ class SolidworksInterface(COMInterface):
132
97
  self.swApp.Visible = self.solidworks_visible
133
98
 
134
99
  def _setup_before_parallel(self, scheduler_address=None):
135
- if not _is_assembly(self.sldprt_path):
100
+ if not is_assembly(self.sldprt_path):
136
101
  self._distribute_files([self.sldprt_path], scheduler_address)
137
102
 
138
103
  def _setup_after_parallel(self, opt: AbstractOptimizer):
139
104
 
140
105
  # validation
141
- if _is_assembly(self.sldprt_path) and get_worker() is not None:
106
+ if is_assembly(self.sldprt_path) and get_worker() is not None:
142
107
  # 現在の仕様だと sldprt_path だけが
143
108
  # worker_space に保存される。
144
109
  # 並列処理に対応するためには
@@ -149,7 +114,7 @@ class SolidworksInterface(COMInterface):
149
114
  jp_message='SolidworksInterfaceでアセンブリパーツを対象とする場合、並列処理はサポートされていません。'
150
115
  ))
151
116
 
152
- if not _is_assembly(self.sldprt_path):
117
+ if not is_assembly(self.sldprt_path):
153
118
  # get suffix
154
119
  suffix = self._get_file_suffix(opt)
155
120
 
@@ -165,7 +130,7 @@ class SolidworksInterface(COMInterface):
165
130
  self.connect_sw()
166
131
 
167
132
  # open it
168
- if _is_assembly(self.sldprt_path):
133
+ if is_assembly(self.sldprt_path):
169
134
  self.swApp.OpenDoc(self.sldprt_path, swDocASSEMBLY)
170
135
  else:
171
136
  self.swApp.OpenDoc(self.sldprt_path, swDocPART)
@@ -185,8 +150,14 @@ class SolidworksInterface(COMInterface):
185
150
  with Lock(self._access_sw_lock_name):
186
151
  sleep(0.2)
187
152
  swModel = self.swModel
188
- mgr = _UpdateVariableManager()
189
- mgr._update_global_variables(swModel, self.current_prm_values)
153
+ mgr = SolidworksVariableManager(asm_logger)
154
+ sw_variables: SWVariables = {
155
+ name: str(param.value) + param.properties.get('unit', '')
156
+ for name, param in
157
+ self.current_prm_values.items()
158
+ if isinstance(param.value, float | int)
159
+ }
160
+ mgr.update_global_variables_recourse(swModel, sw_variables)
190
161
 
191
162
  def update_model(self):
192
163
  """Update .sldprt"""
@@ -229,121 +200,6 @@ class SolidworksInterface(COMInterface):
229
200
  sleep(3)
230
201
 
231
202
 
232
- def _is_assembly(swModel_or_name):
233
- if isinstance(swModel_or_name, str):
234
- return swModel_or_name.lower().endswith('.sldasm')
235
- else:
236
- return swModel_or_name.GetPathName.lower().endswith('.sldasm')
237
-
238
-
239
- def _iter_parts(swModel):
240
- components = swModel.GetComponents(
241
- False # TopOnly
242
- )
243
- return components
244
-
245
-
246
- class _UpdateVariableManager:
247
-
248
- def __init__(self):
249
- self.updated_variables = set()
250
-
251
- def _update_global_variables(self, swModel, x: TrialInput):
252
- # まず自身のパラメータを更新
253
- asm_logger.debug(f'Processing `{swModel.GetPathName}`')
254
- self._update_global_variables_core(swModel, x)
255
-
256
- # アセンブリならば、構成部品のパラメータを更新
257
- if _is_assembly(swModel):
258
- components = _iter_parts(swModel)
259
- for component in components:
260
- swPartModel = component.GetModelDoc2
261
- asm_logger.debug(f'Checking `{swPartModel.GetPathName}`')
262
- if swPartModel.GetPathName.lower() not in self.updated_variables:
263
- asm_logger.debug(f'Processing `{swPartModel.GetPathName}`')
264
- with EditPartContext(swModel, component):
265
- self._update_global_variables_core(swPartModel, x)
266
- self.updated_variables.add(swPartModel.GetPathName.lower())
267
-
268
- def _update_global_variables_core(self, swModel, x: TrialInput):
269
- with EquationContext(swModel) as swEqnMgr:
270
- # txt にリンクされている場合は txt を更新
271
- if swEqnMgr.LinkToFile:
272
- self._update_global_variables_linked_txt(swEqnMgr, x)
273
- self._update_global_variables_simple(swEqnMgr, x)
274
- # noinspection PyStatementEffect
275
- swEqnMgr.EvaluateAll
276
-
277
- def _update_global_variables_linked_txt(self, swEqnMgr, x: TrialInput):
278
- txt_path = swEqnMgr.FilePath
279
- if txt_path in self.updated_variables:
280
- return
281
- with open(txt_path, 'r', encoding='utf_8_sig') as f:
282
- equations = [line.strip() for line in f.readlines() if line.strip() != '']
283
- for i, eq in enumerate(equations):
284
- equations[i] = self._update_equation(eq, x)
285
- with open(txt_path, 'w', encoding='utf_8_sig') as f:
286
- f.writelines([eq + '\n' for eq in equations])
287
- asm_logger.debug(f'`{txt_path}` is updated.')
288
- self.updated_variables.add(txt_path)
289
-
290
- def _update_global_variables_simple(self, swEqnMgr, x: TrialInput):
291
- nEquation = swEqnMgr.GetCount
292
-
293
- # equation を列挙
294
- asm_logger.debug(f'{nEquation} equations detected.')
295
- for i in range(nEquation):
296
- # name, equation の取得
297
- eq = swEqnMgr.Equation(i)
298
- prm_name = self._get_left(eq)
299
- # COM 経由なので必要な時以外は触らない
300
- asm_logger.debug(f'Checking `{prm_name}`')
301
- if (prm_name in x) and (prm_name not in self.updated_variables):
302
- asm_logger.debug(f'Processing `{prm_name}`')
303
- # 特定の Equation がテキストリンク有効か
304
- # どうかを判定する術がないので、一旦更新する
305
- new_eq = self._update_equation(eq, x)
306
- swEqnMgr.Equation(i, new_eq)
307
- # テキストリンクの場合、COM インスタンスに
308
- # 更新された値が残ってしまうのでテキストを再読み込み
309
- if swEqnMgr.LinkToFile:
310
- # noinspection PyStatementEffect
311
- swEqnMgr.UpdateValuesFromExternalEquationFile
312
- self.updated_variables.add(prm_name)
313
-
314
- def _update_equation(self, equation: str, x: TrialInput):
315
- prm_name = self._get_left(equation)
316
- if prm_name not in x:
317
- return equation
318
- prm = x[prm_name]
319
- right = str(prm.value) + prm.properties.get('unit', '')
320
- new_eq = f'"{prm_name}" = {right}'
321
- asm_logger.debug(f'New eq.: `{new_eq}`')
322
- return new_eq
323
-
324
- @staticmethod
325
- def _get_left(equation: str):
326
- return equation.split('=')[0].strip('" ')
327
-
328
- @staticmethod
329
- def _load(swModel):
330
- # テスト用関数
331
- out = set()
332
- swEqnMgr = swModel.GetEquationMgr
333
- for i in range(swEqnMgr.GetCount):
334
- eq = swEqnMgr.Equation(i)
335
- out.add(eq)
336
- if _is_assembly(swModel):
337
- components = _iter_parts(swModel)
338
- for component in components:
339
- swPartModel = component.GetModelDoc2
340
- swEqnMgr = swPartModel.GetEquationMgr
341
- for i in range(swEqnMgr.GetCount):
342
- eq = swEqnMgr.Equation(i)
343
- out.add(eq)
344
- return out
345
-
346
-
347
203
  # noinspection PyPep8Naming
348
204
  def _get_model_by_basename(swApp, basename):
349
205
  swModel = swApp.ActivateDoc(basename)
@@ -133,6 +133,8 @@ class AbstractOptimizer:
133
133
  *,
134
134
  pass_to_fem: bool = True,
135
135
  ):
136
+ var: Variable
137
+ # noinspection PyUnreachableCode
136
138
  if isinstance(value, Real):
137
139
  var = NumericVariable()
138
140
  elif isinstance(value, str):
@@ -148,7 +150,7 @@ class AbstractOptimizer:
148
150
  var.pass_to_fem = pass_to_fem
149
151
  var.properties = properties if properties is not None else {}
150
152
  _duplicated_name_check(name, self.variable_manager.variables.keys())
151
- self.variable_manager.variables.update({name: var})
153
+ self.variable_manager.set_variable(var)
152
154
 
153
155
  def add_parameter(
154
156
  self,
@@ -176,7 +178,7 @@ class AbstractOptimizer:
176
178
  prm.properties = properties
177
179
  prm.pass_to_fem = pass_to_fem
178
180
  _duplicated_name_check(name, self.variable_manager.variables.keys())
179
- self.variable_manager.variables.update({name: prm})
181
+ self.variable_manager.set_variable(prm)
180
182
 
181
183
  def add_expression_string(
182
184
  self,
@@ -185,14 +187,18 @@ class AbstractOptimizer:
185
187
  properties: dict[str, ...] | None = None,
186
188
  *,
187
189
  pass_to_fem: bool = True,
190
+ _disable_matmul_operator: bool = True
188
191
  ) -> None:
189
192
  var = ExpressionFromString()
190
193
  var.name = name
191
- var._expr = ExpressionFromString.InternalClass(expression_string=expression_string)
194
+ var._expr = ExpressionFromString.InternalClass(
195
+ expression_string=expression_string,
196
+ _disable_matmul_operator=_disable_matmul_operator,
197
+ )
192
198
  var.properties = properties or dict()
193
199
  var.pass_to_fem = pass_to_fem
194
200
  _duplicated_name_check(name, self.variable_manager.variables.keys())
195
- self.variable_manager.variables.update({name: var})
201
+ self.variable_manager.set_variable(var)
196
202
 
197
203
  def add_expression_sympy(
198
204
  self,
@@ -208,7 +214,7 @@ class AbstractOptimizer:
208
214
  var.properties = properties or dict()
209
215
  var.pass_to_fem = pass_to_fem
210
216
  _duplicated_name_check(name, self.variable_manager.variables.keys())
211
- self.variable_manager.variables.update({name: var})
217
+ self.variable_manager.set_variable(var)
212
218
 
213
219
  def add_expression(
214
220
  self,
@@ -228,7 +234,7 @@ class AbstractOptimizer:
228
234
  var.properties = properties or dict()
229
235
  var.pass_to_fem = pass_to_fem
230
236
  _duplicated_name_check(name, self.variable_manager.variables.keys())
231
- self.variable_manager.variables.update({name: var})
237
+ self.variable_manager.set_variable(var)
232
238
 
233
239
  def add_categorical_parameter(
234
240
  self,
@@ -252,7 +258,7 @@ class AbstractOptimizer:
252
258
  prm.properties = properties
253
259
  prm.pass_to_fem = pass_to_fem
254
260
  _duplicated_name_check(name, self.variable_manager.variables.keys())
255
- self.variable_manager.variables.update({name: prm})
261
+ self.variable_manager.set_variable(prm)
256
262
 
257
263
  def add_objective(
258
264
  self,
@@ -280,6 +286,7 @@ class AbstractOptimizer:
280
286
  kwargs: dict | None = None,
281
287
  ):
282
288
  # argument processing
289
+ # noinspection PyUnreachableCode
283
290
  if isinstance(names, str):
284
291
  names = [f'{names}_{i}' for i in range(n_return)]
285
292
  elif isinstance(names, Sequence):
@@ -466,7 +473,7 @@ class AbstractOptimizer:
466
473
  raise NotImplementedError
467
474
  return violation_names
468
475
 
469
- def _check_and_raise_interruption(self) -> ...:
476
+ def _check_and_raise_interruption(self):
470
477
  # raise Interrupt
471
478
  interrupted = self.entire_status.value >= WorkerStatus.interrupting
472
479
  if interrupted:
@@ -704,7 +711,7 @@ class AbstractOptimizer:
704
711
  self,
705
712
  x: TrialInput,
706
713
  opt_: AbstractOptimizer | None = None,
707
- trial_id: str =None,
714
+ trial_id: str = None,
708
715
  ) -> _FReturnValue | None:
709
716
  """Nothing will be raised even if infeasible."""
710
717
 
@@ -1,14 +1,32 @@
1
+ import re
1
2
  from numbers import Number
2
3
 
3
4
  from sympy import sympify
4
5
  from sympy.core.sympify import SympifyError
5
6
  from sympy import Min, Max, Add, Symbol, Expr, Basic # TODO: Add sqrt, pow
6
7
 
8
+ from pyfemtet._util.symbol_support_for_param_name import convert_symbols
9
+
7
10
  __all__ = [
8
11
  '_ExpressionFromString', 'InvalidExpression', 'SympifyError'
9
12
  ]
10
13
 
11
14
 
15
+ def _convert(expr_str):
16
+ """ \" で囲まれた部分があれば記号を置き換える """
17
+
18
+ def repl(m: re.Match) -> str:
19
+ inner = m.group(1)
20
+ return f'"{convert_symbols(inner)}"'
21
+
22
+ # 非貪欲で " 内だけを拾う
23
+ expr_str = re.sub(r'"(.+?)"', repl, expr_str)
24
+ # " を消す
25
+ expr_str = expr_str.replace('"', '')
26
+
27
+ return expr_str
28
+
29
+
12
30
  class InvalidExpression(Exception):
13
31
  pass
14
32
 
@@ -27,7 +45,11 @@ class _ExpressionFromString:
27
45
  _expr_str: str
28
46
  _sympy_expr: Expr
29
47
 
30
- def __init__(self, expression_string: str | Number = None, sympy_expr: Expr = None):
48
+ def __init__(
49
+ self,
50
+ expression_string: str | Number = None,
51
+ sympy_expr: Expr = None,
52
+ ):
31
53
  """
32
54
  Raises:
33
55
  SympifyError: Sympy が認識できない場合
@@ -54,6 +76,10 @@ class _ExpressionFromString:
54
76
  e.expr # '1.0'
55
77
  e.value # 1.0
56
78
 
79
+ # To use "-", "@" and "." for name
80
+ e = Expression('"Sample-1.0@Part1" * 2')
81
+ e.expr # 'Sample_hyphen_1_dot_0_at_Part1 * 2'
82
+
57
83
  """
58
84
 
59
85
  # check
@@ -66,7 +92,7 @@ class _ExpressionFromString:
66
92
 
67
93
  else:
68
94
  assert expression_string is not None
69
- self._expr_str: str = str(expression_string)
95
+ self._expr_str: str = _convert(str(expression_string))
70
96
 
71
97
  # max(name1, name2) など関数を入れる際に問題になるので
72
98
  # 下記の仕様は廃止、使い方として数値桁区切り , を入れてはいけない
@@ -74,7 +100,7 @@ class _ExpressionFromString:
74
100
  # # 日本人が数値に , を使うとき Python では _ を意味する
75
101
  # # expression に _ が入っていても構わない
76
102
  # tmp_expr = str(self._expr_str).replace(',', '_')
77
- self._sympy_expr = sympify(self._expr_str, locals=get_valid_functions())
103
+ self._sympy_expr = sympify(self._expr_str, locals=get_valid_functions()) # noqa
78
104
 
79
105
  if not isinstance(self._sympy_expr, Basic):
80
106
  raise InvalidExpression(f'{self._expr_str} は数式ではありません。')
@@ -101,12 +127,12 @@ class _ExpressionFromString:
101
127
  in dependency_values.values()]), \
102
128
  'ExpressionFromString では数値変数のみをサポートしています。'
103
129
 
104
- re_sympy_expr = sympify(
130
+ re_sympy_expr = sympify( # noqa
105
131
  self.expression_string,
106
132
  locals=get_valid_functions(dependency_values),
107
133
  )
108
134
 
109
- evaluated_sympy_obj = re_sympy_expr.subs(dependency_values)
135
+ evaluated_sympy_obj = re_sympy_expr.subs(dependency_values) # noqa
110
136
  try:
111
137
  evaluated_value = float(evaluated_sympy_obj)
112
138
  except (ValueError, TypeError) as e:
@@ -3,12 +3,14 @@ from typing import Callable, TypeAlias, Literal
3
3
  import inspect
4
4
  from numbers import Real # マイナーなので型ヒントには使わず isinstance で使う
5
5
  from graphlib import TopologicalSorter
6
+ import unicodedata
6
7
 
7
8
  import numpy as np
8
9
 
9
10
  from ._string_as_expression import _ExpressionFromString
10
11
 
11
12
  from pyfemtet._i18n import _
13
+ from pyfemtet._util.symbol_support_for_param_name import convert_symbols
12
14
 
13
15
  __all__ = [
14
16
  'SupportedVariableTypes',
@@ -320,13 +322,16 @@ class VariableManager:
320
322
  if filter is not None:
321
323
  if 'pass_to_fem' in filter:
322
324
  if var.pass_to_fem:
325
+ name = var.properties.get('original_name', name)
323
326
  raw.update({name: var})
324
327
 
325
328
  if 'parameter' in filter:
326
329
  if isinstance(var, Parameter):
330
+ name = var.properties.get('original_name', name)
327
331
  raw.update({name: var})
328
332
 
329
333
  else:
334
+ name = var.properties.get('original_name', name)
330
335
  raw.update({name: var})
331
336
 
332
337
  if format is None:
@@ -350,3 +355,13 @@ class VariableManager:
350
355
  format=format,
351
356
  )
352
357
  )
358
+
359
+ def set_variable(self, variable: Variable):
360
+ original_name = variable.name
361
+ variable.properties.update(
362
+ {'original_name': original_name}
363
+ )
364
+ variable.name = convert_symbols(variable.name)
365
+ if not unicodedata.is_normalized('NFKC', variable.name):
366
+ variable.name = unicodedata.normalize('NFKC', variable.name)
367
+ self.variables.update({variable.name: variable})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyfemtet
3
- Version: 1.1.6
3
+ Version: 1.2.1
4
4
  Summary: Design parameter optimization using Femtet.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -7,7 +7,7 @@ pyfemtet/_i18n/i18n.py,sha256=zBbatQO7bkyO1MU6Y8TtrhGpDoUMP2PetRyWsINVcHc,808
7
7
  pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.mo,sha256=wjYhvR2TUpjHCBowrW2bQYUxKmnEi3d8GBPgseadRGw,34424
8
8
  pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.po,sha256=ktqUESvDUja2LQJDo-oEv58FH6klUmpu3lAoITtR_NQ,48313
9
9
  pyfemtet/_i18n/locales/messages.pot,sha256=krqoEumXnY45pG5dm-dQPmynb-eNx1BbIfbHB0URCvE,30025
10
- pyfemtet/_i18n/messages.py,sha256=mzTARnpZPZ-Pmcq8RdOyy5a4XGCCSxwxuoHjN_HJ0TM,17382
10
+ pyfemtet/_i18n/messages.py,sha256=AvGLbs_ELTIBm4nCeDyaXWsEiTPuGkYVAjlp_TCfxmo,16994
11
11
  pyfemtet/_util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  pyfemtet/_util/closing.py,sha256=JPcgHDbW249YF20bMOX6UX-LquWoCWA14KhX-qFouR4,502
13
13
  pyfemtet/_util/dask_util.py,sha256=ekzOFqSOIHyB8KK5--ndM2xBdueIfS1pi-inOLj6JT4,2198
@@ -21,7 +21,9 @@ pyfemtet/_util/femtet_version.py,sha256=9bWRMC_Exb-3rh5bg9eKfwBcgkxz_vg_eX99RPuk
21
21
  pyfemtet/_util/helper.py,sha256=chlfSDQ764kn0mVgBXj8WXKBrje25AX6Riia8W5zkJo,2543
22
22
  pyfemtet/_util/process_util.py,sha256=_hiRTZVZll8tnlBfXvz6GcBue4aE__jA0KnsVXe6m2A,3038
23
23
  pyfemtet/_util/sample.xlsx,sha256=OU8mBY48YESJFQrdt4OkntlE1z-6WiyUyOV-PMr09DQ,9423
24
+ pyfemtet/_util/solidworks_variable.py,sha256=aZqDH1Jx5rpK2paFyKL8RODV0jmEfq1pKVCsSmr40GA,6969
24
25
  pyfemtet/_util/str_enum.py,sha256=b-mQRUsSZvk4zupYTxxSaOm3rtxfNyOajywZ82x9rmk,1441
26
+ pyfemtet/_util/symbol_support_for_param_name.py,sha256=6pR5gt24R6yhxh6GhyQZXTN9fxqxGa3ObTV31wCc0EM,224
25
27
  pyfemtet/core.py,sha256=t5tvWGrBNzCL9cP-91hbTR8q5lzULPsVeIEybeslhxQ,936
26
28
  pyfemtet/dispatch_extensions/__init__.py,sha256=BzxYq3x8YdkdClq4VvH4G5HTGxu5nyAhN7xlFsnTv8c,159
27
29
  pyfemtet/dispatch_extensions/_impl.py,sha256=Sgp350ioKcNVslXv9xRdtRjaQGRQM-BwbJYXjeildtw,11107
@@ -29,7 +31,7 @@ pyfemtet/logger/__init__.py,sha256=lofBrZHr0P1hsxPUiPG1SQqKxCuSBk8zGnR7vUfCHYw,5
29
31
  pyfemtet/logger/_impl.py,sha256=tR71WZbjUvnZqULzxD4Y8Vhq8eBnJhMm360-JXxB5Dc,7012
30
32
  pyfemtet/opt/__init__.py,sha256=1LcwTddtoi8plemxkzmX0YEKiNpAZvKn9OoNQysyDLE,339
31
33
  pyfemtet/opt/exceptions.py,sha256=M_O7jm20Y4e_QxsKF6tnEl-OrAtErUOj6hNT7eEXCO4,1327
32
- pyfemtet/opt/femopt.py,sha256=Zht_H_eaTUwUcA7XFlzod0mGoJzTOZckqRK3VuwjaHM,23716
34
+ pyfemtet/opt/femopt.py,sha256=d-w9enC_XG-4ScIE26PvnoQNqVBXWyveade0wrEcDTM,23827
33
35
  pyfemtet/opt/history/__init__.py,sha256=pUp3SO4R7RGzmpNDLBg_pQH0X2yzBd-oqsHXWmB33os,201
34
36
  pyfemtet/opt/history/_history.py,sha256=K1k-iOSFoowqKPVZgvWEhdysO9ZsMuqEQ-P_kvO-T3U,54587
35
37
  pyfemtet/opt/history/_hypervolume.py,sha256=_IvGH71ZNreWvDQCG815Q2hS1OEvPFPQhUnNXf1UxRQ,4449
@@ -39,10 +41,10 @@ pyfemtet/opt/interface/_base_interface.py,sha256=iWJmJ8kxRH-Cztfhy3QKfRhSKRMytBt
39
41
  pyfemtet/opt/interface/_dummy_classes.py,sha256=847zs3SwetMpRsGtivhvST_z2UKavKvTfUBZvkYfqB0,505
40
42
  pyfemtet/opt/interface/_excel_interface/__init__.py,sha256=bFOmY18-j4RJc_dHQMe62GsxFwQSj7RWdvi6jxWuqyg,74
41
43
  pyfemtet/opt/interface/_excel_interface/debug-excel-interface.xlsm,sha256=TM1CEOC5XtU7qYKNnHScO02kdtXT-gc5y29m2hatsm0,114259
42
- pyfemtet/opt/interface/_excel_interface/excel_interface.py,sha256=x_pKZzjCc_c2HuypHY5wIaRVtjKa48SYbmqtmduLldM,39680
44
+ pyfemtet/opt/interface/_excel_interface/excel_interface.py,sha256=Sghavj7bcslQ5ue9xJzV6DdBfhv6XKn-XxKD-T39KEo,39854
43
45
  pyfemtet/opt/interface/_femtet_interface/__init__.py,sha256=snQruC8Rl_5rFeVmiqw9lmzdJ5mL42HpIlHIn5ytd8s,77
44
46
  pyfemtet/opt/interface/_femtet_interface/_femtet_parametric.py,sha256=dEe6udq2CBpXAcKCye90sXC0UVKok14LORitobc8DK8,10282
45
- pyfemtet/opt/interface/_femtet_interface/femtet_interface.py,sha256=8Z4yNpyqXXaqj_aBg7x4l2x63lAOfLQ6VKSP4sx-X5g,45309
47
+ pyfemtet/opt/interface/_femtet_interface/femtet_interface.py,sha256=ptvklQdKwSq9sW712Y4-sO4nTZPVfjrDdBToGOyQoIE,45717
46
48
  pyfemtet/opt/interface/_femtet_with_nx_interface/__init__.py,sha256=ppeoWVSmVsTmDNKpuFRVTnhjcoefQVEog3-FRiKpEe4,104
47
49
  pyfemtet/opt/interface/_femtet_with_nx_interface/femtet_with_nx_interface.py,sha256=IPIoNMtcJmtiv7eM3yDMWDOynTf0mXd-438LoDVqZCU,8628
48
50
  pyfemtet/opt/interface/_femtet_with_nx_interface/model1.prt,sha256=cYVw2izr4_9PCPHOpi46XmDVOuNZ5ksuwKqzBtCZfNA,104833
@@ -51,7 +53,7 @@ pyfemtet/opt/interface/_femtet_with_nx_interface/update_model.py,sha256=2U5SJWnG
51
53
  pyfemtet/opt/interface/_femtet_with_solidworks/__init__.py,sha256=5McSpy2uTmJNBylCrKt4xMSq90hlSpqyXYsjwZT3yGA,128
52
54
  pyfemtet/opt/interface/_femtet_with_solidworks/femtet_with_solidworks_interface.py,sha256=xBAmHbzNrmHI6zzwUMX_mdjUkhRfyqzmYQN2_QNZcfE,5897
53
55
  pyfemtet/opt/interface/_solidworks_interface/__init__.py,sha256=2c52Hfme1xdJepewRGVkPT4yhrZMQgzlCuqvHzEZPVk,95
54
- pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py,sha256=2SaUI5Lh1gVGqTNcSgqn0Ay1e0tZQHIXFOyYquwVvPw,14127
56
+ pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py,sha256=qJIC6Qg7slskDwKDRTFYKzbftqseUaYveRTtOdZA_EQ,8370
55
57
  pyfemtet/opt/interface/_solidworks_interface/sw_const.py,sha256=M6KV0KmRiSOofW4ydV-3Zxqzofz4ij13CsM3Ggw6HS4,3085
56
58
  pyfemtet/opt/interface/_surrogate_model_interface/__init__.py,sha256=9sjzQjJsMLdpBSpURyl8x4VQHEO_PGYgAshCHoycAPI,252
57
59
  pyfemtet/opt/interface/_surrogate_model_interface/base_surrogate_interface.py,sha256=48mUOPgOVi_SRs_VnElgh6BMUJHQG9jzWpCocK_gjiY,6355
@@ -65,7 +67,7 @@ pyfemtet/opt/meta_script/__main__.py,sha256=9-QM6eZOLpZ_CxERpRu3RAMqpudorSJdPCiK
65
67
  pyfemtet/opt/meta_script/sample/sample.bas,sha256=2iuSYMgPDyAdiSDVGxRu3avjcZYnULz0l8e25YBa7SQ,27966
66
68
  pyfemtet/opt/meta_script/sample/sample.femprj,sha256=6_0ywhgXxZjdzZzQFog8mgMUEjKNCFVNlEgAWoptovk,292885
67
69
  pyfemtet/opt/optimizer/__init__.py,sha256=A4QYeF0KHEFdwoxLfkDND7ikDQ186Ryy3oXEGdakFSg,463
68
- pyfemtet/opt/optimizer/_base_optimizer.py,sha256=9vwrB7ER-Qfh0tGdP5Fg7mP459WXFGSc-yMlyYdZ4sY,37598
70
+ pyfemtet/opt/optimizer/_base_optimizer.py,sha256=z3NQyKSQkRHHlf1UWYWVnAQaBIMpX92qWdBlh-NfE4A,37760
69
71
  pyfemtet/opt/optimizer/_trial_queue.py,sha256=Yv6JlfVCYOiCukllfxk79xU4_utmxwRA3gcCWpdyG9k,2919
70
72
  pyfemtet/opt/optimizer/optuna_optimizer/__init__.py,sha256=u2Bwc79tkZTU5dMbhzzrPQi0RlFg22UgXc-m9K9G6wQ,242
71
73
  pyfemtet/opt/optimizer/optuna_optimizer/_optuna_attribute.py,sha256=7eZsruVCGgMlcnf3a9Vf55FOEE-D7V777MJQajI12Cw,1842
@@ -85,8 +87,8 @@ pyfemtet/opt/prediction/_model.py,sha256=uw3CW_sNkoFa3Cn_ek3_Tr2lYl4ClptKGIpmRF2
85
87
  pyfemtet/opt/problem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
88
  pyfemtet/opt/problem/problem.py,sha256=X9mro2yVJ6Uw9ck0F0OjG-0M2ReKtuWltu-JUEFIkzQ,10025
87
89
  pyfemtet/opt/problem/variable_manager/__init__.py,sha256=uzuraWUZfLzB3uZHIQHFL7uMxWvv7Oaf940zEozXtNY,476
88
- pyfemtet/opt/problem/variable_manager/_string_as_expression.py,sha256=aTJ9W9Gs6BS0Z_OsxWByJs9dAt32opD2_9913MCggPg,3626
89
- pyfemtet/opt/problem/variable_manager/_variable_manager.py,sha256=jtIHFWgVP2jhA3c5uSD388VZHuShR25ZZ8SYz5-6Rro,12785
90
+ pyfemtet/opt/problem/variable_manager/_string_as_expression.py,sha256=LlwVkg7__doA_cprcsZyWC_5Yy_-10c-Bs7fQhur7BM,4324
91
+ pyfemtet/opt/problem/variable_manager/_variable_manager.py,sha256=08pTFp3LnOraXWUj99fhmr32v-V1KDKioO6OsQ2xNEo,13516
90
92
  pyfemtet/opt/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
93
  pyfemtet/opt/visualization/_create_wrapped_components.py,sha256=9AltJHr1DM6imZfpNp867rC-uAYqQ-emdgTLChKDrl8,2513
92
94
  pyfemtet/opt/visualization/history_viewer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -172,9 +174,9 @@ pyfemtet/opt/visualization/plotter/parallel_plot_creator.py,sha256=VRhT0CUG1mCHD
172
174
  pyfemtet/opt/visualization/plotter/pm_graph_creator.py,sha256=7EwmoJlnHwDrpw65NchiA63FIjgGTLq6vTcpTzrSnJo,11841
173
175
  pyfemtet/opt/wat_ex14_parametric_jp.femprj,sha256=dMwQMt6yok_PbZLyxPYdmg5wJQwgQDZ4RhS76zdGLGk,177944
174
176
  pyfemtet/opt/worker_status.py,sha256=simvPa1AkO1idmPXrF5WjYVEBx3tO7hLhbM3J1rFjdo,3824
175
- pyfemtet-1.1.6.dist-info/METADATA,sha256=d9ONd4nzpIoizIL5ZFjQ3v_9RJ5vm_eElDuZFwaw7A4,3410
176
- pyfemtet-1.1.6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
177
- pyfemtet-1.1.6.dist-info/entry_points.txt,sha256=Tsb_l_8Z6pyyq2tRfuKiwfJUV3nq_cHoLS61foALtsg,134
178
- pyfemtet-1.1.6.dist-info/licenses/LICENSE,sha256=LWUL5LlMGjSRTvsalS8_fFuwS4VMw18fJSNWFwDK8pc,1060
179
- pyfemtet-1.1.6.dist-info/licenses/LICENSE_THIRD_PARTY.txt,sha256=8_9-cgzTpmeuCqItPZb9-lyAZcH2Qp9sZTU_hYuOZIQ,191
180
- pyfemtet-1.1.6.dist-info/RECORD,,
177
+ pyfemtet-1.2.1.dist-info/METADATA,sha256=xZOqdfjtSbf1ZCNoG2Z3nwC4SJpNkPBaa_zaUzDk0Uk,3410
178
+ pyfemtet-1.2.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
179
+ pyfemtet-1.2.1.dist-info/entry_points.txt,sha256=Tsb_l_8Z6pyyq2tRfuKiwfJUV3nq_cHoLS61foALtsg,134
180
+ pyfemtet-1.2.1.dist-info/licenses/LICENSE,sha256=LWUL5LlMGjSRTvsalS8_fFuwS4VMw18fJSNWFwDK8pc,1060
181
+ pyfemtet-1.2.1.dist-info/licenses/LICENSE_THIRD_PARTY.txt,sha256=8_9-cgzTpmeuCqItPZb9-lyAZcH2Qp9sZTU_hYuOZIQ,191
182
+ pyfemtet-1.2.1.dist-info/RECORD,,