setupEM 0.6.1__tar.gz → 0.6.4__tar.gz

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.
Files changed (27) hide show
  1. {setupem-0.6.1 → setupem-0.6.4}/PKG-INFO +16 -3
  2. {setupem-0.6.1 → setupem-0.6.4}/README.md +10 -0
  3. setupem-0.6.1/src/setupEM.egg-info/PKG-INFO → setupem-0.6.4/README_pypi.md +13 -21
  4. {setupem-0.6.1 → setupem-0.6.4}/pyproject.toml +2 -1
  5. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/__init__.py +1 -1
  6. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/palace_results.py +7 -2
  7. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/setupEM.py +88 -16
  8. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/setupThermal.py +36 -6
  9. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/setup_common.py +591 -291
  10. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/stackupEditor.py +112 -14
  11. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/thermal_results.py +16 -0
  12. setupem-0.6.1/README_pypi.md → setupem-0.6.4/src/setupEM.egg-info/PKG-INFO +34 -1
  13. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM.egg-info/requires.txt +2 -1
  14. {setupem-0.6.1 → setupem-0.6.4}/LICENSE +0 -0
  15. {setupem-0.6.1 → setupem-0.6.4}/setup.cfg +0 -0
  16. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/__main__.py +0 -0
  17. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/data/SG13G2_100um.xml +0 -0
  18. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/data/SG13G2_200um.xml +0 -0
  19. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/data/SG13G2_200um_with_parameters.xml +0 -0
  20. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/data/SG13G2_nosub.xml +0 -0
  21. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/momentum_import.py +0 -0
  22. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/result_viewer.py +0 -0
  23. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM/stackup_writer.py +0 -0
  24. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM.egg-info/SOURCES.txt +0 -0
  25. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM.egg-info/dependency_links.txt +0 -0
  26. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM.egg-info/entry_points.txt +0 -0
  27. {setupem-0.6.1 → setupem-0.6.4}/src/setupEM.egg-info/top_level.txt +0 -0
@@ -1,14 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: setupEM
3
- Version: 0.6.1
3
+ Version: 0.6.4
4
4
  Summary: Python tool for configuration of gds2palace workflow with GUI.
5
5
  Author-email: Volker Muehlhaus <volker@muehlhaus.com>
6
6
  License-Expression: GPL-3.0-or-later
7
7
  Requires-Python: >=3.9
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
- Requires-Dist: gds2palace>=0.4.0
10
+ Requires-Dist: gds2palace>=0.4.3
11
11
  Requires-Dist: PySide6
12
+ Requires-Dist: shiboken6
12
13
  Requires-Dist: scipy
13
14
  Requires-Dist: requests
14
15
  Requires-Dist: scikit-rf
@@ -28,6 +29,7 @@ setupEM includes two built-in tools for working with simulation results directly
28
29
  - **Model Fit** (Create Model tab > Model Fit...) launches [snp2le](https://github.com/iic-jku/snp2le), an external open-source tool that extracts a lumped-element SPICE/Spectre netlist from S-parameter results - offering to install it via pip if it isn't already present. See section "[Model Fit](#model-fit)".
29
30
 
30
31
  - A graphical **Stackup XML Editor** (Tools > Edit Stackup XML...), including Variables, Reference-relative positioning, Derived Layers, and Thermal Tables
32
+ - The stackup preview graphics are **interactive**: click a shape for its properties, and selection syncs both ways with the Stackup Editor's tables
31
33
  - Input Files tab can now **override stackup Variables** (e.g. `total_thickness`) directly, without hand-editing the XML or the generated model
32
34
  - **setupThermal**, a companion app for Elmer thermal simulation, alongside setupEM
33
35
 
@@ -43,6 +45,11 @@ The setupEM package now includes setupThermal also, which is the equivalent of s
43
45
 
44
46
  An overview of the SetupEM user interface is given below in chapter "Using setupEM"
45
47
 
48
+ Two more external tools are used by parts of the workflow, and are not installed automatically:
49
+
50
+ - [ParaView](https://www.paraview.org/) — to view field-dump output (Palace/Elmer EM) and Elmer thermal result files via the "View fields/results in Paraview" buttons.
51
+ - An MPI implementation — only needed for multi-process Elmer runs (the Elmer solver settings' multithreading option). Use OpenMPI or MPICH on Linux/macOS; on Windows, install [Microsoft MPI](https://learn.microsoft.com/en-us/message-passing-interface/microsoft-mpi) (setupEM checks for this and shows a download link if it's missing).
52
+
46
53
 
47
54
  ## Installing the AWS Palace FEM solver engine
48
55
  **setupEM** creates and runs simulation models for the AWS Palace FEM solver engine. The underlying solver **AWS Palace** can be installed in multiple ways. For a smooth interaction with the gds2palace workflow, it is recommended to create some scripts that help running the model and convert the Palace results to SnP Touchstone files.
@@ -102,10 +109,14 @@ sudo apt install libxcb-cursor0 libxcb-xinerama0 libxcb-xkb1 libxcb-icccm4 libxc
102
109
  The setupEM module also installs these dependencies:
103
110
  - gds2palace
104
111
  - PySide6
112
+ - shiboken6
105
113
  - scipy
106
114
  - requests
107
115
  - scikit-rf
108
116
  - matplotlib
117
+ - numpy
118
+ - gdspy
119
+ - meshio
109
120
 
110
121
  ---
111
122
 
@@ -322,13 +333,15 @@ This project is licensed under the GNU General Public License v3.0 or later (GPL
322
333
 
323
334
  **Note:** the `setupEM` PyPI package itself requires:
324
335
 
325
- - gds2palace>=0.4.0
336
+ - gds2palace>=0.4.3
326
337
  - PySide6
338
+ - shiboken6
327
339
  - scipy
328
340
  - requests
329
341
  - scikit-rf
330
342
  - matplotlib
331
343
  - numpy
332
344
  - gdspy
345
+ - meshio
333
346
 
334
347
  (Other Python modules mentioned above are only needed to run standalone helper scripts in this repository, not to use the installed package.)
@@ -8,6 +8,7 @@ setupEM includes two built-in tools for working with simulation results directly
8
8
  - **Model Fit** (Create Model tab > Model Fit...) launches [snp2le](https://github.com/iic-jku/snp2le), an external open-source tool that extracts a lumped-element SPICE/Spectre netlist from S-parameter results - offering to install it via pip if it isn't already present. See section "[Model Fit](#model-fit)".
9
9
 
10
10
  - A graphical **Stackup XML Editor** (Tools > Edit Stackup XML...), including Variables, Reference-relative positioning, Derived Layers, and Thermal Tables
11
+ - The stackup preview graphics are **interactive**: click a shape for its properties, and selection syncs both ways with the Stackup Editor's tables
11
12
  - Input Files tab can now **override stackup Variables** (e.g. `total_thickness`) directly, without hand-editing the XML or the generated model
12
13
  - **setupThermal**, a companion app for Elmer thermal simulation, alongside setupEM
13
14
 
@@ -23,6 +24,11 @@ The setupEM package now includes setupThermal also, which is the equivalent of s
23
24
 
24
25
  An overview of the SetupEM user interface is given below in chapter "Using setupEM"
25
26
 
27
+ Two more external tools are used by parts of the workflow, and are not installed automatically:
28
+
29
+ - [ParaView](https://www.paraview.org/) — to view field-dump output (Palace/Elmer EM) and Elmer thermal result files via the "View fields/results in Paraview" buttons.
30
+ - An MPI implementation — only needed for multi-process Elmer runs (the Elmer solver settings' multithreading option). Use OpenMPI or MPICH on Linux/macOS; on Windows, install [Microsoft MPI](https://learn.microsoft.com/en-us/message-passing-interface/microsoft-mpi) (setupEM checks for this and shows a download link if it's missing).
31
+
26
32
 
27
33
  ## Installing the AWS Palace FEM solver engine
28
34
  **setupEM** creates and runs simulation models for the AWS Palace FEM solver engine. The underlying solver **AWS Palace** can be installed in multiple ways. For a smooth interaction with the gds2palace workflow, it is recommended to create some scripts that help running the model and convert the Palace results to SnP Touchstone files.
@@ -82,10 +88,14 @@ sudo apt install libxcb-cursor0 libxcb-xinerama0 libxcb-xkb1 libxcb-icccm4 libxc
82
88
  The setupEM module also installs these dependencies:
83
89
  - gds2palace
84
90
  - PySide6
91
+ - shiboken6
85
92
  - scipy
86
93
  - requests
87
94
  - scikit-rf
88
95
  - matplotlib
96
+ - numpy
97
+ - gdspy
98
+ - meshio
89
99
 
90
100
  ---
91
101
 
@@ -1,23 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: setupEM
3
- Version: 0.6.1
4
- Summary: Python tool for configuration of gds2palace workflow with GUI.
5
- Author-email: Volker Muehlhaus <volker@muehlhaus.com>
6
- License-Expression: GPL-3.0-or-later
7
- Requires-Python: >=3.9
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Requires-Dist: gds2palace>=0.4.0
11
- Requires-Dist: PySide6
12
- Requires-Dist: scipy
13
- Requires-Dist: requests
14
- Requires-Dist: scikit-rf
15
- Requires-Dist: matplotlib
16
- Requires-Dist: numpy
17
- Requires-Dist: gdspy
18
- Requires-Dist: meshio
19
- Dynamic: license-file
20
-
21
1
  # Python GUI for gds2palace
22
2
 
23
3
  ## What's New
@@ -28,6 +8,7 @@ setupEM includes two built-in tools for working with simulation results directly
28
8
  - **Model Fit** (Create Model tab > Model Fit...) launches [snp2le](https://github.com/iic-jku/snp2le), an external open-source tool that extracts a lumped-element SPICE/Spectre netlist from S-parameter results - offering to install it via pip if it isn't already present. See section "[Model Fit](#model-fit)".
29
9
 
30
10
  - A graphical **Stackup XML Editor** (Tools > Edit Stackup XML...), including Variables, Reference-relative positioning, Derived Layers, and Thermal Tables
11
+ - The stackup preview graphics are **interactive**: click a shape for its properties, and selection syncs both ways with the Stackup Editor's tables
31
12
  - Input Files tab can now **override stackup Variables** (e.g. `total_thickness`) directly, without hand-editing the XML or the generated model
32
13
  - **setupThermal**, a companion app for Elmer thermal simulation, alongside setupEM
33
14
 
@@ -43,6 +24,11 @@ The setupEM package now includes setupThermal also, which is the equivalent of s
43
24
 
44
25
  An overview of the SetupEM user interface is given below in chapter "Using setupEM"
45
26
 
27
+ Two more external tools are used by parts of the workflow, and are not installed automatically:
28
+
29
+ - [ParaView](https://www.paraview.org/) — to view field-dump output (Palace/Elmer EM) and Elmer thermal result files via the "View fields/results in Paraview" buttons.
30
+ - An MPI implementation — only needed for multi-process Elmer runs (the Elmer solver settings' multithreading option). Use OpenMPI or MPICH on Linux/macOS; on Windows, install [Microsoft MPI](https://learn.microsoft.com/en-us/message-passing-interface/microsoft-mpi) (setupEM checks for this and shows a download link if it's missing).
31
+
46
32
 
47
33
  ## Installing the AWS Palace FEM solver engine
48
34
  **setupEM** creates and runs simulation models for the AWS Palace FEM solver engine. The underlying solver **AWS Palace** can be installed in multiple ways. For a smooth interaction with the gds2palace workflow, it is recommended to create some scripts that help running the model and convert the Palace results to SnP Touchstone files.
@@ -102,10 +88,14 @@ sudo apt install libxcb-cursor0 libxcb-xinerama0 libxcb-xkb1 libxcb-icccm4 libxc
102
88
  The setupEM module also installs these dependencies:
103
89
  - gds2palace
104
90
  - PySide6
91
+ - shiboken6
105
92
  - scipy
106
93
  - requests
107
94
  - scikit-rf
108
95
  - matplotlib
96
+ - numpy
97
+ - gdspy
98
+ - meshio
109
99
 
110
100
  ---
111
101
 
@@ -322,13 +312,15 @@ This project is licensed under the GNU General Public License v3.0 or later (GPL
322
312
 
323
313
  **Note:** the `setupEM` PyPI package itself requires:
324
314
 
325
- - gds2palace>=0.4.0
315
+ - gds2palace>=0.4.3
326
316
  - PySide6
317
+ - shiboken6
327
318
  - scipy
328
319
  - requests
329
320
  - scikit-rf
330
321
  - matplotlib
331
322
  - numpy
332
323
  - gdspy
324
+ - meshio
333
325
 
334
326
  (Other Python modules mentioned above are only needed to run standalone helper scripts in this repository, not to use the installed package.)
@@ -12,8 +12,9 @@ authors = [
12
12
  { name = "Volker Muehlhaus", email = "volker@muehlhaus.com" }
13
13
  ]
14
14
  dependencies = [
15
- "gds2palace>=0.4.0",
15
+ "gds2palace>=0.4.3",
16
16
  "PySide6",
17
+ "shiboken6",
17
18
  "scipy",
18
19
  "requests",
19
20
  "scikit-rf",
@@ -24,4 +24,4 @@ A Python tool for EM setup using gds2palace.
24
24
  from .setupEM import main
25
25
 
26
26
  __all__ = ["main"]
27
- __version__ = "0.6.1"
27
+ __version__ = "0.6.4"
@@ -53,8 +53,10 @@ def find_paraview_files(run_path, model_basename):
53
53
  recursively. Palace's own field-dump feature (triggered by fdump/SaveStep) writes
54
54
  its category/excitation folder structure without gds2palace's control - confirmed
55
55
  (on two Palace versions) to only keep the last-solved excitation's Cycle files, so
56
- no fixed filename or count can be assumed here. Falls back to loose .vtu if no .pvd
57
- exists yet. Empty list if the output directory doesn't exist / has nothing yet.
56
+ no fixed filename or count can be assumed here. Prefers .pvd, then falls back to
57
+ .pvtu (the multi-partition index - ties per-partition pieces back into one dataset),
58
+ then loose .vtu if neither exists yet. Empty list if the output directory doesn't
59
+ exist / has nothing yet.
58
60
  """
59
61
  output_dir = find_output_dir(run_path, model_basename)
60
62
  if not os.path.isdir(output_dir):
@@ -62,6 +64,9 @@ def find_paraview_files(run_path, model_basename):
62
64
  pvd_files = sorted(glob.glob(os.path.join(output_dir, '**', '*.pvd'), recursive=True))
63
65
  if pvd_files:
64
66
  return pvd_files
67
+ pvtu_files = sorted(glob.glob(os.path.join(output_dir, '**', '*.pvtu'), recursive=True))
68
+ if pvtu_files:
69
+ return pvtu_files
65
70
  return sorted(glob.glob(os.path.join(output_dir, '**', '*.vtu'), recursive=True))
66
71
 
67
72
 
@@ -165,10 +165,21 @@ class FrequenciesTab(QWidget):
165
165
  self.dump_layout = QHBoxLayout()
166
166
 
167
167
  self.fdump_layout = QVBoxLayout()
168
- self.fdump_layout.addWidget(QLabel("fdump [GHz], values separated by comma"))
168
+ self.fdump_label = QLabel("fdump [GHz], values separated by comma")
169
+ self.fdump_layout.addWidget(self.fdump_label)
169
170
  self.fdump_edit = QLineEdit("")
170
171
  self.fdump_edit.setStyleSheet(EDIT_STYLE_OPTIONAL)
171
172
  self.fdump_layout.addWidget(self.fdump_edit)
173
+
174
+ # Elmer has no per-sample SaveStep like Palace - any fdump value turns on
175
+ # field-dump output at every solved frequency (sweep + fpoint together), so a
176
+ # per-frequency list is misleading there. Elmer mode shows this checkbox instead
177
+ # of fdump_edit; only one of the two is ever visible, toggled in setPalaceMode()/
178
+ # setElmerMode(). Both widgets always exist so mode switches are just a visibility
179
+ # flip, no rebuilding.
180
+ self.fdump_enabled_checkbox = QCheckBox("Enable field dump at all frequencies")
181
+ self.fdump_layout.addWidget(self.fdump_enabled_checkbox)
182
+
172
183
  self.dump_layout.addLayout(self.fdump_layout)
173
184
  self.dump_group.setLayout(self.dump_layout)
174
185
 
@@ -184,7 +195,9 @@ class FrequenciesTab(QWidget):
184
195
  def save_values(self):
185
196
  # fstart/fstop may be left empty only if fpoint or fdump supplies at least
186
197
  # one frequency instead (gds2palace treats fstart/fstop as fully optional)
187
- discrete_freqs_given = (self.fpoint_edit.text() != "" or self.fdump_edit.text() != "")
198
+ fdump_given = (self.fdump_enabled_checkbox.isChecked() if self.MainWindow.ElmerMode
199
+ else self.fdump_edit.text() != "")
200
+ discrete_freqs_given = (self.fpoint_edit.text() != "" or fdump_given)
188
201
 
189
202
  fstart = None
190
203
  if self.start_edit.text() == "":
@@ -239,18 +252,35 @@ class FrequenciesTab(QWidget):
239
252
  else:
240
253
  saved_values.pop("fpoint",None) # delete key
241
254
 
242
- text = self.fdump_edit.text()
243
- if text != "":
244
- saved_values ["fdump"] = ast.literal_eval('['+text+']')
255
+ if self.MainWindow.ElmerMode:
256
+ saved_values["fdump_enabled"] = self.fdump_enabled_checkbox.isChecked()
257
+ # don't touch saved_values["fdump"] here - it's Palace-only data (a real
258
+ # frequency list) and must survive a round-trip through Elmer mode untouched
259
+ have_sweep = ("fstart" in saved_values and "fstop" in saved_values)
260
+ have_fpoint = bool(saved_values.get("fpoint"))
261
+ if self.fdump_enabled_checkbox.isChecked() and not have_sweep and not have_fpoint:
262
+ QMessageBox.warning(self, "Error",
263
+ "Field dump needs at least one frequency: set fstart/fstop or fpoint first.")
264
+ self.fdump_enabled_checkbox.setChecked(False)
265
+ saved_values["fdump_enabled"] = False
266
+ return False
245
267
  else:
246
- saved_values.pop("fdump",None)
268
+ text = self.fdump_edit.text()
269
+ if text != "":
270
+ saved_values ["fdump"] = ast.literal_eval('['+text+']')
271
+ else:
272
+ saved_values.pop("fdump",None)
273
+ # don't touch saved_values["fdump_enabled"] here either, same reasoning
247
274
  # "View fields in Paraview" is only relevant once fdump is set
248
275
  self.MainWindow.create_model_tab._update_paraview_button_visibility()
249
276
 
250
277
  # if fstart == fstop == fdump or fstart == fstop == fstep, then remove fstart, fstop
251
278
  if fstart is not None and fstop is not None and fstart == fstop:
252
279
  discrete_list1 = saved_values.get("fpoint", [])
253
- discrete_list2 = saved_values.get("fdump", [])
280
+ # fdump no longer holds real per-frequency data in Elmer mode, and collapsing
281
+ # the sweep away here would remove the very fstop value the field-dump
282
+ # checkbox's generated code depends on (see ModelEditorTab.create_model_text)
283
+ discrete_list2 = [] if self.MainWindow.ElmerMode else saved_values.get("fdump", [])
254
284
  if fstart in discrete_list1 or fstart in discrete_list2:
255
285
  saved_values.pop("fstart", None)
256
286
  saved_values.pop("fstop", None)
@@ -265,7 +295,9 @@ class FrequenciesTab(QWidget):
265
295
  def load_values(self):
266
296
  # if fstart/fstop were intentionally omitted in favor of fpoint/fdump, keep the
267
297
  # fields blank on reload instead of repopulating the "0"/"50" sweep defaults
268
- discrete_freqs_given = ("fpoint" in saved_values) or ("fdump" in saved_values)
298
+ fdump_given = saved_values.get("fdump_enabled", False) if self.MainWindow.ElmerMode \
299
+ else ("fdump" in saved_values)
300
+ discrete_freqs_given = ("fpoint" in saved_values) or fdump_given
269
301
  fstart_default = "" if discrete_freqs_given else "0"
270
302
  fstop_default = "" if discrete_freqs_given else "50"
271
303
  self.start_edit.setText(str(saved_values.get("fstart",fstart_default)))
@@ -277,6 +309,7 @@ class FrequenciesTab(QWidget):
277
309
 
278
310
  float_list = saved_values.get("fdump","")
279
311
  self.fdump_edit.setText(','.join(map(str, float_list)))
312
+ self.fdump_enabled_checkbox.setChecked(bool(saved_values.get("fdump_enabled", False)))
280
313
 
281
314
 
282
315
  class PortsTab(QWidget):
@@ -1386,7 +1419,11 @@ class CreateModelTab(CreateModelTabBase):
1386
1419
  self.log_area.appendPlainText("\n" + summary + "\n")
1387
1420
 
1388
1421
  def _update_paraview_button_visibility(self):
1389
- self.paraview_btn.setVisible(bool(saved_values.get('fdump')))
1422
+ if self.MainWindow.ElmerMode:
1423
+ visible = bool(saved_values.get('fdump_enabled'))
1424
+ else:
1425
+ visible = bool(saved_values.get('fdump'))
1426
+ self.paraview_btn.setVisible(visible)
1390
1427
 
1391
1428
  def load_values(self):
1392
1429
  super().load_values()
@@ -1409,7 +1446,7 @@ class CreateModelTab(CreateModelTabBase):
1409
1446
  # found for thermal_results.vtu). Check run_path too, defensively.
1410
1447
  search_dirs = [os.path.join(run_path, "mesh"), run_path]
1411
1448
  file_paths = []
1412
- for pattern in ("fields*.pvd", "fields*.vtu"):
1449
+ for pattern in ("fields*.pvd", "fields*.pvtu", "fields*.vtu"):
1413
1450
  for d in search_dirs:
1414
1451
  file_paths = sorted(glob.glob(os.path.join(d, pattern)))
1415
1452
  if file_paths:
@@ -1418,7 +1455,7 @@ class CreateModelTab(CreateModelTabBase):
1418
1455
  break
1419
1456
  not_found = (
1420
1457
  f"⚠️ No Elmer field-dump output found under {run_path}\n"
1421
- "(set fdump to specific frequencies before running the simulation)\n"
1458
+ "(enable field dump before running the simulation)\n"
1422
1459
  )
1423
1460
  self._open_in_paraview(file_paths, not_found)
1424
1461
 
@@ -1731,13 +1768,22 @@ class ModelEditorTab(QWidget):
1731
1768
  special_keylist = ['simulation_ports','materials_list','dielectrics_list','metals_list',
1732
1769
  'layernumbers','allpolygons']
1733
1770
  # List of keys that we don't write to Python model code editor
1734
- ignore_list = ['model_basename','sim_path']
1771
+ # fdump_enabled is a GUI-only toggle (Elmer mode), never a real gds2palace setting
1772
+ ignore_list = ['model_basename','sim_path','fdump_enabled']
1735
1773
 
1736
1774
 
1737
1775
  # Keywords that are excluded in Palace mode
1738
1776
  if self.MainWindow.PalaceMode:
1739
1777
  ignore_list.append('iterative')
1740
1778
 
1779
+ if self.MainWindow.ElmerMode:
1780
+ # Elmer mode shows a plain on/off checkbox (fdump_enabled) instead of Palace's
1781
+ # per-frequency fdump list - suppress the generic per-key emission of fdump
1782
+ # here so a stale Palace-mode list saved earlier in the same session doesn't
1783
+ # leak into an Elmer-mode script; the synthesized settings['fdump'] line
1784
+ # (below, after special_keylist) is emitted instead when the checkbox is on.
1785
+ ignore_list.append('fdump')
1786
+
1741
1787
  if forExport:
1742
1788
  # these commands are only used within this GUI application to control gmsh
1743
1789
  ignore_list.extend(['preview_only','no_preview'])
@@ -1747,6 +1793,23 @@ class ModelEditorTab(QWidget):
1747
1793
  if not key in ignore_list:
1748
1794
  add_key(key)
1749
1795
 
1796
+ if self.MainWindow.ElmerMode and bool(saved_values.get('fdump_enabled')):
1797
+ # Elmer has no per-frequency SaveStep like Palace - it dumps fields at every
1798
+ # solved frequency once any fdump value is set, so reuse an already-solved
1799
+ # frequency here rather than asking the user to pick one. This is harmless
1800
+ # (adds no extra solve) as long as util_elmer.write_elmer_frequencies()
1801
+ # dedupes the combined frequency list, which it does.
1802
+ # Known limitation: this line's RHS references "settings", so
1803
+ # parse_assignments() (setup_common.py) skips it entirely on Import -
1804
+ # re-importing an exported Elmer+fdump script loses fdump_enabled (loads
1805
+ # unchecked). Not fixed here since it's a silent no-op, not a crash.
1806
+ add_text("\n# 'Enable field dump' checkbox: Elmer dumps fields at every solved")
1807
+ add_text("# frequency once fdump is non-empty, so reuse an already-solved one")
1808
+ if 'fstop' in saved_values:
1809
+ add_text("settings['fdump'] = [settings['fstop']]")
1810
+ elif saved_values.get('fpoint'):
1811
+ add_text("settings['fdump'] = [settings['fpoint'][0]]")
1812
+
1750
1813
 
1751
1814
  add_text("\n# ===================== port definitions =======================")
1752
1815
  add_text("simulation_ports = simulation_setup.all_simulation_ports()")
@@ -1951,6 +2014,10 @@ class MainWindow(MainWindowBase):
1951
2014
  self.ElmerMode = False
1952
2015
  self.setWindowTitle(APP_NAME + ' Palace')
1953
2016
  self.frequencies_tab.dump_group.setVisible(True)
2017
+ self.frequencies_tab.dump_group.setTitle("Optional list of fixed frequencies creating field dump data for visualization (Paraview files))")
2018
+ self.frequencies_tab.fdump_label.setVisible(True)
2019
+ self.frequencies_tab.fdump_edit.setVisible(True)
2020
+ self.frequencies_tab.fdump_enabled_checkbox.setVisible(False)
1954
2021
  self.mesh_tab.AMR_group.setVisible(True)
1955
2022
  self.mesh_tab.Elmer_group.setVisible(False)
1956
2023
 
@@ -1963,9 +2030,14 @@ class MainWindow(MainWindowBase):
1963
2030
  self.PalaceMode = False
1964
2031
  self.ElmerMode = True
1965
2032
  self.setWindowTitle(APP_NAME + ' Elmer')
1966
- # fdump now also enables Elmer EM field dumps (Exec Solver = Always), not just
1967
- # Palace's SaveStep - so this group must stay visible/usable in Elmer mode too.
2033
+ # Elmer has no per-sample SaveStep like Palace - any fdump value turns on
2034
+ # field-dump output at every solved frequency, so it shows a plain on/off
2035
+ # checkbox here instead of Palace's per-frequency fdump list.
1968
2036
  self.frequencies_tab.dump_group.setVisible(True)
2037
+ self.frequencies_tab.dump_group.setTitle("Create field dump data for visualization (Paraview files)")
2038
+ self.frequencies_tab.fdump_label.setVisible(False)
2039
+ self.frequencies_tab.fdump_edit.setVisible(False)
2040
+ self.frequencies_tab.fdump_enabled_checkbox.setVisible(True)
1969
2041
  self.mesh_tab.AMR_group.setVisible(False)
1970
2042
  self.mesh_tab.Elmer_group.setVisible(True)
1971
2043
 
@@ -1995,8 +2067,8 @@ class MainWindow(MainWindowBase):
1995
2067
 
1996
2068
 
1997
2069
  def show_version(self):
1998
- setupEM_version = importlib.metadata.version("setupEM")
1999
- gds2palace_version = importlib.metadata.version("gds2palace")
2070
+ setupEM_version = self.get_setupEM_version()
2071
+ gds2palace_version = self.get_gds2palace_version()
2000
2072
  # snp2le (used by Model Fit) is an optional dependency, not installed by default
2001
2073
  try:
2002
2074
  snp2le_version = importlib.metadata.version("snp2le")
@@ -53,14 +53,14 @@ if __package__ in (None, ""):
53
53
  FileDropLineEdit, FileInputTab, PythonHighlighter, CodeEditor,
54
54
  VectorWidget, PopUpWindow, CreateModelTabBase, MainWindowBase,
55
55
  )
56
- from thermal_results import build_thermal_summary, format_source_table, find_thermal_vtu
56
+ from thermal_results import build_thermal_summary, format_source_table, find_thermal_paraview_file
57
57
  else:
58
58
  from .setup_common import (
59
59
  EDIT_STYLE_OPTIONAL, EDIT_STYLE_REQUIRED, COMBO_STYLE_REQUIRED, COMBO_STYLE_OPTIONAL,
60
60
  FileDropLineEdit, FileInputTab, PythonHighlighter, CodeEditor,
61
61
  VectorWidget, PopUpWindow, CreateModelTabBase, MainWindowBase,
62
62
  )
63
- from .thermal_results import build_thermal_summary, format_source_table, find_thermal_vtu
63
+ from .thermal_results import build_thermal_summary, format_source_table, find_thermal_paraview_file
64
64
 
65
65
 
66
66
  '''
@@ -501,6 +501,28 @@ class MeshTab(QWidget):
501
501
  self.main_layout.addWidget(self.mesh_group)
502
502
 
503
503
 
504
+ # ---------- ELMER SOLVER GROUP ----------
505
+ self.Elmer_group = QGroupBox("Elmer solver settings")
506
+ self.Elmer_layout = QVBoxLayout()
507
+
508
+ self.solver_layout = QHBoxLayout()
509
+ self.solverlabel = QLabel("Solver")
510
+ self.solverlabel.setFixedWidth(label_width)
511
+ self.solver_layout.addWidget(self.solverlabel)
512
+
513
+ self.solver_box = QComboBox()
514
+ self.solver_box.setFixedWidth(edit_width)
515
+ self.solver_box.setStyleSheet(COMBO_STYLE_OPTIONAL)
516
+ self.solver_box.addItems(["iterative","direct"])
517
+ self.solver_layout.addWidget(self.solver_box)
518
+ self.solver_box.setCurrentIndex(1)
519
+ self.solver_layout.addStretch()
520
+ self.Elmer_layout.addLayout(self.solver_layout)
521
+
522
+ self.Elmer_group.setLayout(self.Elmer_layout)
523
+ self.main_layout.addWidget(self.Elmer_group)
524
+
525
+
504
526
  # ---------- BOUNDARY GROUP ----------
505
527
  self.mesh_group = QGroupBox("Boundary settings")
506
528
  self.mesh_layout = QVBoxLayout()
@@ -551,6 +573,9 @@ class MeshTab(QWidget):
551
573
  return False
552
574
  saved_values ["margin"] = float(value)
553
575
 
576
+ # iterative or direct solver for Elmer
577
+ saved_values["iterative"] = "iterative" in self.solver_box.currentText()
578
+
554
579
  # all saved
555
580
  return True
556
581
 
@@ -560,6 +585,11 @@ class MeshTab(QWidget):
560
585
  self.cells_maxsize_edit.setText(str(saved_values.get("meshsize_max","100")))
561
586
  self.margins_edit.setText(str(saved_values.get("margin","100")))
562
587
 
588
+ if saved_values.get("iterative", False):
589
+ self.solver_box.setCurrentIndex(0)
590
+ else:
591
+ self.solver_box.setCurrentIndex(1)
592
+
563
593
 
564
594
 
565
595
  class CreateModelTab(CreateModelTabBase):
@@ -615,7 +645,7 @@ class CreateModelTab(CreateModelTabBase):
615
645
 
616
646
  def launch_paraview(self):
617
647
  run_path = saved_values['sim_path'] + "/elmer_model/" + saved_values['model_basename'] + "_data"
618
- vtu_path = find_thermal_vtu(run_path)
648
+ vtu_path = find_thermal_paraview_file(run_path)
619
649
  self._open_in_paraview(
620
650
  [vtu_path] if vtu_path else [],
621
651
  f"⚠️ No thermal results .vtu found yet under {run_path}\n"
@@ -786,7 +816,7 @@ class ModelEditorTab(QWidget):
786
816
  special_keylist = ['thermal_objects','materials_list','dielectrics_list','metals_list',
787
817
  'layernumbers','allpolygons']
788
818
  # List of keys that we don't write to Python model code editor
789
- ignore_list = ['model_basename','sim_path','iterative']
819
+ ignore_list = ['model_basename','sim_path']
790
820
 
791
821
 
792
822
  if forExport:
@@ -935,8 +965,8 @@ class MainWindow(MainWindowBase):
935
965
  # ---------- Menu actions ----------
936
966
 
937
967
  def show_version(self):
938
- setupEM_version = importlib.metadata.version("setupEM")
939
- gds2palace_version = importlib.metadata.version("gds2palace")
968
+ setupEM_version = self.get_setupEM_version()
969
+ gds2palace_version = self.get_gds2palace_version()
940
970
  version_info = f"Installed:\nsetupEM {setupEM_version}\ngds2palace {gds2palace_version}"
941
971
 
942
972
  # get latest available version information