emerge 1.1.0__py3-none-any.whl → 1.1.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 emerge might be problematic. Click here for more details.

@@ -273,13 +273,17 @@ class Assembler:
273
273
 
274
274
  logger.debug('Implementing PEC Boundary Conditions.')
275
275
  pec_ids: list[int] = []
276
+ pec_tris: list[int] = []
276
277
 
277
278
  # Conductivity above al imit, consider it all PEC
278
279
  ipec = 0
280
+
279
281
  for itet in range(field.n_tets):
280
282
  if cond[0,0,itet] > self.settings.mw_3d_peclim:
281
283
  ipec+=1
282
284
  pec_ids.extend(field.tet_to_field[:,itet])
285
+ for tri in field.mesh.tet_to_tri[:,itet]:
286
+ pec_tris.append(tri)
283
287
  if ipec>0:
284
288
  logger.trace(f'Extended PEC with {ipec} tets with a conductivity > {self.settings.mw_3d_peclim}.')
285
289
 
@@ -295,9 +299,12 @@ class Assembler:
295
299
  eids = field.edge_to_field[:, ii]
296
300
  pec_ids.extend(list(eids))
297
301
 
302
+
298
303
  for ii in tri_ids:
299
304
  tids = field.tri_to_field[:, ii]
300
305
  pec_ids.extend(list(tids))
306
+
307
+ pec_tris.extend(tri_ids)
301
308
 
302
309
 
303
310
  ############################################################
@@ -412,7 +419,8 @@ class Assembler:
412
419
 
413
420
  simjob.port_vectors = port_vectors
414
421
  simjob.solve_ids = solve_ids
415
-
422
+ simjob._pec_tris = pec_tris
423
+
416
424
  if has_periodic:
417
425
  simjob.P = Pmat
418
426
  simjob.Pd = Pmat.getH()
@@ -876,7 +876,7 @@ class Microwave3D:
876
876
  def _run_adaptive_mesh(self,
877
877
  iteration: int,
878
878
  frequency: float,
879
- automatic_modal_analysis: bool = True) -> MWData:
879
+ automatic_modal_analysis: bool = True) -> tuple[MWData, list[int]]:
880
880
  """Executes a frequency domain study
881
881
 
882
882
  The study is distributed over "n_workers" workers.
@@ -965,7 +965,7 @@ class Microwave3D:
965
965
  self.solveroutine.reset()
966
966
  ### Compute S-parameters and return
967
967
  self._post_process([job,], [mats,])
968
- return self.data
968
+ return self.data, job._pec_tris
969
969
 
970
970
  def eigenmode(self, search_frequency: float,
971
971
  nmodes: int = 6,
@@ -773,6 +773,7 @@ class RectangularWaveguide(PortBC):
773
773
  logger.info(' - Constructing coordinate system from normal port')
774
774
  self.cs = Axis(self.selection.normal).construct_cs()
775
775
  logger.debug(f' - Port CS: {self.cs}')
776
+
776
777
  def get_basis(self) -> np.ndarray:
777
778
  return self.cs._basis
778
779
 
@@ -667,13 +667,51 @@ class MWField:
667
667
  return sum([self.excitation[mode.port_number]*self._fields[mode.port_number] for mode in self.port_modes]) # type: ignore
668
668
 
669
669
  def set_field_vector(self) -> None:
670
- """Defines the default excitation coefficients for the current dataset"""
670
+ """Defines the default excitation coefficients for the current dataset as an excitation of only port 1."""
671
671
  self.excitation = {key: 0.0 for key in self._fields.keys()}
672
672
  self.excitation[self.port_modes[0].port_number] = 1.0 + 0j
673
673
 
674
- def excite_port(self, number: int) -> None:
674
+ def excite_port(self, number: int, excitation: complex = 1.0 + 0.0j) -> None:
675
+ """Excite a single port provided by a given port number
676
+
677
+ Args:
678
+ number (int): The port number to excite
679
+ coefficient (complex): The port excitation. Defaults to 1.0 + 0.0j
680
+ """
681
+ self.excitation = {key: 0.0 for key in self._fields.keys()}
682
+ self.excitation[self.port_modes[number-1].port_number] = excitation
683
+
684
+ def set_excitations(self, *excitations: complex) -> None:
685
+ """Set bulk port excitations by an ordered array of excitation coefficients.
686
+
687
+ Returns:
688
+ *complex: A sequence of complex numbers
689
+ """
675
690
  self.excitation = {key: 0.0 for key in self._fields.keys()}
676
- self.excitation[self.port_modes[number].port_number] = 1.0 + 0j
691
+ for iport, coeff in enumerate(excitations):
692
+ self.excitation[self.port_modes[iport].port_number] = coeff
693
+
694
+ def combine_ports(self, p1: int, p2: int) -> MWField:
695
+ """Combines ports p1 and p2 into a cifferential and common mode port respectively.
696
+
697
+ The p1 index becomes the differential mode port
698
+ The p2 index becomes the common mode port
699
+
700
+ Args:
701
+ p1 (int): The first port number
702
+ p2 (int): The second port number
703
+
704
+ Returns:
705
+ MWField: _description_
706
+ """
707
+
708
+ fp1 = self._fields[p1]
709
+ fp2 = self._fields[p2]
710
+
711
+ self._fields[p1] = (fp1-fp2)/np.sqrt(2)
712
+ self._fields[p2] = (fp1+fp2)/np.sqrt(2)
713
+
714
+ return self
677
715
 
678
716
  @property
679
717
  def EH(self) -> tuple[np.ndarray, np.ndarray]:
@@ -720,7 +758,9 @@ class MWField:
720
758
  xf = xs.flatten()
721
759
  yf = ys.flatten()
722
760
  zf = zs.flatten()
761
+ logger.debug(f'Interpolating {xf.shape[0]} field points')
723
762
  Ex, Ey, Ez = self.basis.interpolate(self._field, xf, yf, zf, usenan=usenan)
763
+ logger.debug('E Interpolation complete')
724
764
  self.Ex = Ex.reshape(shp)
725
765
  self.Ey = Ey.reshape(shp)
726
766
  self.Ez = Ez.reshape(shp)
@@ -728,6 +768,7 @@ class MWField:
728
768
 
729
769
  constants = 1/ (-1j*2*np.pi*self.freq*(self._dur*MU0) )
730
770
  Hx, Hy, Hz = self.basis.interpolate_curl(self._field, xf, yf, zf, constants, usenan=usenan)
771
+ logger.debug('H Interpolation complete')
731
772
  ids = self.basis.interpolate_index(xf, yf, zf)
732
773
 
733
774
  self.er = self._der[ids].reshape(shp)
@@ -743,10 +784,10 @@ class MWField:
743
784
 
744
785
  return field
745
786
 
746
- def _solution_quality(self) -> tuple[np.ndarray, np.ndarray]:
787
+ def _solution_quality(self, solve_ids: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
747
788
  from .adaptive_mesh import compute_error_estimate
748
789
 
749
- error_tet, max_elem_size = compute_error_estimate(self)
790
+ error_tet, max_elem_size = compute_error_estimate(self, solve_ids)
750
791
  return error_tet, max_elem_size
751
792
 
752
793
  def boundary(self,
@@ -1146,6 +1187,54 @@ class MWScalarNdim:
1146
1187
  def S(self, i1: int, i2: int) -> np.ndarray:
1147
1188
  return self.Sp[...,self._portmap[i1], self._portmap[i2]]
1148
1189
 
1190
+ def combine_ports(self, p1: int, p2: int) -> MWScalarNdim:
1191
+ """Combine ports p1 and p2 into a differential and common mode port respectively.
1192
+
1193
+ The p1 index becomes the differential mode port
1194
+ The p2 index becomes the common mode port
1195
+
1196
+ Args:
1197
+ p1 (int): The first port number
1198
+ p2 (int): The second port number
1199
+
1200
+ Returns:
1201
+ MWScalarNdim: _description_
1202
+ """
1203
+ if p1==p2:
1204
+ raise ValueError('p1 and p2 must be different port numbers')
1205
+
1206
+ F, N, _ = self.Sp.shape
1207
+ p1 = p1-1
1208
+ p2 = p2-1
1209
+
1210
+ if not (0 <= p1 < N and 0 <= p2 < N):
1211
+ raise IndexError(f'Ports {p1+1} or {p2+1} are out of range {N}')
1212
+
1213
+ Sout = self.Sp.copy()
1214
+ ii, jj = p1, p2
1215
+ idx = np.ones(N, dtype=np.bool)
1216
+ idx[[ii,jj]] = False
1217
+ others = np.nonzero(idx)[0]
1218
+ isqrt2 = 1.0 / np.sqrt(2.0)
1219
+
1220
+ Sout[:, others, ii] = (self.Sp[:, others, ii] - self.Sp[:, others, jj]) * isqrt2
1221
+ Sout[:, others, jj] = (self.Sp[:, others, ii] + self.Sp[:, others, jj]) * isqrt2
1222
+ Sout[:, ii, others] = (self.Sp[:, ii, others] - self.Sp[:, jj, others]) * isqrt2
1223
+ Sout[:, jj, others] = (self.Sp[:, ii, others] + self.Sp[:, jj, others]) * isqrt2
1224
+
1225
+ Sii = self.Sp[:, ii, ii]
1226
+ Sij = self.Sp[:, ii, jj]
1227
+ Sji = self.Sp[:, jj, ii]
1228
+ Sjj = self.Sp[:, jj, jj]
1229
+
1230
+ Sout[:, ii, ii] = 0.5 *(Sii - Sij - Sji + Sjj)
1231
+ Sout[:, ii, jj] = 0.5 *(Sii + Sij - Sji - Sjj)
1232
+ Sout[:, jj, ii] = 0.5 *(Sii - Sij + Sji - Sjj)
1233
+ Sout[:, jj, jj] = 0.5 *(Sii + Sij + Sji + Sjj)
1234
+
1235
+ self.Sp = Sout
1236
+
1237
+ return self
1149
1238
  @property
1150
1239
  def Smat(self) -> np.ndarray:
1151
1240
  """Returns the full S-matrix
@@ -242,6 +242,7 @@ class PVDisplay(BaseDisplay):
242
242
  self._stop: bool = False
243
243
  self._objs: list[_AnimObject] = []
244
244
  self._do_animate: bool = False
245
+ self._animate_next: bool = False
245
246
  self._closed_via_x: bool = False
246
247
  self._Nsteps: int = 0
247
248
  self._fps: int = 25
@@ -334,6 +335,7 @@ class PVDisplay(BaseDisplay):
334
335
  self._plot = pv.Plotter()
335
336
  self._stop = False
336
337
  self._objs = []
338
+ self._animate_next = False
337
339
  C_CYCLE = _gen_c_cycle()
338
340
 
339
341
  def _close_callback(self, arg):
@@ -403,6 +405,7 @@ class PVDisplay(BaseDisplay):
403
405
  print('If you closed the animation without using (Q) press Ctrl+C to kill the process.')
404
406
  self._Nsteps = Nsteps
405
407
  self._fps = fps
408
+ self._animate_next = True
406
409
  self._do_animate = True
407
410
  return self
408
411
 
@@ -518,7 +521,7 @@ class PVDisplay(BaseDisplay):
518
521
 
519
522
  self._plot.add_mesh(self._volume_edges(_select(obj)), color='#000000', line_width=2, show_edges=True)
520
523
 
521
- if isinstance(obj, GeoObject) and label:
524
+ if label:
522
525
  points = []
523
526
  labels = []
524
527
  for dt in obj.dimtags:
@@ -691,14 +694,14 @@ class PVDisplay(BaseDisplay):
691
694
  actor = self._plot.add_mesh(grid_no_nan, scalars=name, scalar_bar_args=self._cbar_args, **kwargs)
692
695
 
693
696
 
694
- if self._do_animate:
697
+ if self._animate_next:
695
698
  def on_update(obj: _AnimObject, phi: complex):
696
699
  field_anim = obj.T(np.real(obj.field * phi))
697
700
  obj.grid[name] = field_anim
698
701
  obj.fgrid[name] = obj.grid.threshold(scalars=name)[name]
699
702
  #obj.fgrid replace with thresholded scalar data.
700
703
  self._objs.append(_AnimObject(field_flat, T, grid, grid_no_nan, actor, on_update))
701
-
704
+ self._animate_next = False
702
705
  self._reset_cbar()
703
706
 
704
707
  def add_boundary_field(self,
@@ -773,13 +776,13 @@ class PVDisplay(BaseDisplay):
773
776
  kwargs = setdefault(kwargs, cmap=cmap, clim=clim, opacity=opacity, pickable=False, multi_colors=True)
774
777
  actor = self._plot.add_mesh(grid, scalars=name, scalar_bar_args=self._cbar_args, **kwargs)
775
778
 
776
- if self._do_animate:
779
+ if self._animate_next:
777
780
  def on_update(obj: _AnimObject, phi: complex):
778
781
  field_anim = obj.T(np.real(obj.field * phi))
779
782
  obj.grid[name] = field_anim
780
783
  #obj.fgrid replace with thresholded scalar data.
781
784
  self._objs.append(_AnimObject(field_flat, T, grid, grid, actor, on_update))
782
-
785
+ self._animate_next = False
783
786
  self._reset_cbar()
784
787
 
785
788
  def add_title(self, title: str) -> None:
@@ -921,7 +924,7 @@ class PVDisplay(BaseDisplay):
921
924
 
922
925
  actor = self._plot.add_mesh(contour, opacity=opacity, cmap=cmap, clim=clim, pickable=False, scalar_bar_args=self._cbar_args)
923
926
 
924
- if self._do_animate:
927
+ if self._animate_next:
925
928
  def on_update(obj: _AnimObject, phi: complex):
926
929
  new_vals = obj.T(np.real(obj.field * phi))
927
930
  obj.grid['anim'] = new_vals
@@ -929,7 +932,7 @@ class PVDisplay(BaseDisplay):
929
932
  obj.actor.GetMapper().SetInputData(new_contour) # type: ignore
930
933
 
931
934
  self._objs.append(_AnimObject(field, T, grid, None, actor, on_update)) # type: ignore
932
-
935
+ self._animate_next = False
933
936
  self._reset_cbar()
934
937
 
935
938
  def _add_aux_items(self) -> None:
@@ -21,6 +21,9 @@ import numpy as np
21
21
  from .cs import Axis, CoordinateSystem, _parse_vector, Plane
22
22
  from typing import Callable, TypeVar, Iterable, Any
23
23
 
24
+ class SelectionError(Exception):
25
+ pass
26
+
24
27
  def align_rectangle_frame(pts3d: np.ndarray, normal: np.ndarray) -> dict[str, Any]:
25
28
  """Tries to find a rectangle as convex-hull of a set of points with a given normal vector.
26
29
 
@@ -174,7 +177,7 @@ class Selection:
174
177
  """
175
178
  dim: int = -1
176
179
  def __init__(self, tags: list[int] | set[int] | tuple[int] | None = None):
177
-
180
+ self.name: str = 'Selection'
178
181
  self._tags: set[int] = set()
179
182
 
180
183
  if tags is not None:
@@ -252,7 +255,19 @@ class Selection:
252
255
  maxy = max(maxy, y1)
253
256
  maxz = max(maxz, z1)
254
257
  return (minx, miny, minz), (maxx, maxy, maxz)
255
-
258
+
259
+ def _named(self, name: str) -> Selection:
260
+ """Sets the name of the selection and returns it
261
+
262
+ Args:
263
+ name (str): The name of the selection
264
+
265
+ Returns:
266
+ Selection: The same selection object
267
+ """
268
+ self.name = name
269
+ return self
270
+
256
271
  def exclude(self, xyz_excl_function: Callable = lambda x,y,z: True, plane: Plane | None = None, axis: Axis | None = None) -> Selection:
257
272
  """Exclude points by evaluating a function(x,y,z)-> bool
258
273
 
@@ -458,7 +458,8 @@ class Simulation:
458
458
  plot_mesh: bool = False,
459
459
  volume_mesh: bool = True,
460
460
  opacity: float | None = None,
461
- labels: bool = False) -> None:
461
+ labels: bool = False,
462
+ face_labels: bool = False) -> None:
462
463
  """View the current geometry in either the BaseDisplay object (PVDisplay only) or
463
464
  the GMSH viewer.
464
465
 
@@ -476,8 +477,13 @@ class Simulation:
476
477
  return
477
478
  for geo in self.state.current_geo_state:
478
479
  self.display.add_object(geo, mesh=plot_mesh, opacity=opacity, volume_mesh=volume_mesh, label=labels)
480
+
481
+ if face_labels and geo.dim==3:
482
+ for face_name in geo._face_pointers.keys():
483
+ self.display.add_object(geo.face(face_name), color='yellow', opacity=0.1, label=face_name)
479
484
  if selections:
480
- [self.display.add_object(sel, color='red', opacity=0.6, label=labels) for sel in selections]
485
+ [self.display.add_object(sel, color='red', opacity=0.6, label=sel.name) for sel in selections]
486
+
481
487
  self.display.show()
482
488
 
483
489
  return None
@@ -688,9 +694,9 @@ class SimulationBeta(Simulation):
688
694
 
689
695
 
690
696
  def __post_init__(self):
691
-
692
- self.mesher.set_algorithm(Algorithm3D.HXT)
693
- logger.debug('Setting mesh algorithm to HXT')
697
+ pass
698
+ #self.mesher.set_algorithm(Algorithm3D.HXT)
699
+ #logger.debug('Setting mesh algorithm to HXT')
694
700
 
695
701
 
696
702
  def _reset_mesh(self):
@@ -706,10 +712,10 @@ class SimulationBeta(Simulation):
706
712
  convergence: float = 0.02,
707
713
  magnitude_convergence: float = 2.0,
708
714
  phase_convergence: float = 180,
709
- refinement_ratio: float = 0.9,
710
- growth_rate: float = 3,
715
+ refinement_ratio: float = 0.6,
716
+ growth_rate: float = 2,
711
717
  minimum_refinement_percentage: float = 20.0,
712
- error_field_inclusion_percentage: float = 5.0,
718
+ error_field_inclusion_percentage: float = 60.0,
713
719
  frequency: float = None,
714
720
  show_mesh: bool = False) -> SimulationDataset:
715
721
  """ A beta-version of adaptive mesh refinement.
@@ -736,7 +742,7 @@ class SimulationBeta(Simulation):
736
742
  SimulationDataset: _description_
737
743
  """
738
744
  from .physics.microwave.adaptive_mesh import select_refinement_indices, reduce_point_set, compute_convergence
739
-
745
+ from collections import defaultdict
740
746
 
741
747
  max_freq = np.max(self.mw.frequencies)
742
748
 
@@ -752,11 +758,18 @@ class SimulationBeta(Simulation):
752
758
 
753
759
  self.state.stash()
754
760
 
761
+ a0 = 0.26
762
+ c0 = 0.75
763
+ x0 = 12
764
+ q0 = (1-a0)*2/np.pi
765
+ b0 = np.tan((c0-a0)/q0)/x0
766
+ q0 = (0.8-a0)*2/np.pi
767
+
755
768
  for step in range(1,max_steps+1):
756
769
 
757
770
  self.data.sim.new(iter_step=step)
758
771
 
759
- data = self.mw._run_adaptive_mesh(step, max_freq)
772
+ data, solve_ids = self.mw._run_adaptive_mesh(step, max_freq)
760
773
 
761
774
  field = data.field[-1]
762
775
 
@@ -775,51 +788,89 @@ class SimulationBeta(Simulation):
775
788
  passed = 0
776
789
 
777
790
  if passed >= min_refined_passes:
778
- logger.info('Adaptive mesh refinement successfull')
791
+ logger.info(f'Adaptive mesh refinement successfull with {self.mesh.n_tets} tetrahedra.')
779
792
  break
780
793
 
781
- error, lengths = field._solution_quality()
794
+ error, lengths = field._solution_quality(solve_ids)
782
795
 
783
796
  idx = select_refinement_indices(error, error_field_inclusion_percentage/100)
784
797
  idx = idx[::-1]
785
798
 
786
- self.mesher.add_refinement_points(self.mw.mesh.centers[:,idx], lengths[idx])
799
+ npts = idx.shape[0]
800
+ np_percentage = npts/self.mesh.n_tets * 100
801
+
802
+ refinement_ratio = (a0 + np.arctan(b0*np_percentage)*q0)
803
+ #calc_refinement_ratio(refinement_throttle, point_percentage)
804
+ logger.info(f'Adding {npts} refinement points with a ratio: {refinement_ratio}')
805
+
806
+ # tet_nodes = defaultdict(lambda: 1000.)
807
+ # for itet in idx:
808
+ # for inode in self.mesh.tets[:,itet]:
809
+ # tet_nodes[inode] = min(tet_nodes[inode], lengths[itet])
810
+
811
+ # N = len(tet_nodes)
812
+ # coords = np.zeros((3,N), dtype=np.float64)
813
+ # sizes = np.zeros((N,), dtype=np.float64)
814
+ # for i, (index, size) in enumerate(tet_nodes.items()):
815
+ # coords[:,i] = self.mesh.nodes[:,index]
816
+ # sizes[i] = size
817
+
818
+ # self.mesher.add_refinement_points(coords, sizes, refinement_ratio*np.ones((N,)))
819
+
820
+ self.mesher.add_refinement_points(self.mw.mesh.centers[:,idx], lengths[idx], refinement_ratio*np.ones_like(lengths[idx]))
787
821
 
788
822
  logger.debug(f'Pass {step}: Adding {len(idx)} new refinement points.')
789
823
 
790
824
  new_ids = reduce_point_set(self.mesher._amr_coords, growth_rate, self.mesher._amr_sizes, refinement_ratio, 0.20)
791
825
 
792
- logger.debug(f'Pass {step}: Removing {self.mesher._amr_coords.shape[1] - len(new_ids)} points from {self.mesher._amr_coords.shape[1]} to {len(new_ids)}')
826
+ nremoved = self.mesher._amr_coords.shape[1] - len(new_ids)
827
+ if nremoved > 0:
828
+ logger.info(f'Cleanup of step {step}: Removing {nremoved} points.')
793
829
 
794
830
  self.mesher._amr_coords = self.mesher._amr_coords[:,new_ids]
795
831
  self.mesher._amr_sizes = self.mesher._amr_sizes[new_ids]
832
+ self.mesher._amr_ratios = self.mesher._amr_ratios[new_ids]
833
+ self.mesher._amr_new = self.mesher._amr_new[new_ids]
796
834
 
835
+ def clip(value: float):
836
+ return max(1.3, value)
837
+
838
+ logger.debug(f'Initial refinement ratio: {refinement_ratio}')
839
+
840
+ over = False
841
+ under = False
842
+ throttle = 1.0
797
843
 
798
844
  while True:
799
845
 
800
- self._reset_mesh()
801
-
802
- logger.debug(f'Pass {step}: Adding {len(idx)} refinement points.')
803
-
804
- self.mesher.set_refinement_function(refinement_ratio, growth_rate, 1.0)
846
+ if over and under:
847
+ throttle *= 2
805
848
 
849
+ self._reset_mesh()
850
+ logger.debug(f'Pass {step}')
851
+ self.mesher.set_refinement_function(growth_rate, 2.0)
806
852
  self.generate_mesh(True)
807
-
808
853
  percentage = (self.mesh.n_tets/last_n_tets - 1) * 100
809
854
  logger.info(f'Pass {step}: New mesh has {self.mesh.n_tets} (+{percentage:.1f}%) tetrahedra.')
810
855
 
811
856
  if percentage < minimum_refinement_percentage:
857
+ F = (2*minimum_refinement_percentage-percentage)/(throttle*minimum_refinement_percentage)
812
858
  logger.debug('Not enough mesh refinement, decreasing mesh size constraint.')
813
- refinement_ratio = refinement_ratio * 0.9
859
+ refinement_ratio = self.mesher.refine_finer(F)
814
860
  logger.debug(f'New refinement ratio: {refinement_ratio}')
861
+ under=True
815
862
  continue
816
-
817
- if percentage > 2*minimum_refinement_percentage and refinement_ratio < 0.99:
863
+ if percentage > (minimum_refinement_percentage*2):
864
+ F = (percentage - minimum_refinement_percentage)/(throttle*minimum_refinement_percentage)
818
865
  logger.debug('Too much mesh refinement, decreasing mesh size constraint.')
819
- refinement_ratio = refinement_ratio ** (1-np.log(percentage/minimum_refinement_percentage)/4)
866
+ refinement_ratio = self.mesher.refine_coarser(F)
820
867
  logger.debug(f'New refinement ratio: {refinement_ratio}')
868
+ over=True
869
+ continue
821
870
 
822
-
871
+ over = False
872
+ under = False
873
+ throttle = 1.0
823
874
  last_n_tets = self.mesh.n_tets
824
875
  break
825
876
 
emerge/_emerge/solver.py CHANGED
@@ -209,7 +209,7 @@ def filter_real_modes(eigvals: np.ndarray, eigvecs: np.ndarray,
209
209
  filtered_vals = eigvals[mask]
210
210
  filtered_vecs = eigvecs[:, mask]
211
211
  k0vals = np.sqrt(sign*filtered_vals)
212
- order = np.argsort(np.abs(k0vals))# ascending distance
212
+ order = np.argsort(np.abs(k0vals)) # ascending distance
213
213
  filtered_vals = filtered_vals[order] # reorder eigenvalues
214
214
  filtered_vecs = filtered_vecs[:, order]
215
215
  return filtered_vals, filtered_vecs
@@ -1282,7 +1282,7 @@ class SolveRoutine:
1282
1282
  NF = A.shape[0]
1283
1283
  NS = solve_ids.shape[0]
1284
1284
 
1285
- logger.debug(self.pre + f'Removing {NF-NS} prescribed DOFs ({NS} left)')
1285
+ logger.debug(self.pre + f' Removing {NF-NS} prescribed DOFs ({NS} left)')
1286
1286
 
1287
1287
  Asel = A[np.ix_(solve_ids, solve_ids)]
1288
1288
  Bsel = B[np.ix_(solve_ids, solve_ids)]
@@ -1325,7 +1325,7 @@ class SolveRoutine:
1325
1325
  NF = A.shape[0]
1326
1326
  NS = solve_ids.shape[0]
1327
1327
 
1328
- logger.debug(self.pre + f'Removing {NF-NS} prescribed DOFs ({NS} left)')
1328
+ logger.debug(self.pre + f' Removing {NF-NS} prescribed DOFs ({NS} left)')
1329
1329
 
1330
1330
  Asel = A[np.ix_(solve_ids, solve_ids)]
1331
1331
  Bsel = B[np.ix_(solve_ids, solve_ids)]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emerge
3
- Version: 1.1.0
3
+ Version: 1.1.1
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