pyedb 0.30.0__py3-none-any.whl → 0.34.0__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 pyedb might be problematic. Click here for more details.

@@ -193,6 +193,19 @@ class ControlFileLayer:
193
193
  content.set("Thickness", self.properties.get("Thickness", "0.001"))
194
194
  if self.properties.get("Type"):
195
195
  content.set("Type", self.properties.get("Type", "conductor"))
196
+ if self.properties.get("ConvertPolygonToCircle"):
197
+ content.set("ConvertPolygonToCircle", self.properties["ConvertPolygonToCircle"])
198
+ if self.properties.get("ConvertPolygonToCircleRatio"):
199
+ content.set("ConvertPolygonToCircleRatio", self.properties["ConvertPolygonToCircleRatio"])
200
+ if self.properties.get("ReconstructArcs"):
201
+ content.set("ReconstructArcs", self.properties["ReconstructArcs"])
202
+ if self.properties.get("ArcTolerance"):
203
+ content.set("ArcTolerance", self.properties["ArcTolerance"])
204
+ if self.properties.get("UnionPrimitives"):
205
+ content.set("UnionPrimitives", self.properties["UnionPrimitives"])
206
+ # To confirm syntax with development
207
+ if self.properties.get("DefeatureMinTraceWidth"):
208
+ content.set("DefeatureMinTraceWidth", self.properties["DefeatureMinTraceWidth"])
196
209
 
197
210
 
198
211
  class ControlFileVia(ControlFileLayer):
@@ -226,6 +239,14 @@ class ControlFileVia(ControlFileLayer):
226
239
  content.set("Thickness", self.properties.get("Thickness", "0.001"))
227
240
  if self.properties.get("Type"):
228
241
  content.set("Type", self.properties.get("Type", "conductor"))
242
+ if self.properties.get("ConvertPolygonToCircle"):
243
+ content.set("ConvertPolygonToCircle", self.properties["ConvertPolygonToCircle"])
244
+ if self.properties.get("ConvertPolygonToCircleRatio"):
245
+ content.set("ConvertPolygonToCircleRatio", self.properties["ConvertPolygonToCircleRatio"])
246
+ if self.properties.get("ReconstructArcs"):
247
+ content.set("ReconstructArcs", self.properties["ReconstructArcs"])
248
+ if self.properties.get("ArcTolerance"):
249
+ content.set("ArcTolerance", self.properties["ArcTolerance"])
229
250
  if self.create_via_group:
230
251
  viagroup = ET.SubElement(content, "CreateViaGroups")
231
252
  viagroup.set("CheckContainment", "true" if self.check_containment else "false")
@@ -113,8 +113,9 @@ class EDBNetsData(NetDotNet):
113
113
  show_legend=True,
114
114
  save_plot=None,
115
115
  outline=None,
116
- size=(2000, 1000),
116
+ size=(6000, 3000),
117
117
  show=True,
118
+ plot_vias=True,
118
119
  ):
119
120
  """Plot a net to Matplotlib 2D chart.
120
121
 
@@ -134,6 +135,9 @@ class EDBNetsData(NetDotNet):
134
135
  Image size in pixel (width, height).
135
136
  show : bool, optional
136
137
  Whether to show the plot or not. Default is `True`.
138
+ plot_vias : bool, optional
139
+ Whether to plot vias or not. It may impact on performances.
140
+ Default is `True`.
137
141
  """
138
142
 
139
143
  return self._app.nets.plot(
@@ -144,6 +148,7 @@ class EDBNetsData(NetDotNet):
144
148
  outline=outline,
145
149
  size=size,
146
150
  show=show,
151
+ plot_vias=plot_vias,
147
152
  )
148
153
 
149
154
  def get_smallest_trace_width(self):
@@ -411,17 +411,6 @@ class EDBPadstack(object):
411
411
  >>> edb_padstack = edb.padstacks.definitions["MyPad"]
412
412
  """
413
413
 
414
- PAD_SHAPE_PARAMETERS = {
415
- "circle": ["diameter"],
416
- "square": ["size"],
417
- "rectangle": ["x_size", "y_size"],
418
- "oval": ["x_size", "y_size", "corner_radius"],
419
- "bullet": ["x_size", "y_size", "corner_radius"],
420
- "round45": ["inner", "channel_width", "isolation_gap"],
421
- "round90": ["inner", "channel_width", "isolation_gap"],
422
- "no_geometry": [],
423
- }
424
-
425
414
  def __init__(self, edb_padstack, ppadstack):
426
415
  self._edb_object = edb_padstack
427
416
  self.edb_padstack = edb_padstack
@@ -468,175 +457,6 @@ class EDBPadstack(object):
468
457
  def _padstack_def_data(self, value):
469
458
  self._edb_object.SetData(value)
470
459
 
471
- @property
472
- def pad_parameters(self) -> dict:
473
- """Pad parameters.
474
-
475
- Returns
476
- -------
477
- dict
478
- params = {
479
- 'regular_pad': [
480
- {'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0.1mm', 'offset_y': '0', 'rotation': '0',
481
- 'diameter': '0.5mm'}
482
- ],
483
- 'anti_pad': [
484
- {'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
485
- 'diameter': '1mm'}
486
- ],
487
- 'thermal_pad': [
488
- {'layer_name': '1_Top', 'shape': 'round90', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
489
- 'inner': '1mm', 'channel_width': '0.2mm', 'isolation_gap': '0.3mm'},
490
- ],
491
- 'hole': [
492
- {'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
493
- 'diameter': '0.1499997mm'},
494
- ]
495
- }
496
- """
497
- pdef_data = self._padstack_def_data
498
- pad_type_list = [
499
- self._ppadstack._pedb._edb.Definition.PadType.RegularPad,
500
- self._ppadstack._pedb._edb.Definition.PadType.AntiPad,
501
- self._ppadstack._pedb._edb.Definition.PadType.ThermalPad,
502
- # self._ppadstack._pedb._edb.Definition.PadType.Hole,
503
- # This property doesn't appear in UI. It is unclear what it is used for. Suppressing this property for now.
504
- ]
505
- data = {}
506
- for pad_type in pad_type_list:
507
- pad_type_name = pascal_to_snake(pad_type.ToString())
508
- temp_list = []
509
- for lyr_name in list(pdef_data.GetLayerNames()):
510
- result = pdef_data.GetPadParametersValue(lyr_name, pad_type)
511
- _, pad_shape, params, offset_x, offset_y, rotation = result
512
- pad_shape = pascal_to_snake(pad_shape.ToString())
513
-
514
- pad_params = {}
515
- pad_params["layer_name"] = lyr_name
516
- pad_params["shape"] = pad_shape
517
- pad_params["offset_x"] = offset_x.ToString()
518
- pad_params["offset_y"] = offset_y.ToString()
519
- pad_params["rotation"] = rotation.ToString()
520
-
521
- for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[pad_shape]):
522
- pad_params[i] = params[idx].ToString()
523
- temp_list.append(pad_params)
524
- data[pad_type_name] = temp_list
525
- return data
526
-
527
- @pad_parameters.setter
528
- def pad_parameters(self, params: dict):
529
- original_params = self.pad_parameters
530
- pdef_data = self._padstack_def_data
531
-
532
- pad_type_list = [
533
- self._ppadstack._pedb._edb.Definition.PadType.RegularPad,
534
- self._ppadstack._pedb._edb.Definition.PadType.AntiPad,
535
- self._ppadstack._pedb._edb.Definition.PadType.ThermalPad,
536
- self._ppadstack._pedb._edb.Definition.PadType.Hole,
537
- ]
538
- for pad_type in pad_type_list:
539
- pad_type_name = pascal_to_snake(pad_type.ToString())
540
- rpp = params.get(pad_type_name, [])
541
- for idx, layer_data in enumerate(rpp):
542
- # Get geometry type from kwargs
543
- p = layer_data.get("shape")
544
- temp_param = []
545
-
546
- # Handle Circle geometry type
547
- if p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Circle.ToString()):
548
- temp_param.append(layer_data["diameter"])
549
- pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Circle
550
-
551
- # Handle Square geometry type
552
- elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Square.ToString()):
553
- temp_param.append(layer_data["size"])
554
- pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Square
555
-
556
- elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Rectangle.ToString()):
557
- temp_param.append(layer_data["x_size"])
558
- temp_param.append(layer_data["y_size"])
559
- pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Rectangle
560
-
561
- # Handle Oval geometry type
562
- elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Oval.ToString()):
563
- temp_param.append(layer_data["x_size"])
564
- temp_param.append(layer_data["y_size"])
565
- temp_param.append(layer_data["corner_radius"])
566
- pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Oval
567
-
568
- # Handle Bullet geometry type
569
- elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Bullet.ToString()):
570
- temp_param.append(layer_data["x_size"])
571
- temp_param.append(layer_data["y_size"])
572
- temp_param.append(layer_data["corner_radius"])
573
- pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Bullet
574
-
575
- # Handle Round45 geometry type
576
- elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Round45.ToString()):
577
- temp_param.append(layer_data["inner"])
578
- temp_param.append(layer_data["channel_width"])
579
- temp_param.append(layer_data["isolation_gap"])
580
- pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Round45
581
-
582
- # Handle Round90 geometry type
583
- elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Round90.ToString()):
584
- temp_param.append(layer_data["inner"])
585
- temp_param.append(layer_data["channel_width"])
586
- temp_param.append(layer_data["isolation_gap"])
587
- pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Round90
588
- elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.NoGeometry.ToString()):
589
- continue
590
-
591
- # Set pad parameters for the current layer
592
- pdef_data.SetPadParameters(
593
- layer_data["layer_name"],
594
- pad_type,
595
- pad_shape,
596
- convert_py_list_to_net_list([self._ppadstack._pedb.edb_value(i) for i in temp_param]),
597
- self._ppadstack._pedb.edb_value(layer_data.get("offset_x", 0)),
598
- self._ppadstack._pedb.edb_value(layer_data.get("offset_y", 0)),
599
- self._ppadstack._pedb.edb_value(layer_data.get("rotation", 0)),
600
- )
601
- self._padstack_def_data = pdef_data
602
-
603
- @property
604
- def hole_parameters(self):
605
- pdef_data = self._padstack_def_data
606
- _, hole_shape, params, offset_x, offset_y, rotation = pdef_data.GetHoleParametersValue()
607
- hole_shape = pascal_to_snake(hole_shape.ToString())
608
-
609
- hole_params = {}
610
- hole_params["shape"] = hole_shape
611
- for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[hole_shape]):
612
- hole_params[i] = params[idx].ToString()
613
- hole_params["offset_x"] = offset_x.ToString()
614
- hole_params["offset_y"] = offset_y.ToString()
615
- hole_params["rotation"] = rotation.ToString()
616
- return hole_params
617
-
618
- @hole_parameters.setter
619
- def hole_parameters(self, params: dict):
620
- original_params = self.hole_parameters
621
- pdef_data = self._padstack_def_data
622
-
623
- temp_param = []
624
- shape = params["shape"]
625
- if shape == "no_geometry":
626
- return # .net api doesn't tell how to set no_geometry shape.
627
- for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[shape]):
628
- temp_param.append(params[i])
629
- pedb_shape = getattr(self._ppadstack._pedb._edb.Definition.PadGeometryType, snake_to_pascal(shape))
630
-
631
- pdef_data.SetHoleParameters(
632
- pedb_shape,
633
- convert_py_list_to_net_list([self._ppadstack._pedb.edb_value(i) for i in temp_param]),
634
- self._ppadstack._pedb.edb_value(params.get("offset_x", original_params.get("offset_x", 0))),
635
- self._ppadstack._pedb.edb_value(params.get("offset_y", original_params.get("offset_y", 0))),
636
- self._ppadstack._pedb.edb_value(params.get("rotation", original_params.get("rotation", 0))),
637
- )
638
- self._padstack_def_data = pdef_data
639
-
640
460
  @property
641
461
  def instances(self):
642
462
  """Definitions Instances."""
@@ -1322,18 +1142,6 @@ class EDBPadstack(object):
1322
1142
  self.edb_padstack.SetData(new_padstack_data)
1323
1143
  return True
1324
1144
 
1325
- def set_properties(self, **kwargs):
1326
- for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]:
1327
- value = kwargs.get(k, False)
1328
- if value:
1329
- setattr(self, k, value)
1330
-
1331
- def get_properties(self):
1332
- kwargs = {}
1333
- for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]:
1334
- kwargs[k] = getattr(self, k)
1335
- return kwargs
1336
-
1337
1145
 
1338
1146
  class EDBPadstackInstance(Primitive):
1339
1147
  """Manages EDB functionalities for a padstack.
@@ -1583,6 +1391,17 @@ class EDBPadstackInstance(Primitive):
1583
1391
 
1584
1392
  @property
1585
1393
  def padstack_definition(self):
1394
+ """Padstack definition Name.
1395
+
1396
+ Returns
1397
+ -------
1398
+ str
1399
+ Name of the padstack definition.
1400
+ """
1401
+ return self.definition.name
1402
+
1403
+ @property
1404
+ def definition(self):
1586
1405
  """Padstack definition.
1587
1406
 
1588
1407
  Returns
@@ -1590,7 +1409,7 @@ class EDBPadstackInstance(Primitive):
1590
1409
  str
1591
1410
  Name of the padstack definition.
1592
1411
  """
1593
- self._pdef = self._edb_padstackinstance.GetPadstackDef().GetName()
1412
+ self._pdef = EDBPadstack(self._edb_padstackinstance.GetPadstackDef(), self._pedb.padstacks)
1594
1413
  return self._pdef
1595
1414
 
1596
1415
  @property
@@ -1975,6 +1794,10 @@ class EDBPadstackInstance(Primitive):
1975
1794
  name = str(name).strip("'")
1976
1795
  return name
1977
1796
 
1797
+ @aedt_name.setter
1798
+ def aedt_name(self, value):
1799
+ self._edb_object.SetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, value)
1800
+
1978
1801
  def parametrize_position(self, prefix=None):
1979
1802
  """Parametrize the instance position.
1980
1803
 
@@ -2324,15 +2147,3 @@ class EDBPadstackInstance(Primitive):
2324
2147
  max_limit=max_limit,
2325
2148
  component_only=component_only,
2326
2149
  )
2327
-
2328
- @property
2329
- def properties(self):
2330
- data = {}
2331
- data["name"] = self.aedt_name
2332
- data["definition"] = self.padstack_definition
2333
- data["backdrill_parameters"] = self.backdrill_parameters
2334
- _, position, rotation = self._edb_object.GetPositionAndRotationValue()
2335
- data["position"] = [position.X.ToString(), position.Y.ToString()]
2336
- data["rotation"] = [rotation.ToString()]
2337
- data["id"] = self.id
2338
- return data
@@ -29,6 +29,7 @@ from pyedb.dotnet.edb_core.dotnet.primitive import (
29
29
  RectangleDotNet,
30
30
  TextDotNet,
31
31
  )
32
+ from pyedb.dotnet.edb_core.geometry.polygon_data import PolygonData
32
33
  from pyedb.modeler.geometry_operators import GeometryOperators
33
34
 
34
35
 
@@ -305,6 +306,36 @@ class EdbPolygon(Primitive):
305
306
  # prim = point_list
306
307
  # return self.add_void(prim)
307
308
 
309
+ @property
310
+ def polygon_data(self):
311
+ """:class:`pyedb.dotnet.edb_core.dotnet.database.PolygonDataDotNet`: Outer contour of the Polygon object."""
312
+ return PolygonData(self._pedb, self._edb_object.GetPolygonData())
313
+
314
+ @polygon_data.setter
315
+ def polygon_data(self, poly):
316
+ self._edb_object.SetPolygonData(poly._edb_object)
317
+
318
+ def expand(self, offset=0.001, tolerance=1e-12, round_corners=True, maximum_corner_extension=0.001):
319
+ """Expand the polygon shape by an absolute value in all direction.
320
+ Offset can be negative for negative expansion.
321
+
322
+ Parameters
323
+ ----------
324
+ offset : float, optional
325
+ Offset value in meters.
326
+ tolerance : float, optional
327
+ Tolerance in meters.
328
+ round_corners : bool, optional
329
+ Whether to round corners or not.
330
+ If True, use rounded corners in the expansion otherwise use straight edges (can be degenerate).
331
+ maximum_corner_extension : float, optional
332
+ The maximum corner extension (when round corners are not used) at which point the corner is clipped.
333
+ """
334
+ pd = self.polygon_data
335
+ pd.expand(offset, tolerance, round_corners, maximum_corner_extension)
336
+ self.polygon_data = pd
337
+ return pd
338
+
308
339
 
309
340
  class EdbText(Primitive, TextDotNet):
310
341
  def __init__(self, raw_primitive, core_app):
@@ -1168,8 +1168,8 @@ class EdbHfss(object):
1168
1168
  list
1169
1169
  [lower left corner X, lower left corner, upper right corner X, upper right corner Y].
1170
1170
  """
1171
- if layout == None:
1172
- return False
1171
+ if layout is None:
1172
+ layout = self._active_layout
1173
1173
  layout_obj_instances = layout.GetLayoutInstance().GetAllLayoutObjInstances()
1174
1174
  tuple_list = []
1175
1175
  for lobj in layout_obj_instances.Items:
@@ -332,9 +332,7 @@ class LayoutValidation:
332
332
  counts += 1
333
333
  if fix:
334
334
  if not obj.component:
335
- obj._edb_object.SetProductProperty(
336
- self._pedb.edb_api.ProductId.Designer, 11, f"via_{via_count}"
337
- )
335
+ obj._edb_object.SetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, f"Via{via_count}")
338
336
  via_count = via_count + 1
339
337
  else:
340
338
  obj._edb_object.SetProductProperty(
@@ -69,6 +69,7 @@ DC_ATTRIBUTES = [
69
69
  "dc_conductivity",
70
70
  "dc_permittivity",
71
71
  ]
72
+ PERMEABILITY_DEFAULT_VALUE = 1
72
73
 
73
74
 
74
75
  def get_line_float_value(line):
@@ -114,7 +115,6 @@ class Material(object):
114
115
  self.__name: str = material_def.GetName()
115
116
  self.__material_def = material_def
116
117
  self.__dc_model = material_def.GetDielectricMaterialModel()
117
- self.__properties: MaterialProperties = MaterialProperties()
118
118
 
119
119
  @property
120
120
  def name(self):
@@ -130,8 +130,7 @@ class Material(object):
130
130
  def conductivity(self):
131
131
  """Get material conductivity."""
132
132
  material_property_id = self.__edb_definition.MaterialPropertyId.Conductivity
133
- self.__properties.conductivity = self.__property_value(material_property_id)
134
- return self.__properties.conductivity
133
+ return self.__property_value(material_property_id)
135
134
 
136
135
  @conductivity.setter
137
136
  def conductivity(self, value):
@@ -144,8 +143,7 @@ class Material(object):
144
143
  def permittivity(self):
145
144
  """Get material permittivity."""
146
145
  material_property_id = self.__edb_definition.MaterialPropertyId.Permittivity
147
- self.__properties.permittivity = self.__property_value(material_property_id)
148
- return self.__properties.permittivity
146
+ return self.__property_value(material_property_id)
149
147
 
150
148
  @permittivity.setter
151
149
  def permittivity(self, value):
@@ -158,8 +156,7 @@ class Material(object):
158
156
  def permeability(self):
159
157
  """Get material permeability."""
160
158
  material_property_id = self.__edb_definition.MaterialPropertyId.Permeability
161
- self.__properties.permeability = self.__property_value(material_property_id)
162
- return self.__properties.permeability
159
+ return self.__property_value(material_property_id)
163
160
 
164
161
  @permeability.setter
165
162
  def permeability(self, value):
@@ -182,8 +179,7 @@ class Material(object):
182
179
  def dielectric_loss_tangent(self):
183
180
  """Get material loss tangent."""
184
181
  material_property_id = self.__edb_definition.MaterialPropertyId.DielectricLossTangent
185
- self.__properties.dielectric_loss_tangent = self.__property_value(material_property_id)
186
- return self.__properties.dielectric_loss_tangent
182
+ return self.__property_value(material_property_id)
187
183
 
188
184
  @loss_tangent.setter
189
185
  def loss_tangent(self, value):
@@ -205,9 +201,10 @@ class Material(object):
205
201
  @property
206
202
  def dc_conductivity(self):
207
203
  """Get material dielectric conductivity."""
204
+ res = None
208
205
  if self.__dc_model:
209
- self.__properties.dc_conductivity = self.__dc_model.GetDCConductivity()
210
- return self.__properties.dc_conductivity
206
+ res = self.__dc_model.GetDCConductivity()
207
+ return res
211
208
 
212
209
  @dc_conductivity.setter
213
210
  def dc_conductivity(self, value: Union[int, float]):
@@ -220,9 +217,10 @@ class Material(object):
220
217
  @property
221
218
  def dc_permittivity(self):
222
219
  """Get material dielectric relative permittivity"""
220
+ res = None
223
221
  if self.__dc_model:
224
- self.__properties.dc_permittivity = self.__dc_model.GetDCRelativePermitivity()
225
- return self.__properties.dc_permittivity
222
+ res = self.__dc_model.GetDCRelativePermitivity()
223
+ return res
226
224
 
227
225
  @dc_permittivity.setter
228
226
  def dc_permittivity(self, value: Union[int, float]):
@@ -237,9 +235,10 @@ class Material(object):
237
235
  @property
238
236
  def dielectric_model_frequency(self):
239
237
  """Get material frequency in GHz."""
238
+ res = None
240
239
  if self.__dc_model:
241
- self.__properties.dielectric_model_frequency = self.__dc_model.GetFrequency()
242
- return self.__properties.dielectric_model_frequency
240
+ res = self.__dc_model.GetFrequency()
241
+ return res
243
242
 
244
243
  @dielectric_model_frequency.setter
245
244
  def dielectric_model_frequency(self, value: Union[int, float]):
@@ -252,9 +251,10 @@ class Material(object):
252
251
  @property
253
252
  def loss_tangent_at_frequency(self):
254
253
  """Get material loss tangeat at frequency."""
254
+ res = None
255
255
  if self.__dc_model:
256
- self.__properties.loss_tangent_at_frequency = self.__dc_model.GetLossTangentAtFrequency()
257
- return self.__properties.loss_tangent_at_frequency
256
+ res = self.__dc_model.GetLossTangentAtFrequency()
257
+ return res
258
258
 
259
259
  @loss_tangent_at_frequency.setter
260
260
  def loss_tangent_at_frequency(self, value):
@@ -268,9 +268,10 @@ class Material(object):
268
268
  @property
269
269
  def permittivity_at_frequency(self):
270
270
  """Get material relative permittivity at frequency."""
271
+ res = None
271
272
  if self.__dc_model:
272
- self.__properties.permittivity_at_frequency = self.__dc_model.GetRelativePermitivityAtFrequency()
273
- return self.__properties.permittivity_at_frequency
273
+ res = self.__dc_model.GetRelativePermitivityAtFrequency()
274
+ return res
274
275
 
275
276
  @permittivity_at_frequency.setter
276
277
  def permittivity_at_frequency(self, value: Union[int, float]):
@@ -284,8 +285,7 @@ class Material(object):
284
285
  def magnetic_loss_tangent(self):
285
286
  """Get material magnetic loss tangent."""
286
287
  material_property_id = self.__edb_definition.MaterialPropertyId.MagneticLossTangent
287
- self.__properties.magnetic_loss_tangent = self.__property_value(material_property_id)
288
- return self.__properties.magnetic_loss_tangent
288
+ return self.__property_value(material_property_id)
289
289
 
290
290
  @magnetic_loss_tangent.setter
291
291
  def magnetic_loss_tangent(self, value):
@@ -298,8 +298,7 @@ class Material(object):
298
298
  def thermal_conductivity(self):
299
299
  """Get material thermal conductivity."""
300
300
  material_property_id = self.__edb_definition.MaterialPropertyId.ThermalConductivity
301
- self.__properties.thermal_conductivity = self.__property_value(material_property_id)
302
- return self.__properties.thermal_conductivity
301
+ return self.__property_value(material_property_id)
303
302
 
304
303
  @thermal_conductivity.setter
305
304
  def thermal_conductivity(self, value):
@@ -312,8 +311,7 @@ class Material(object):
312
311
  def mass_density(self):
313
312
  """Get material mass density."""
314
313
  material_property_id = self.__edb_definition.MaterialPropertyId.MassDensity
315
- self.__properties.mass_density = self.__property_value(material_property_id)
316
- return self.__properties.mass_density
314
+ return self.__property_value(material_property_id)
317
315
 
318
316
  @mass_density.setter
319
317
  def mass_density(self, value):
@@ -326,8 +324,7 @@ class Material(object):
326
324
  def youngs_modulus(self):
327
325
  """Get material youngs modulus."""
328
326
  material_property_id = self.__edb_definition.MaterialPropertyId.YoungsModulus
329
- self.__properties.youngs_modulus = self.__property_value(material_property_id)
330
- return self.__properties.youngs_modulus
327
+ return self.__property_value(material_property_id)
331
328
 
332
329
  @youngs_modulus.setter
333
330
  def youngs_modulus(self, value):
@@ -340,8 +337,7 @@ class Material(object):
340
337
  def specific_heat(self):
341
338
  """Get material specific heat."""
342
339
  material_property_id = self.__edb_definition.MaterialPropertyId.SpecificHeat
343
- self.__properties.specific_heat = self.__property_value(material_property_id)
344
- return self.__properties.specific_heat
340
+ return self.__property_value(material_property_id)
345
341
 
346
342
  @specific_heat.setter
347
343
  def specific_heat(self, value):
@@ -354,8 +350,7 @@ class Material(object):
354
350
  def poisson_ratio(self):
355
351
  """Get material poisson ratio."""
356
352
  material_property_id = self.__edb_definition.MaterialPropertyId.PoissonsRatio
357
- self.__properties.poisson_ratio = self.__property_value(material_property_id)
358
- return self.__properties.poisson_ratio
353
+ return self.__property_value(material_property_id)
359
354
 
360
355
  @poisson_ratio.setter
361
356
  def poisson_ratio(self, value):
@@ -368,8 +363,7 @@ class Material(object):
368
363
  def thermal_expansion_coefficient(self):
369
364
  """Get material thermal coefficient."""
370
365
  material_property_id = self.__edb_definition.MaterialPropertyId.ThermalExpansionCoefficient
371
- self.__properties.thermal_expansion_coefficient = self.__property_value(material_property_id)
372
- return self.__properties.thermal_expansion_coefficient
366
+ return self.__property_value(material_property_id)
373
367
 
374
368
  @thermal_expansion_coefficient.setter
375
369
  def thermal_expansion_coefficient(self, value):
@@ -380,10 +374,10 @@ class Material(object):
380
374
 
381
375
  def to_dict(self):
382
376
  """Convert material into dictionary."""
383
- self.__load_all_properties()
377
+ properties = self.__load_all_properties()
384
378
 
385
379
  res = {"name": self.name}
386
- res.update(self.__properties.model_dump())
380
+ res.update(properties.model_dump())
387
381
  return res
388
382
 
389
383
  def update(self, input_dict: dict):
@@ -419,10 +413,13 @@ class Material(object):
419
413
  """
420
414
  return self.__edb.edb_value(value)
421
415
 
422
- def __load_all_properties(self):
416
+ def __load_all_properties(self) -> MaterialProperties:
423
417
  """Load all properties of the material."""
424
- for property in self.__properties.model_dump().keys():
425
- _ = getattr(self, property)
418
+ res = MaterialProperties()
419
+ for property in res.model_dump().keys():
420
+ value = getattr(self, property)
421
+ setattr(res, property, value)
422
+ return res
426
423
 
427
424
  def __property_value(self, material_property_id):
428
425
  """Get property value from a material property id."""
@@ -507,6 +504,9 @@ class Materials(object):
507
504
 
508
505
  material_def = self.__edb_definition.MaterialDef.Create(self.__edb.active_db, name)
509
506
  material = Material(self.__edb, material_def)
507
+ # Apply default values to the material
508
+ if "permeability" not in kwargs:
509
+ kwargs["permeability"] = PERMEABILITY_DEFAULT_VALUE
510
510
  attributes_input_dict = {key: val for (key, val) in kwargs.items() if key in ATTRIBUTES + DC_ATTRIBUTES}
511
511
  if "loss_tangent" in kwargs: # pragma: no cover
512
512
  warnings.warn(
@@ -188,7 +188,10 @@ class Modeler(object):
188
188
  for lay in self._pedb.stackup.non_stackup_layers:
189
189
  _primitives_by_layer[lay] = []
190
190
  for i in self._layout.primitives:
191
- lay = i.layer.name
191
+ layer = i.layer
192
+ if not layer:
193
+ continue
194
+ lay = layer.name
192
195
  if lay in _primitives_by_layer:
193
196
  _primitives_by_layer[lay].append(i)
194
197
  return _primitives_by_layer