emerge 0.6.9__tar.gz → 0.6.10__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.

Potentially problematic release.


This version of emerge might be problematic. Click here for more details.

Files changed (110) hide show
  1. {emerge-0.6.9 → emerge-0.6.10}/.bumpversion.toml +1 -1
  2. {emerge-0.6.9 → emerge-0.6.10}/PKG-INFO +1 -1
  3. {emerge-0.6.9 → emerge-0.6.10}/emerge/__init__.py +12 -3
  4. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/cs.py +36 -0
  5. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/polybased.py +58 -26
  6. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/shapes.py +6 -0
  7. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geometry.py +12 -3
  8. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/logsettings.py +13 -2
  9. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/material.py +10 -1
  10. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/mesh3d.py +15 -4
  11. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/microwave_3d.py +1 -1
  12. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/microwave_bc.py +17 -19
  13. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot/pyvista/display.py +1 -1
  14. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot/simple_plots.py +15 -3
  15. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/simmodel.py +6 -5
  16. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/solve_interfaces/cudss_interface.py +10 -4
  17. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/solver.py +14 -4
  18. {emerge-0.6.9 → emerge-0.6.10}/examples/demo10_sgh.py +1 -1
  19. {emerge-0.6.9 → emerge-0.6.10}/examples/demo11_lumped_element_filter.py +1 -1
  20. {emerge-0.6.9 → emerge-0.6.10}/examples/demo12_mode_alignment.py +1 -1
  21. {emerge-0.6.9 → emerge-0.6.10}/examples/demo13_helix_antenna.py +2 -2
  22. {emerge-0.6.9 → emerge-0.6.10}/examples/demo14_boundary_selection.py +1 -1
  23. {emerge-0.6.9 → emerge-0.6.10}/examples/demo1_stepped_imp_filter.py +1 -1
  24. {emerge-0.6.9 → emerge-0.6.10}/examples/demo2_combline_filter.py +1 -1
  25. {emerge-0.6.9 → emerge-0.6.10}/examples/demo3_coupled_line_filter.py +1 -1
  26. {emerge-0.6.9 → emerge-0.6.10}/examples/demo4_patch_antenna.py +1 -1
  27. emerge-0.6.10/examples/demo5_revolve.py +15 -0
  28. {emerge-0.6.9 → emerge-0.6.10}/examples/demo6_striplines_with_vias.py +1 -1
  29. {emerge-0.6.9 → emerge-0.6.10}/examples/demo7_periodic_cells.py +1 -1
  30. {emerge-0.6.9 → emerge-0.6.10}/examples/demo8_waveguide_bpf_synthesis.py +1 -1
  31. {emerge-0.6.9 → emerge-0.6.10}/examples/demo9_dielectric_resonator.py +2 -2
  32. {emerge-0.6.9 → emerge-0.6.10}/pyproject.toml +1 -1
  33. {emerge-0.6.9 → emerge-0.6.10}/uv.lock +1 -1
  34. emerge-0.6.9/examples/demo5_revolve.py +0 -25
  35. {emerge-0.6.9 → emerge-0.6.10}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  36. {emerge-0.6.9 → emerge-0.6.10}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  37. {emerge-0.6.9 → emerge-0.6.10}/.gitignore +0 -0
  38. {emerge-0.6.9 → emerge-0.6.10}/.opt +0 -0
  39. {emerge-0.6.9 → emerge-0.6.10}/.python-version +0 -0
  40. {emerge-0.6.9 → emerge-0.6.10}/LICENSE +0 -0
  41. {emerge-0.6.9 → emerge-0.6.10}/README.md +0 -0
  42. {emerge-0.6.9 → emerge-0.6.10}/THIRD_PARTY_LICENSES.md +0 -0
  43. {emerge-0.6.9 → emerge-0.6.10}/UMFPACK_Install_windows.md +0 -0
  44. {emerge-0.6.9 → emerge-0.6.10}/UMFPACK_installer_windows.py +0 -0
  45. {emerge-0.6.9 → emerge-0.6.10}/emerge/__main__.py +0 -0
  46. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/__init__.py +0 -0
  47. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/_cache_check.py +0 -0
  48. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/bc.py +0 -0
  49. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/const.py +0 -0
  50. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/coord.py +0 -0
  51. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/dataset.py +0 -0
  52. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/elements/__init__.py +0 -0
  53. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/elements/femdata.py +0 -0
  54. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/elements/index_interp.py +0 -0
  55. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/elements/ned2_interp.py +0 -0
  56. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/elements/nedelec2.py +0 -0
  57. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/elements/nedleg2.py +0 -0
  58. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/__init__.py +0 -0
  59. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/horn.py +0 -0
  60. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/modeler.py +0 -0
  61. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/operations.py +0 -0
  62. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/pcb.py +0 -0
  63. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/pcb_tools/calculator.py +0 -0
  64. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/pcb_tools/macro.py +0 -0
  65. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/pmlbox.py +0 -0
  66. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo/step.py +0 -0
  67. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/geo2d.py +0 -0
  68. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/howto.py +0 -0
  69. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/mesher.py +0 -0
  70. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/mth/common_functions.py +0 -0
  71. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/mth/integrals.py +0 -0
  72. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/mth/optimized.py +0 -0
  73. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/mth/pairing.py +0 -0
  74. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/periodic.py +0 -0
  75. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/__init__.py +0 -0
  76. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/__init__.py +0 -0
  77. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/adaptive_freq.py +0 -0
  78. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/assembly/assembler.py +0 -0
  79. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/assembly/curlcurl.py +0 -0
  80. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +0 -0
  81. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/assembly/generalized_eigen_hb.py +0 -0
  82. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/assembly/periodicbc.py +0 -0
  83. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/assembly/robinbc.py +0 -0
  84. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/microwave_data.py +0 -0
  85. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/periodic.py +0 -0
  86. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/port_functions.py +0 -0
  87. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/sc.py +0 -0
  88. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/simjob.py +0 -0
  89. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/sparam.py +0 -0
  90. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/physics/microwave/touchstone.py +0 -0
  91. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot/__init__.py +0 -0
  92. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot/display.py +0 -0
  93. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot/matplotlib/mpldisplay.py +0 -0
  94. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot/pyvista/__init__.py +0 -0
  95. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot/pyvista/display_settings.py +0 -0
  96. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/plot.py +0 -0
  97. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/projects/__init__.py +0 -0
  98. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/projects/_gen_base.txt +0 -0
  99. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/projects/_load_base.txt +0 -0
  100. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/projects/generate_project.py +0 -0
  101. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/selection.py +0 -0
  102. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/simulation_data.py +0 -0
  103. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/solve_interfaces/pardiso_interface.py +0 -0
  104. {emerge-0.6.9 → emerge-0.6.10}/emerge/_emerge/system.py +0 -0
  105. {emerge-0.6.9 → emerge-0.6.10}/emerge/cli.py +0 -0
  106. {emerge-0.6.9 → emerge-0.6.10}/emerge/ext.py +0 -0
  107. {emerge-0.6.9 → emerge-0.6.10}/emerge/lib.py +0 -0
  108. {emerge-0.6.9 → emerge-0.6.10}/emerge/plot.py +0 -0
  109. {emerge-0.6.9 → emerge-0.6.10}/emerge/pyvista.py +0 -0
  110. {emerge-0.6.9 → emerge-0.6.10}/src/__init__.py +0 -0
@@ -1,5 +1,5 @@
1
1
  [tool.bumpversion]
2
- current_version = "0.6.9"
2
+ current_version = "0.6.10"
3
3
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
4
4
  serialize = ["{major}.{minor}.{patch}"]
5
5
  search = "{current_version}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emerge
3
- Version: 0.6.9
3
+ Version: 0.6.10
4
4
  Summary: An open source EM FEM simulator in Python
5
5
  Project-URL: Homepage, https://github.com/FennisRobert/EMerge
6
6
  Project-URL: Issues, https://github.com/FennisRobert/EMerge/issues
@@ -18,7 +18,7 @@ along with this program; if not, see
18
18
  """
19
19
  import os
20
20
 
21
- __version__ = "0.6.9"
21
+ __version__ = "0.6.10"
22
22
 
23
23
  ############################################################
24
24
  # HANDLE ENVIRONMENT VARIABLES #
@@ -43,12 +43,13 @@ from loguru import logger
43
43
 
44
44
  LOG_CONTROLLER.set_default()
45
45
  logger.debug('Importing modules')
46
+ LOG_CONTROLLER._set_log_buffer()
46
47
 
47
48
  from ._emerge.simmodel import Simulation
48
49
  from ._emerge.material import Material, FreqCoordDependent, FreqDependent, CoordDependent
49
50
  from ._emerge import bc
50
51
  from ._emerge.solver import SolverBicgstab, SolverGMRES, SolveRoutine, ReverseCuthillMckee, Sorter, SolverPardiso, SolverUMFPACK, SolverSuperLU, EMSolver
51
- from ._emerge.cs import CoordinateSystem, CS, GCS, Plane, Axis, XAX, YAX, ZAX, XYPLANE, XZPLANE, YZPLANE, YXPLANE, ZXPLANE, ZYPLANE
52
+ from ._emerge.cs import CoordinateSystem, CS, GCS, Plane, Axis, XAX, YAX, ZAX, XYPLANE, XZPLANE, YZPLANE, YXPLANE, ZXPLANE, ZYPLANE, cs
52
53
  from ._emerge.coord import Line
53
54
  from ._emerge import geo
54
55
  from ._emerge.selection import Selection, FaceSelection, DomainSelection, EdgeSelection
@@ -62,4 +63,12 @@ from ._emerge.howto import _HowtoClass
62
63
 
63
64
  howto = _HowtoClass()
64
65
 
65
- logger.debug('Importing complete!')
66
+ logger.debug('Importing complete!')
67
+
68
+
69
+ ############################################################
70
+ # CONSTANTS #
71
+ ############################################################
72
+
73
+ CENTER = geo.Alignment.CENTER
74
+ CORNER = geo.Alignment.CORNER
@@ -530,3 +530,39 @@ CS = CoordinateSystem
530
530
  # The global coordinate system
531
531
  GCS = CoordinateSystem(XAX, YAX, ZAX, np.zeros(3), _is_global=True)
532
532
 
533
+ def cs(axes: str, origin: tuple[float, float, float] = (0.,0.,0.,)) -> CoordinateSystem:
534
+ """Generate a coordinate system based on a simple string
535
+ The string must contain the letters x, X, y, Y, z and/or Z.
536
+ Small letters refer to positive axes and capitals to negative axes.
537
+
538
+ The string must be 3 characters long.
539
+
540
+ The first position indices which global axis gets assigned to the new local X-axis
541
+ The second position indicates the Y-axis
542
+ The third position indicates the Z-axis
543
+
544
+ Thus, rotating the global XYZ coordinate system 90 degrees around the Z axis would yield: yXz
545
+
546
+ Args:
547
+ axes (str): The axis description
548
+ origin (tuple[float, float, float], optional): The origin of the coordinate system. Defaults to (0.,0.,0.,).
549
+
550
+ Returns:
551
+ CoordinateSystem: The resultant coordinate system
552
+ """
553
+ if len(axes) != 3:
554
+ raise ValueError('Axis object must be of length 3')
555
+
556
+ axlib = {
557
+ 'x': Axis(np.array([1.0,0.,0.])),
558
+ 'X': Axis(np.array([-1.0,0.,0.])),
559
+ 'y': Axis(np.array([0.,1.0,0.])),
560
+ 'Y': Axis(np.array([0.,-1.0,0.])),
561
+ 'z': Axis(np.array([0.,0.,1.0])),
562
+ 'Z': Axis(np.array([0.,0.,-1.0])),
563
+ }
564
+ ax_obj = [axlib[ax] for ax in axes]
565
+
566
+ return (ax_obj[0]*ax_obj[1]*ax_obj[2]).displace(*origin)
567
+
568
+
@@ -206,6 +206,7 @@ def orthonormalize(axis: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray
206
206
  Zaxis = np.abs(Zaxis/np.linalg.norm(Zaxis))
207
207
  return Xaxis, Yaxis, Zaxis
208
208
 
209
+
209
210
  class GeoPrism(GeoVolume):
210
211
  """The GepPrism class generalizes the GeoVolume for extruded convex polygons.
211
212
  Besides having a volumetric definitions, the class offers a .front_face
@@ -216,35 +217,65 @@ class GeoPrism(GeoVolume):
216
217
  """
217
218
  def __init__(self,
218
219
  volume_tag: int,
219
- front_tag: int,
220
- side_tags: list[int],):
220
+ front_tag: int | None = None,
221
+ side_tags: list[int] | None = None,
222
+ _axis: Axis | None = None):
221
223
  super().__init__(volume_tag)
222
- self.front_tag: int = front_tag
223
- self.back_tag: int = None
224
+
225
+
226
+
227
+ if front_tag is not None and side_tags is not None:
228
+ self.front_tag: int = front_tag
229
+ self.back_tag: int = None
224
230
 
225
- gmsh.model.occ.synchronize()
226
- o1 = gmsh.model.occ.get_center_of_mass(2, self.front_tag)
227
- n1 = gmsh.model.get_normal(self.front_tag, (0,0))
228
- self._add_face_pointer('back', o1, n1)
231
+ gmsh.model.occ.synchronize()
232
+ self._add_face_pointer('back', tag=self.front_tag)
229
233
 
230
- tags = gmsh.model.get_boundary(self.dimtags, oriented=False)
231
-
232
- for dim, tag in tags:
233
- if (dim,tag) in side_tags:
234
- continue
235
- o2 = gmsh.model.occ.get_center_of_mass(2, tag)
236
- n2 = gmsh.model.get_normal(tag, (0,0))
237
- self._add_face_pointer('front', o2, n2)
238
- self.back_tag = tag
239
- break
234
+ tags = gmsh.model.get_boundary(self.dimtags, oriented=False)
235
+
236
+ for dim, tag in tags:
237
+ if (dim,tag) in side_tags:
238
+ continue
239
+ self._add_face_pointer('front',tag=tag)
240
+ self.back_tag = tag
241
+ break
240
242
 
241
- self.side_tags: list[int] = [dt[1] for dt in tags if dt[1]!=self.front_tag and dt[1]!=self.back_tag]
243
+ self.side_tags: list[int] = [dt[1] for dt in tags if dt[1]!=self.front_tag and dt[1]!=self.back_tag]
242
244
 
243
- for tag in self.side_tags:
244
- o2 = gmsh.model.occ.get_center_of_mass(2, tag)
245
- n2 = gmsh.model.get_normal(tag, (0,0))
246
- self._add_face_pointer(f'side{tag}', o2, n2)
247
- self.back_tag = tag
245
+ for tag in self.side_tags:
246
+
247
+ self._add_face_pointer(f'side{tag}', tag=tag)
248
+ self.back_tag = tag
249
+
250
+ elif _axis is not None:
251
+ _axis = _parse_axis(_axis)
252
+ gmsh.model.occ.synchronize()
253
+ tags = gmsh.model.get_boundary(self.dimtags, oriented=False)
254
+ faces = []
255
+ for dim, tag in tags:
256
+ o1 = np.array(gmsh.model.occ.get_center_of_mass(2, tag))
257
+ n1 = np.array(gmsh.model.get_normal(tag, (0,0)))
258
+ if abs(np.sum(n1*_axis.np)) > 0.99:
259
+ dax = sum(o1 * _axis.np)
260
+ faces.append((o1, n1, dax, tag))
261
+
262
+ faces = sorted(faces, key=lambda x: x[2])
263
+ ftags = []
264
+ if len(faces) >= 2:
265
+ ftags.append(faces[0][3])
266
+ ftags.append(faces[-1][3])
267
+ self._add_face_pointer('front',faces[0][0], faces[0][1])
268
+ self._add_face_pointer('back', faces[-1][0], faces[-1][1])
269
+ elif len(faces)==1:
270
+ ftags.append(faces[0][3])
271
+ self._add_face_pointer('cap',faces[0][0], faces[0][1])
272
+
273
+ ictr = 1
274
+ for dim, tag in tags:
275
+ if tag in ftags:
276
+ continue
277
+ self._add_face_pointer(f'side{ictr}', tag=tag)
278
+ ictr += 1
248
279
 
249
280
  def outside(self, *exclude: Literal['front','back']) -> FaceSelection:
250
281
  """Select all outside faces except for the once specified by outside
@@ -462,9 +493,10 @@ class XYPolygon:
462
493
  ax, ay, az = axis
463
494
 
464
495
  volume = gmsh.model.occ.revolve(poly_fin.dimtags, x,y,z, ax, ay, az, angle*np.pi/180)
496
+
465
497
  tags = [t for d,t in volume if d==3]
466
- surftags = [t for d,t in volume if d==2]
467
- return GeoPrism(tags, surftags[0], surftags)
498
+ poly_fin.remove()
499
+ return GeoPrism(tags, _axis=axis)
468
500
 
469
501
  @staticmethod
470
502
  def circle(radius: float,
@@ -27,6 +27,12 @@ from typing import Literal
27
27
  from functools import reduce
28
28
 
29
29
  class Alignment(Enum):
30
+ """The alignment Enum describes if a box, cube or rectangle location
31
+ is specified for the center or the bottom - front - left corner (min X Y and Z)
32
+
33
+ Args:
34
+ Enum (_type_): _description_
35
+ """
30
36
  CENTER = 1
31
37
  CORNER = 2
32
38
 
@@ -285,9 +285,18 @@ class GeoObject:
285
285
 
286
286
  def _add_face_pointer(self,
287
287
  name: str,
288
- origin: np.ndarray,
289
- normal: np.ndarray):
290
- self._face_pointers[name] = _FacePointer(origin, normal)
288
+ origin: np.ndarray | None = None,
289
+ normal: np.ndarray | None = None,
290
+ tag: int | None = None):
291
+ if tag is not None:
292
+ o = gmsh.model.occ.get_center_of_mass(2, tag)
293
+ n = gmsh.model.get_normal(tag, (0,0))
294
+ self._face_pointers[name] = _FacePointer(o, n)
295
+ return
296
+ if origin is not None and normal is not None:
297
+ self._face_pointers[name] = _FacePointer(origin, normal)
298
+ return
299
+ raise ValueError('Eitehr a tag or an origin + normal must be provided!')
291
300
 
292
301
  def make_copy(self) -> GeoObject:
293
302
  new_dimtags = gmsh.model.occ.copy(self.dimtags)
@@ -18,11 +18,14 @@
18
18
  from loguru import logger
19
19
  import sys
20
20
  from typing import Literal
21
- from enum import Enum
22
21
  from pathlib import Path
23
22
  import os
24
- import gmsh
23
+ from collections import deque
25
24
 
25
+ _LOG_BUFFER = deque()
26
+
27
+ def _log_sink(message):
28
+ _LOG_BUFFER.append(message)
26
29
  ############################################################
27
30
  # FORMATS #
28
31
  ############################################################
@@ -82,6 +85,14 @@ class LogController:
82
85
  format=FORMAT_DICT.get(loglevel, INFO_FORMAT))
83
86
  self.std_handlers.append(handle_id)
84
87
 
88
+ def _set_log_buffer(self):
89
+ logger.add(_log_sink)
90
+
91
+ def _flush_log_buffer(self):
92
+ for msg in list(_LOG_BUFFER):
93
+ logger.opt(depth=6).log(msg.record["level"].name, msg.record["message"])
94
+ _LOG_BUFFER.clear()
95
+
85
96
  def set_std_loglevel(self, loglevel: str):
86
97
  handler = {"sink": sys.stdout,
87
98
  "level": loglevel,
@@ -310,6 +310,8 @@ class Material:
310
310
 
311
311
  self.color: str = color
312
312
  self.opacity: float = opacity
313
+ self._hash_key: int = -1
314
+
313
315
  if _neff is None:
314
316
  self._neff: Callable = lambda f: np.sqrt(self.ur._fmax(f)*self.er._fmax(f))
315
317
  else:
@@ -318,8 +320,14 @@ class Material:
318
320
  self._color_rgb = tuple(int(hex_str[i:i+2], 16)/255.0 for i in (0, 2, 4))
319
321
  self._metal: bool = _metal
320
322
 
323
+ def __hash__(self):
324
+ return self._hash_key
325
+
321
326
  def __str__(self) -> str:
322
- return f'Material({self.name})'
327
+ return f'Material({self.name}, {self._hash_key})'
328
+
329
+ def __repr__(self):
330
+ return f'Material({self.name}, {self._hash_key})'
323
331
 
324
332
  def initialize(self, xs: np.ndarray, ys: np.ndarray, zs: np.ndarray, ids: np.ndarray):
325
333
  """Initializes the Material properties to be evaluated at xyz-coordinates for
@@ -343,6 +351,7 @@ class Material:
343
351
  self.ur.reset()
344
352
  self.tand.reset()
345
353
  self.cond.reset()
354
+ self._hash_key = -1
346
355
 
347
356
  @property
348
357
  def frequency_dependent(self) -> bool:
@@ -544,22 +544,33 @@ class Mesh3D(Mesh):
544
544
  #arry = np.zeros((3,3,self.n_tets,), dtype=np.complex128)
545
545
  for vol in volumes:
546
546
  vol.material.reset()
547
-
547
+
548
548
  materials = []
549
+ i = 0
550
+ for vol in volumes:
551
+ if vol.material not in materials:
552
+ materials.append(vol.material)
553
+ vol.material._hash_key = i
554
+ i += 1
549
555
 
550
556
  xs = self.centers[0,:]
551
557
  ys = self.centers[1,:]
552
558
  zs = self.centers[2,:]
553
559
 
560
+ matassign = -1*np.ones((self.n_tets,), dtype=np.int64)
561
+
554
562
  for volume in sorted(volumes, key=lambda x: x._priority):
555
563
 
556
564
  for dimtag in volume.dimtags:
557
565
  etype, etag_list, ntags = gmsh.model.mesh.get_elements(*dimtag)
558
566
  for etags in etag_list:
559
567
  tet_ids = np.array([self.tet_t2i[t] for t in etags])
560
- volume.material.initialize(xs[tet_ids], ys[tet_ids], zs[tet_ids], tet_ids)
561
- if volume.material not in materials:
562
- materials.append(volume.material)
568
+ matassign[tet_ids] = volume.material._hash_key
569
+
570
+ for mat in materials:
571
+ ids = np.argwhere(matassign==mat._hash_key).flatten()
572
+ mat.initialize(xs[ids], ys[ids], zs[ids], ids)
573
+
563
574
 
564
575
  return materials
565
576
 
@@ -53,7 +53,7 @@ def run_job_multi(job: SimJob) -> SimJob:
53
53
  Returns:
54
54
  SimJob: The solved SimJob
55
55
  """
56
- routine = DEFAULT_ROUTINE.duplicate()._configure_routine('MP')
56
+ routine = DEFAULT_ROUTINE._configure_routine('MP')
57
57
  for A, b, ids, reuse, aux in job.iter_Ab():
58
58
  solution, report = routine.solve(A, b, ids, reuse, id=job.id)
59
59
  report.add(**aux)
@@ -306,11 +306,17 @@ class AbsorbingBoundary(RobinBC):
306
306
  Returns:
307
307
  complex: The γ-constant
308
308
  """
309
- return 1j*self.get_beta(k0)
309
+ if self.order == 2:
310
+
311
+ p0 = 1.06103
312
+ p2 = -0.84883
313
+ ky = k0*0.5
314
+ return 1j*k0*p0 - 1j*p2*ky**2/k0
315
+ else:
316
+ Factor = 1
317
+ return 1j*self.get_beta(k0)*Factor
310
318
 
311
- def get_Uinc(self, x_local: np.ndarray, y_local: np.ndarray, k0: float) -> np.ndarray:
312
- return np.zeros((3, len(x_local)), dtype=np.complex128)
313
-
319
+
314
320
  @dataclass
315
321
  class PortMode:
316
322
  modefield: np.ndarray
@@ -825,9 +831,9 @@ class LumpedPort(PortBC):
825
831
  self.Vdirection: Axis = direction # type: ignore
826
832
  self.type = 'TEM'
827
833
 
828
- logger.info('Constructing coordinate system from normal port')
829
- self.cs = Axis(self.selection.normal).construct_cs() # type: ignore
830
-
834
+ # logger.info('Constructing coordinate system from normal port')
835
+ # self.cs = Axis(self.selection.normal).construct_cs() # type: ignore
836
+ self.cs = GCS
831
837
  self.vintline: Line | None = None
832
838
  self.v_integration = True
833
839
 
@@ -881,14 +887,7 @@ class LumpedPort(PortBC):
881
887
  k0: float,
882
888
  which: Literal['E','H'] = 'E') -> np.ndarray:
883
889
  ''' Compute the port mode E-field in local coordinates (XY) + Z out of plane.'''
884
-
885
- px, py, pz = self.cs.in_local_basis(*self.Vdirection.np)
886
-
887
- Ex = px*np.ones_like(x_local)
888
- Ey = py*np.ones_like(x_local)
889
- Ez = pz*np.ones_like(x_local)
890
- Exyz = np.array([Ex, Ey, Ez])
891
- return Exyz
890
+ raise RuntimeError('This function should never be called in this context.')
892
891
 
893
892
  def port_mode_3d_global(self,
894
893
  x_global: np.ndarray,
@@ -911,10 +910,9 @@ class LumpedPort(PortBC):
911
910
  Returns:
912
911
  np.ndarray: The E-field in (3,N) indexing.
913
912
  """
914
- xl, yl, _ = self.cs.in_local_cs(x_global, y_global, z_global)
915
- Ex, Ey, Ez = self.port_mode_3d(xl, yl, k0)
916
- Exg, Eyg, Ezg = self.cs.in_global_basis(Ex, Ey, Ez)
917
- return np.array([Exg, Eyg, Ezg])
913
+ ON = np.ones_like(x_global)
914
+ Ex, Ey, Ez = self.Vdirection.np
915
+ return np.array([Ex*ON, Ey*ON, Ez*ON])
918
916
 
919
917
 
920
918
  class LumpedElement(RobinBC):
@@ -596,7 +596,7 @@ class PVDisplay(BaseDisplay):
596
596
 
597
597
 
598
598
  if scale=='log':
599
- T = lambda x: np.log10(np.abs(x))
599
+ T = lambda x: np.log10(np.abs(x+1e-12))
600
600
  elif scale=='symlog':
601
601
  T = lambda x: np.sign(x) * np.log10(1 + np.abs(x*np.log(10)))
602
602
  else:
@@ -422,9 +422,14 @@ def plot_sp(f: np.ndarray | list[np.ndarray], S: list[np.ndarray] | np.ndarray,
422
422
  show_plot: bool = True,
423
423
  figdata: tuple | None = None) -> tuple[plt.Figure, plt.Axes, plt.Axes]:
424
424
  """Plot S-parameters in dB and phase
425
+
426
+ One may provide:
427
+ - A single frequency with a single S-parameter
428
+ - A single frequency with a list of S-parameters
429
+ - A list of frequencies with a list of S-parameters
425
430
 
426
431
  Args:
427
- f (np.ndarray): Frequency vector
432
+ f (np.ndarray | list[np.ndarray]): Frequency vector or list of frequencies
428
433
  S (list[np.ndarray] | np.ndarray): S-parameters to plot (list or single array)
429
434
  dblim (list, optional): Decibel y-axis limit. Defaults to [-80, 5].
430
435
  xunit (str, optional): Frequency unit. Defaults to "GHz".
@@ -535,7 +540,7 @@ def plot_sp(f: np.ndarray | list[np.ndarray], S: list[np.ndarray] | np.ndarray,
535
540
 
536
541
 
537
542
  def plot_ff(
538
- theta: np.ndarray,
543
+ theta: np.ndarray | list[np.ndarray],
539
544
  E: Union[np.ndarray, Sequence[np.ndarray]],
540
545
  grid: bool = True,
541
546
  dB: bool = False,
@@ -554,7 +559,7 @@ def plot_ff(
554
559
 
555
560
  Parameters
556
561
  ----------
557
- theta : np.ndarray
562
+ theta : np.ndarray | list[np.ndarray]
558
563
  Angle array (radians).
559
564
  E : np.ndarray or sequence of np.ndarray
560
565
  Complex E-field samples; magnitude will be plotted.
@@ -575,6 +580,12 @@ def plot_ff(
575
580
  E_list = [E]
576
581
  else:
577
582
  E_list = list(E)
583
+
584
+ if not isinstance(theta, list):
585
+ thetas = [theta for _ in E_list]
586
+ else:
587
+ thetas = theta
588
+
578
589
  n_series = len(E_list)
579
590
 
580
591
  # Style broadcasting
@@ -591,6 +602,7 @@ def plot_ff(
591
602
 
592
603
  fig, ax = plt.subplots()
593
604
  for i, Ei in enumerate(E_list):
605
+ theta = thetas[i]
594
606
  mag = np.abs(Ei)
595
607
  if dB:
596
608
  mag = 20*np.log10(mag)
@@ -68,7 +68,7 @@ class Simulation:
68
68
  loglevel: Literal['TRACE','DEBUG','INFO','WARNING','ERROR'] = 'INFO',
69
69
  load_file: bool = False,
70
70
  save_file: bool = False,
71
- logfile: bool = False,
71
+ write_log: bool = False,
72
72
  path_suffix: str = ".EMResults"):
73
73
  """Generate a Simulation class object.
74
74
 
@@ -80,7 +80,7 @@ class Simulation:
80
80
  loglevel ("DEBUG","INFO","WARNING","ERROR", optional): The loglevel to use for loguru. Defaults to 'INFO'.
81
81
  load_file (bool, optional): If the simulatio model should be loaded from a file. Defaults to False.
82
82
  save_file (bool, optional): if the simulation file should be stored to a file. Defaults to False.
83
- logfile (bool, optional): If a file should be created that contains the entire log of the simulation. Defaults to False.
83
+ write_log (bool, optional): If a file should be created that contains the entire log of the simulation. Defaults to False.
84
84
  path_suffix (str, optional): The suffix that will be added to the results directory. Defaults to ".EMResults".
85
85
  """
86
86
 
@@ -113,9 +113,10 @@ class Simulation:
113
113
  self._initialize_simulation()
114
114
 
115
115
  self.set_loglevel(loglevel)
116
- if logfile:
117
- self.set_logfile()
116
+ if write_log:
117
+ self.set_write_log()
118
118
 
119
+ LOG_CONTROLLER._flush_log_buffer()
119
120
  self._update_data()
120
121
 
121
122
 
@@ -324,7 +325,7 @@ class Simulation:
324
325
  if loglevel not in ('TRACE','DEBUG'):
325
326
  gmsh.option.setNumber("General.Terminal", 0)
326
327
 
327
- def set_logfile(self) -> None:
328
+ def set_write_log(self) -> None:
328
329
  """Adds a file output for the logger."""
329
330
  LOG_CONTROLLER.set_write_file(self.modelpath)
330
331
 
@@ -15,7 +15,16 @@
15
15
  # along with this program; if not, see
16
16
  # <https://www.gnu.org/licenses/>.
17
17
 
18
- import cupy as cp # ty: ignore
18
+ import warnings
19
+ from loguru import logger
20
+
21
+ # Catch the Cuda warning and print it with Loguru.
22
+ with warnings.catch_warnings(record=True) as w:
23
+ warnings.simplefilter("always")
24
+ import cupy as cp
25
+ for warn in w:
26
+ logger.debug(f"{warn.category.__name__}: {warn.message}")
27
+
19
28
  import nvmath.bindings.cudss as cudss # ty: ignore
20
29
  from nvmath import CudaDataType # ty: ignore
21
30
 
@@ -23,9 +32,6 @@ from scipy.sparse import csr_matrix
23
32
  import numpy as np
24
33
  from typing import Literal
25
34
 
26
- from loguru import logger
27
-
28
-
29
35
  ############################################################
30
36
  # CONSTANTS #
31
37
  ############################################################
@@ -504,6 +504,7 @@ class SolverSuperLU(Solver):
504
504
  logger.info(f'[ID={id}] Calling SuperLU Solver.')
505
505
  self.single = True
506
506
  if not reuse_factorization:
507
+ logger.trace('Computing LU-Decomposition')
507
508
  self.lu = splu(A, permc_spec='MMD_AT_PLUS_A', relax=0, diag_pivot_thresh=self._pivoting_threshold, options=self.options)
508
509
  x = self.lu.solve(b)
509
510
  aux = {
@@ -518,6 +519,7 @@ class SolverUMFPACK(Solver):
518
519
 
519
520
  def __init__(self):
520
521
  super().__init__()
522
+ logger.trace('Creating UMFPACK solver')
521
523
  self.A: np.ndarray = None
522
524
  self.b: np.ndarray = None
523
525
 
@@ -532,6 +534,7 @@ class SolverUMFPACK(Solver):
532
534
  def initialize(self):
533
535
  if self.initalized:
534
536
  return
537
+ logger.trace('Initializing UMFPACK Solver')
535
538
  self.umfpack = um.UmfpackContext('zl')
536
539
  self.umfpack.control[um.UMFPACK_PRL] = 0 # ty: ignore
537
540
  self.umfpack.control[um.UMFPACK_IRSTEP] = 2 # ty: ignore
@@ -542,7 +545,9 @@ class SolverUMFPACK(Solver):
542
545
  self.umfpack.control[um.UMFPACK_BLOCK_SIZE] = 64 # ty: ignore
543
546
  self.umfpack.control[um.UMFPACK_FIXQ] = -1 # ty: ignore
544
547
  self.initalized = True
548
+
545
549
  def reset(self) -> None:
550
+ logger.trace('Resetting UMFPACK solver state')
546
551
  self.fact_symb = False
547
552
 
548
553
  def set_options(self, pivoting_threshold: float | None = None) -> None:
@@ -562,13 +567,14 @@ class SolverUMFPACK(Solver):
562
567
  A.indptr = A.indptr.astype(np.int64)
563
568
  A.indices = A.indices.astype(np.int64)
564
569
  if self.fact_symb is False:
565
- logger.debug(f'[ID={id}] Executing symbollic factorization.')
570
+ logger.trace(f'[ID={id}] Executing symbollic factorization.')
566
571
  self.umfpack.symbolic(A)
567
572
  self.fact_symb = True
568
573
  if not reuse_factorization:
569
- #logger.debug('Executing numeric factorization.')
574
+ logger.trace(f'[ID={id}] Executing numeric factorization.')
570
575
  self.umfpack.numeric(A)
571
576
  self.A = A
577
+ logger.trace(f'[ID={id}] Solving linear system.')
572
578
  x = self.umfpack.solve(um.UMFPACK_A, self.A, b, autoTranspose = False ) # ty: ignore
573
579
  aux = {
574
580
  "Pivoting Threshold": str(self._pivoting_threshold),
@@ -596,12 +602,14 @@ class SolverPardiso(Solver):
596
602
  def solve(self, A, b, precon, reuse_factorization: bool = False, id: int = -1) -> tuple[np.ndarray, SolveReport]:
597
603
  logger.info(f'[ID={id}] Calling Pardiso Solver')
598
604
  if self.fact_symb is False:
599
- logger.debug(f'[ID={id}] Executing symbollic factorization.')
605
+ logger.trace(f'[ID={id}] Executing symbollic factorization.')
600
606
  self.solver.symbolic(A)
601
607
  self.fact_symb = True
602
608
  if not reuse_factorization:
609
+ logger.trace(f'[ID={id}] Executing numeric factorization.')
603
610
  self.solver.numeric(A)
604
611
  self.A = A
612
+ logger.trace(f'[ID={id}] Solving linear system.')
605
613
  x, error = self.solver.solve(A, b)
606
614
  if error != 0:
607
615
  logger.error(f'[ID={id}] Terminated with error code {error}')
@@ -634,13 +642,15 @@ class CuDSSSolver(Solver):
634
642
  logger.info(f'[ID={id}] Calling cuDSS Solver')
635
643
 
636
644
  if self.fact_symb is False:
637
- logger.debug('Executing symbollic factorization')
645
+ logger.trace(f'[ID={id}] Starting from symbollic factorization.')
638
646
  x = self._cudss.from_symbolic(A,b)
639
647
  self.fact_symb = True
640
648
  else:
641
649
  if reuse_factorization:
650
+ logger.trace(f'[ID={id}] Solving linear system.')
642
651
  x = self._cudss.from_solve(b)
643
652
  else:
653
+ logger.trace(f'[ID={id}] Starting from numeric factorization.')
644
654
  x = self._cudss.from_numeric(A,b)
645
655
 
646
656
  return x, SolveReport(solver=str(self), exit_code=0, aux={})
@@ -29,7 +29,7 @@ dx = 2 * mm # distance from horn exit to PML start
29
29
 
30
30
  # Create simulation object
31
31
  m = em.Simulation('HornAntenna')
32
- m.check_version("0.6.9") # Checks version compatibility.
32
+ m.check_version("0.6.10") # Checks version compatibility.
33
33
  # --- Coordinate system for horn geometry -------------------------------
34
34
  hornCS = em.CS(em.YAX, em.ZAX, em.XAX)
35
35
 
@@ -29,7 +29,7 @@ def Cf(C):
29
29
  pack = '0603' # package footprint for lumped components
30
30
  # Create simulation and PCB layouter with substrate thickness and material
31
31
  m = em.Simulation('LumpedFilter')
32
- m.check_version("0.6.9") # Checks version compatibility.
32
+ m.check_version("0.6.10") # Checks version compatibility.
33
33
 
34
34
  th = 0.5 # substrate thickness (meters)
35
35
  Hair = 2.0
@@ -12,7 +12,7 @@ direction (+Z vs -Z). In EMerge we can alignm modes using the .align_mode() meth
12
12
 
13
13
  # First we define our simulation
14
14
  m = em.Simulation('aligntest')
15
- m.check_version("0.6.9") # Checks version compatibility.
15
+ m.check_version("0.6.10") # Checks version compatibility.
16
16
 
17
17
  # We create a cyllindrical waveguide in the Y-axis.
18
18
  cyl = em.geo.Cylinder(0.012, 0.05, em.YAX.construct_cs())
@@ -25,7 +25,7 @@ porth = 2*mm # vertical height of the feed extrusion
25
25
 
26
26
  # --- Simulation object -------------------------------------------------------
27
27
  model = em.Simulation('helix')
28
- model.check_version("0.6.9") # Checks version compatibility.
28
+ model.check_version("0.6.10") # Checks version compatibility.
29
29
 
30
30
  dfeed = 3*mm # straight feed length before the helix starts
31
31
 
@@ -45,7 +45,7 @@ cross_section = em.geo.XYPolygon.circle(radw, Nsections=6)
45
45
  helix = h_curve.pipe(cross_section).set_material(em.lib.MET_COPPER)
46
46
 
47
47
  # We add a block to make attachment of ports easier.
48
- block = em.geo.Box(dfeed, dfeed, dfeed, position=h_curve.p0, alignment=em.geo.Alignment.CENTER).set_material(em.lib.MET_COPPER)
48
+ block = em.geo.Box(dfeed, dfeed, dfeed, position=h_curve.p0, alignment=em.CENTER).set_material(em.lib.MET_COPPER)
49
49
 
50
50
  # Optional preview of current scene (geometry only at this point)
51
51
  model.view()
@@ -37,7 +37,7 @@ wgb = 10.16*mm
37
37
  L = 50*mm
38
38
 
39
39
  model = em.Simulation('Test Mode')
40
- model.check_version("0.6.9") # Checks version compatibility.
40
+ model.check_version("0.6.10") # Checks version compatibility.
41
41
 
42
42
  # first lets define a WR90 waveguide
43
43
  wg_box = em.geo.Box(L, wga, wgb, position=(-L, -wga/2, -wgb/2))
@@ -28,7 +28,7 @@ pcbmat = em.Material(er=er, color="#217627", opacity=0.2)
28
28
  # We start by creating our simulation object.
29
29
 
30
30
  m = em.Simulation('Demo1_SIF', loglevel='INFO')
31
- m.check_version("0.6.9") # Checks version compatibility.
31
+ m.check_version("0.6.10") # Checks version compatibility.
32
32
  # To accomodate PCB routing we make use of the PCBLayouter class. To use it we need to
33
33
  # supply it with a thickness, the desired air-box height, the units at which we supply
34
34
  # the dimensions and the PCB material.
@@ -43,7 +43,7 @@ lfeed = 100*mil
43
43
 
44
44
  # A usual we start our simulation file
45
45
  model = em.Simulation('Combline_DEMO')
46
- model.check_version("0.6.9") # Checks version compatibility.
46
+ model.check_version("0.6.10") # Checks version compatibility.
47
47
 
48
48
  # The filter consists of quarter lamba cylindrical pins inside an airbox.
49
49
  # First we create the airbox
@@ -38,7 +38,7 @@ extra = 100 # extra margin (mil)
38
38
 
39
39
  # --- Simulation setup ----------------------------------------------------
40
40
  model = em.Simulation('Demo3')
41
- model.check_version("0.6.9") # Checks version compatibility.
41
+ model.check_version("0.6.10") # Checks version compatibility.
42
42
  # --- Material and layouter -----------------------------------------------
43
43
  mat = em.Material(er=3.55, color="#488343", opacity=0.1)
44
44
  # Create PCB layouter with given substrate thickness and units
@@ -34,7 +34,7 @@ f2 = 1.60e9 # stop frequency
34
34
  # --- Create simulation object -------------------------------------------
35
35
  model = em.Simulation('MyPatchAntenna')
36
36
 
37
- model.check_version("0.6.9") # Checks version compatibility.
37
+ model.check_version("0.6.10") # Checks version compatibility.
38
38
 
39
39
  # --- Define geometry primitives -----------------------------------------
40
40
  # Substrate block centered at origin in XY, thickness in Z (negative down)
@@ -0,0 +1,15 @@
1
+ import emerge as em
2
+
3
+ model = em.Simulation('Sphere')
4
+ model.check_version("0.6.10") # Checks version compatibility.
5
+
6
+ poly = em.geo.XYPolygon([0, 0.05, 0.05, 0], [0, 0, 0.1, 0.1])
7
+ vol = poly.revolve(em.XZPLANE.cs(), (0,0,0), (1,0,0))
8
+
9
+ model.commit_geometry()
10
+
11
+
12
+ model.mw.set_frequency(3e9)
13
+
14
+ model.generate_mesh()
15
+ model.view(selections=[vol.face('side1'),])
@@ -14,7 +14,7 @@ mm = 0.001 # Define a millimeter
14
14
  th = 1.0 # mm
15
15
 
16
16
  model = em.Simulation('Stripline_test')
17
- model.check_version("0.6.9") # Checks version compatibility.
17
+ model.check_version("0.6.10") # Checks version compatibility.
18
18
 
19
19
  # As usual we start by creating our layouter
20
20
  ly = em.geo.PCB(th, mm, em.GCS, em.lib.DIEL_RO4350B)
@@ -32,7 +32,7 @@ fl = 25*mm # Feed length
32
32
 
33
33
  # We start again by defining our simulation model
34
34
  model = em.Simulation('Periodic')
35
- model.check_version("0.6.9") # Checks version compatibility.
35
+ model.check_version("0.6.10") # Checks version compatibility.
36
36
 
37
37
  # Next we will create a PeriodicCell class (in our case a hexagonal cell). This class
38
38
  # is simply meant to simplify our lives and improve the simulation setup flow.
@@ -80,7 +80,7 @@ wgaps = np.linspace(1*mm, 20*mm, 21)
80
80
  Ks = []
81
81
  hphis = []
82
82
  with em.Simulation('IrisSim') as sim:
83
- sim.check_version("0.6.9") # Checks version compatibility.
83
+ sim.check_version("0.6.10") # Checks version compatibility.
84
84
  for wgap in sim.parameter_sweep(True, wgap=wgaps):
85
85
  # Define two short waveguide sections separated by iris plate
86
86
  wg1 = em.geo.Box(wga, Lfeed, wgb, (-wga/2, -Lfeed - t_thickness/2, 0))
@@ -32,8 +32,8 @@ mat_resonator = em.lib.Material(er=34, color="#ededed")
32
32
  Nmodes = 5
33
33
 
34
34
  # --- Create simulation ---------------------------------------------------
35
- model = em.Simulation('DielectricResonatorFilter')
36
- model.check_version("0.6.9") # Checks version compatibility.
35
+ model = em.Simulation('DielectricResonatorFilter', loglevel="DEBUG")
36
+ model.check_version("0.6.10") # Checks version compatibility.
37
37
 
38
38
  # --- Build geometry ------------------------------------------------------
39
39
  # Metal enclosure box (PEC by default)
@@ -3,7 +3,7 @@ allow-direct-references = true
3
3
 
4
4
  [project]
5
5
  name = "emerge"
6
- version = "0.6.9"
6
+ version = "0.6.10"
7
7
  description = "An open source EM FEM simulator in Python"
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.10, <4.0"
@@ -245,7 +245,7 @@ wheels = [
245
245
 
246
246
  [[package]]
247
247
  name = "emerge"
248
- version = "0.6.9"
248
+ version = "0.6.10"
249
249
  source = { editable = "." }
250
250
  dependencies = [
251
251
  { name = "cloudpickle" },
@@ -1,25 +0,0 @@
1
- import emerge as em
2
- """This demo is still in progress.
3
-
4
- For now it just shows you how to work with the revolve system.
5
- """
6
- model = em.Simulation('Revolve test')
7
- model.check_version("0.6.9") # Checks version compatibility.
8
-
9
- mm = 0.001
10
- rad_feed = 30*mm
11
- rad_out = 70*mm
12
- len_horn = 100*mm
13
- len_feed = 40*mm
14
- th = 5*mm
15
-
16
- poly = em.geo.XYPolygon([rad_feed, rad_feed, rad_out, 0, 0], [-len_feed, 0, len_horn, len_horn, -len_feed])
17
- vol_in = poly.revolve(em.ZXPLANE.cs(), (0,0,0), (1,0,0))
18
- poly = em.geo.XYPolygon([rad_feed+th, rad_feed+th, rad_out+th, 0, 0], [-len_feed, 0, len_horn, len_horn, -len_feed])
19
- vol_out = poly.revolve(em.ZXPLANE.cs(), (0,0,0), (1,0,0))
20
-
21
- ratio = 2.5
22
- airbox = em.geo.pmlbox(40*mm, ratio*rad_out, ratio*rad_out, (len_horn-5*mm, -ratio*rad_out/2, -ratio*rad_out/2), thickness=30*mm,
23
- top=True, bottom=True, right=True, front=True, back=True)
24
-
25
- model.view()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes