pyedb 0.7.0__py3-none-any.whl → 0.8.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.

Files changed (46) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/dotnet/clr_module.py +1 -1
  3. pyedb/dotnet/edb.py +7 -7
  4. pyedb/dotnet/edb_core/cell/hierarchy/model.py +1 -1
  5. pyedb/dotnet/edb_core/components.py +15 -12
  6. pyedb/dotnet/edb_core/configuration.py +232 -25
  7. pyedb/dotnet/edb_core/definition/component_def.py +10 -1
  8. pyedb/dotnet/edb_core/definition/component_model.py +1 -1
  9. pyedb/dotnet/edb_core/definition/definition_obj.py +1 -1
  10. pyedb/dotnet/edb_core/definition/definitions.py +8 -2
  11. pyedb/dotnet/edb_core/definition/package_def.py +61 -15
  12. pyedb/dotnet/edb_core/dotnet/database.py +5 -4
  13. pyedb/dotnet/edb_core/edb_data/components_data.py +3 -2
  14. pyedb/dotnet/edb_core/edb_data/connectable.py +1 -1
  15. pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +14 -13
  16. pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +2 -2
  17. pyedb/dotnet/edb_core/edb_data/layer_data.py +9 -3
  18. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +6 -5
  19. pyedb/dotnet/edb_core/edb_data/primitives_data.py +16 -13
  20. pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +7 -1
  21. pyedb/dotnet/edb_core/edb_data/sources.py +10 -0
  22. pyedb/dotnet/edb_core/geometry/__init__.py +0 -0
  23. pyedb/dotnet/edb_core/{edb_data/obj_base.py → geometry/point_data.py} +12 -26
  24. pyedb/dotnet/edb_core/geometry/polygon_data.py +77 -0
  25. pyedb/dotnet/edb_core/layout.py +59 -0
  26. pyedb/dotnet/edb_core/materials.py +715 -597
  27. pyedb/dotnet/edb_core/nets.py +3 -3
  28. pyedb/dotnet/edb_core/obj_base.py +94 -0
  29. pyedb/dotnet/edb_core/padstack.py +57 -6
  30. pyedb/dotnet/edb_core/siwave.py +11 -4
  31. pyedb/dotnet/edb_core/stackup.py +152 -131
  32. pyedb/dotnet/edb_core/utilities/__init__.py +3 -0
  33. pyedb/dotnet/edb_core/utilities/heatsink.py +69 -0
  34. pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py +46 -0
  35. pyedb/edb_logger.py +15 -1
  36. pyedb/exceptions.py +6 -0
  37. pyedb/generic/filesystem.py +7 -3
  38. pyedb/generic/general_methods.py +4 -0
  39. pyedb/generic/process.py +4 -1
  40. pyedb/generic/settings.py +30 -8
  41. pyedb/siwave.py +50 -1
  42. {pyedb-0.7.0.dist-info → pyedb-0.8.0.dist-info}/METADATA +31 -53
  43. {pyedb-0.7.0.dist-info → pyedb-0.8.0.dist-info}/RECORD +46 -39
  44. /pyedb/dotnet/edb_core/{edb_data → utilities}/simulation_setup.py +0 -0
  45. {pyedb-0.7.0.dist-info → pyedb-0.8.0.dist-info}/LICENSE +0 -0
  46. {pyedb-0.7.0.dist-info → pyedb-0.8.0.dist-info}/WHEEL +0 -0
@@ -26,450 +26,536 @@ import difflib
26
26
  import logging
27
27
  import os
28
28
  import re
29
+ from typing import Optional, Union
29
30
  import warnings
30
31
 
32
+ from pydantic import BaseModel, confloat
33
+
34
+ from pyedb import Edb
31
35
  from pyedb.dotnet.clr_module import _clr
32
36
  from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
37
+ from pyedb.exceptions import MaterialModelException
33
38
  from pyedb.generic.general_methods import is_ironpython, pyedb_function_handler
34
39
 
35
40
  logger = logging.getLogger(__name__)
36
41
 
42
+ # TODO: Once we are Python3.9+ change PositiveInt implementation like
43
+ # from annotated_types import Gt
44
+ # from typing_extensions import Annotated
45
+ # PositiveFloat = Annotated[float, Gt(0)]
46
+ try:
47
+ from annotated_types import Gt
48
+ from typing_extensions import Annotated
49
+
50
+ PositiveFloat = Annotated[float, Gt(0)]
51
+ except:
52
+ PositiveFloat = confloat(gt=0)
53
+
54
+ ATTRIBUTES = [
55
+ "conductivity",
56
+ "dielectric_loss_tangent",
57
+ "magnetic_loss_tangent",
58
+ "mass_density",
59
+ "permittivity",
60
+ "permeability",
61
+ "poisson_ratio",
62
+ "specific_heat",
63
+ "thermal_conductivity",
64
+ "youngs_modulus",
65
+ "thermal_expansion_coefficient",
66
+ ]
67
+ DC_ATTRIBUTES = [
68
+ "dielectric_model_frequency",
69
+ "loss_tangent_at_frequency",
70
+ "permittivity_at_frequency",
71
+ "dc_conductivity",
72
+ "dc_permittivity",
73
+ ]
74
+
75
+
76
+ def get_line_float_value(line):
77
+ """Retrieve the float value expected in the line of an AMAT file.
78
+
79
+ The associated string is expected to follow one of the following cases:
80
+ - simple('permittivity', 12.)
81
+ - permittivity='12'.
82
+ """
83
+ try:
84
+ return float(re.split(",|=", line)[-1].strip("'\n)"))
85
+ except ValueError:
86
+ return None
87
+
88
+
89
+ class MaterialProperties(BaseModel):
90
+ """Store material properties."""
91
+
92
+ conductivity: Optional[PositiveFloat] = None
93
+ dielectric_loss_tangent: Optional[PositiveFloat] = None
94
+ magnetic_loss_tangent: Optional[PositiveFloat] = None
95
+ mass_density: Optional[PositiveFloat] = None
96
+ permittivity: Optional[PositiveFloat] = None
97
+ permeability: Optional[PositiveFloat] = None
98
+ poisson_ratio: Optional[PositiveFloat] = None
99
+ specific_heat: Optional[PositiveFloat] = None
100
+ thermal_conductivity: Optional[PositiveFloat] = None
101
+ youngs_modulus: Optional[PositiveFloat] = None
102
+ thermal_expansion_coefficient: Optional[PositiveFloat] = None
103
+ dc_conductivity: Optional[PositiveFloat] = None
104
+ dc_permittivity: Optional[PositiveFloat] = None
105
+ dielectric_model_frequency: Optional[PositiveFloat] = None
106
+ loss_tangent_at_frequency: Optional[PositiveFloat] = None
107
+ permittivity_at_frequency: Optional[PositiveFloat] = None
108
+
37
109
 
38
110
  class Material(object):
39
- """Manages EDB methods for material property management."""
40
-
41
- def __init__(self, pclass, edb_material_def):
42
- self._pclass = pclass
43
- self._name = edb_material_def.GetName()
44
- self._edb_material_def = edb_material_def
45
- self._conductivity = 0.0
46
- self._loss_tangent = 0.0
47
- self._magnetic_loss_tangent = 0.0
48
- self._mass_density = 0.0
49
- self._permittivity = 0.0
50
- self._permeability = 0.0
51
- self._poisson_ratio = 0.0
52
- self._specific_heat = 0.0
53
- self._thermal_conductivity = 0.0
54
- self._youngs_modulus = 0.0
55
- self._thermal_expansion_coefficient = 0.0
56
- self._dc_conductivity = 0.0
57
- self._dc_permittivity = 0.0
58
- self._dielectric_model_frequency = 0.0
59
- self._loss_tangent_at_frequency = 0.0
60
- self._permittivity_at_frequency = 0.0
61
-
62
- def _edb_value(self, value):
63
- return self._pclass._edb_value(value)
111
+ """Manage EDB methods for material property management."""
64
112
 
65
- @property
66
- def name(self):
67
- """Retrieve material name."""
68
- return self._name
113
+ def __init__(self, edb: Edb, material_def):
114
+ self.__edb: Edb = edb
115
+ self.__edb_definition = edb.edb_api.definition
116
+ self.__name: str = material_def.GetName()
117
+ self.__material_def = material_def
118
+ self.__dc_model = material_def.GetDielectricMaterialModel()
119
+ self.__properties: MaterialProperties = MaterialProperties()
69
120
 
70
121
  @property
71
- def _db(self):
72
- return self._pclass._db
122
+ def name(self):
123
+ """Material name."""
124
+ return self.__name
73
125
 
74
126
  @property
75
- def _edb(self):
76
- return self._pclass._edb
77
-
78
- @pyedb_function_handler()
79
- def _get_property(self, property_name):
80
- if is_ironpython: # pragma: no cover
81
- property_box = _clr.StrongBox[float]()
82
- self._edb_material_def.GetProperty(property_name, property_box)
83
- return float(property_box)
84
- else:
85
- _, property_box = self._edb_material_def.GetProperty(property_name)
86
- if isinstance(property_box, float):
87
- return property_box
88
- else:
89
- return property_box.ToDouble()
127
+ def dc_model(self):
128
+ """Material dielectric model."""
129
+ return self.__dc_model
90
130
 
91
131
  @property
92
132
  def conductivity(self):
93
- material_id = self._edb.definition.MaterialPropertyId.Conductivity
94
- self._conductivity = self._get_property(material_id)
95
- return self._conductivity
133
+ """Get material conductivity."""
134
+ if self.__properties.conductivity is None:
135
+ material_property_id = self.__edb_definition.MaterialPropertyId.Conductivity
136
+ self.__properties.conductivity = self.__property_value(material_property_id)
137
+ return self.__properties.conductivity
96
138
 
97
139
  @conductivity.setter
98
140
  def conductivity(self, value):
99
- """Retrieve material conductivity."""
100
- material_id = self._edb.definition.MaterialPropertyId.Conductivity
101
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
102
- self._conductivity = value
141
+ """Set material conductivity."""
142
+ edb_value = self.__edb_value(value)
143
+ material_property_id = self.__edb_definition.MaterialPropertyId.Conductivity
144
+ self.__material_def.SetProperty(material_property_id, self.__edb_value(value))
145
+ self.__properties.conductivity = edb_value.ToDouble()
103
146
 
104
147
  @property
105
148
  def permittivity(self):
106
- """Retrieve material permittivity."""
107
- material_id = self._edb.definition.MaterialPropertyId.Permittivity
108
- self._permittivity = self._get_property(material_id)
109
- return self._permittivity
149
+ """Get material permittivity."""
150
+ if self.__properties.permittivity is None:
151
+ material_property_id = self.__edb_definition.MaterialPropertyId.Permittivity
152
+ self.__properties.permittivity = self.__property_value(material_property_id)
153
+ return self.__properties.permittivity
110
154
 
111
155
  @permittivity.setter
112
156
  def permittivity(self, value):
113
- material_id = self._edb.definition.MaterialPropertyId.Permittivity
114
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
115
- self._permittivity = value
157
+ """Set material permittivity."""
158
+ edb_value = self.__edb_value(value)
159
+ material_property_id = self.__edb_definition.MaterialPropertyId.Permittivity
160
+ self.__material_def.SetProperty(material_property_id, edb_value)
161
+ self.__properties.permittivity = edb_value.ToDouble()
116
162
 
117
163
  @property
118
164
  def permeability(self):
119
- """Retrieve material permeability."""
120
- material_id = self._edb.definition.MaterialPropertyId.Permeability
121
- self._permeability = self._get_property(material_id)
122
- return self._permeability
165
+ """Get material permeability."""
166
+ if self.__properties.permeability is None:
167
+ material_property_id = self.__edb_definition.MaterialPropertyId.Permeability
168
+ self.__properties.permeability = self.__property_value(material_property_id)
169
+ return self.__properties.permeability
123
170
 
124
171
  @permeability.setter
125
172
  def permeability(self, value):
126
- material_id = self._edb.definition.MaterialPropertyId.Permeability
127
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
128
- self._permeability = value
173
+ """Set material permeability."""
174
+ edb_value = self.__edb_value(value)
175
+ material_property_id = self.__edb_definition.MaterialPropertyId.Permeability
176
+ self.__material_def.SetProperty(material_property_id, edb_value)
177
+ self.__properties.permeability = edb_value.ToDouble()
129
178
 
130
179
  @property
131
180
  def loss_tangent(self):
132
- """Retrieve material loss tangent."""
133
- material_id = self._edb.definition.MaterialPropertyId.DielectricLossTangent
134
- self._loss_tangent = self._get_property(material_id)
135
- return self._loss_tangent
181
+ """Get material loss tangent."""
182
+ warnings.warn(
183
+ "This method is deprecated in versions >0.7.0 and will soon be removed. "
184
+ "Use property dielectric_loss_tangent instead.",
185
+ DeprecationWarning,
186
+ )
187
+
188
+ return self.dielectric_loss_tangent
189
+
190
+ @property
191
+ def dielectric_loss_tangent(self):
192
+ """Get material loss tangent."""
193
+ if self.__properties.dielectric_loss_tangent is None:
194
+ material_property_id = self.__edb_definition.MaterialPropertyId.DielectricLossTangent
195
+ self.__properties.dielectric_loss_tangent = self.__property_value(material_property_id)
196
+ return self.__properties.dielectric_loss_tangent
136
197
 
137
198
  @loss_tangent.setter
138
199
  def loss_tangent(self, value):
139
- material_id = self._edb.definition.MaterialPropertyId.DielectricLossTangent
140
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
141
- self._loss_tangent = value
200
+ """Set material loss tangent."""
201
+ warnings.warn(
202
+ "This method is deprecated in versions >0.7.0 and will soon be removed. "
203
+ "Use property dielectric_loss_tangent instead.",
204
+ DeprecationWarning,
205
+ )
206
+
207
+ return self.dielectric_loss_tangent(value)
208
+
209
+ @dielectric_loss_tangent.setter
210
+ def dielectric_loss_tangent(self, value):
211
+ """Set material loss tangent."""
212
+ edb_value = self.__edb_value(value)
213
+ material_property_id = self.__edb_definition.MaterialPropertyId.DielectricLossTangent
214
+ self.__material_def.SetProperty(material_property_id, edb_value)
215
+ self.__properties.dielectric_loss_tangent = edb_value.ToDouble()
142
216
 
143
217
  @property
144
218
  def dc_conductivity(self):
145
- """"""
146
- if self._edb_material_def.GetDielectricMaterialModel():
147
- return self._edb_material_def.GetDielectricMaterialModel().GetDCConductivity()
219
+ """Get material dielectric conductivity."""
220
+ if self.__dc_model and self.__properties.dc_conductivity is None:
221
+ self.__properties.dc_conductivity = self.__dc_model.GetDCConductivity()
222
+ return self.__properties.dc_conductivity
148
223
 
149
224
  @dc_conductivity.setter
150
- def dc_conductivity(self, value):
151
- if self._edb_material_def.GetDielectricMaterialModel():
152
- self._edb_material_def.GetDielectricMaterialModel().SetDCConductivity(value)
225
+ def dc_conductivity(self, value: Union[int, float]):
226
+ """Set material dielectric conductivity."""
227
+ if self.__dc_model:
228
+ self.__dc_model.SetDCConductivity(value)
229
+ self.__properties.dc_conductivity = value
153
230
 
154
231
  @property
155
232
  def dc_permittivity(self):
156
- """"""
157
- if self._edb_material_def.GetDielectricMaterialModel():
158
- return self._edb_material_def.GetDielectricMaterialModel().GetDCRelativePermitivity()
233
+ """Get material dielectric relative permittivity"""
234
+ if self.__dc_model and self.__properties.dc_permittivity is None:
235
+ self.__properties.dc_permittivity = self.__dc_model.GetDCRelativePermitivity()
236
+ return self.__properties.dc_permittivity
159
237
 
160
238
  @dc_permittivity.setter
161
- def dc_permittivity(self, value):
162
- if self._edb_material_def.GetDielectricMaterialModel():
163
- self._edb_material_def.GetDielectricMaterialModel().SetDCRelativePermitivity(value)
239
+ def dc_permittivity(self, value: Union[int, float]):
240
+ """Set material dielectric relative permittivity"""
241
+ if self.__dc_model:
242
+ self.__dc_model.SetDCRelativePermitivity(value)
243
+ self.__properties.dc_permittivity = value
164
244
 
165
245
  @property
166
246
  def dielectric_model_frequency(self):
167
- """
168
-
169
- Returns
170
- -------
171
- Frequency in GHz
172
- """
173
- if self._edb_material_def.GetDielectricMaterialModel():
174
- return self._edb_material_def.GetDielectricMaterialModel().GetFrequency()
247
+ """Get material frequency in GHz."""
248
+ if self.__dc_model and self.__properties.dielectric_model_frequency is None:
249
+ self.__properties.dielectric_model_frequency = self.__dc_model.GetFrequency()
250
+ return self.__properties.dielectric_model_frequency
175
251
 
176
252
  @dielectric_model_frequency.setter
177
- def dielectric_model_frequency(self, value):
178
- if self._edb_material_def.GetDielectricMaterialModel():
179
- self._edb_material_def.GetDielectricMaterialModel().SetFrequency(value)
253
+ def dielectric_model_frequency(self, value: Union[int, float]):
254
+ """Get material frequency in GHz."""
255
+ if self.__dc_model:
256
+ self.__dc_model.SetFrequency(value)
257
+ self.__properties.dielectric_model_frequency = value
180
258
 
181
259
  @property
182
260
  def loss_tangent_at_frequency(self):
183
- if self._edb_material_def.GetDielectricMaterialModel():
184
- return self._edb_material_def.GetDielectricMaterialModel().GetLossTangentAtFrequency()
261
+ """Get material loss tangeat at frequency."""
262
+ if self.__dc_model and self.__properties.loss_tangent_at_frequency is None:
263
+ self.__properties.loss_tangent_at_frequency = self.__dc_model.GetLossTangentAtFrequency()
264
+ return self.__properties.loss_tangent_at_frequency
185
265
 
186
266
  @loss_tangent_at_frequency.setter
187
267
  def loss_tangent_at_frequency(self, value):
188
- if self._edb_material_def.GetDielectricMaterialModel():
189
- self._edb_material_def.GetDielectricMaterialModel().SetLossTangentAtFrequency(self._edb_value(value))
268
+ """Set material loss tangeat at frequency."""
269
+ if self.__dc_model:
270
+ edb_value = self.__edb_value(value)
271
+ self.__dc_model.SetLossTangentAtFrequency(edb_value)
272
+ self.__properties.dielectric_model_frequency = edb_value.ToDouble()
190
273
 
191
274
  @property
192
275
  def permittivity_at_frequency(self):
193
- if self._edb_material_def.GetDielectricMaterialModel():
194
- return self._edb_material_def.GetDielectricMaterialModel().GetRelativePermitivityAtFrequency()
276
+ """Get material relative permittivity at frequency."""
277
+ if self.__dc_model and self.__properties.permittivity_at_frequency is None:
278
+ self.__properties.permittivity_at_frequency = self.__dc_model.GetRelativePermitivityAtFrequency()
279
+ return self.__properties.permittivity_at_frequency
195
280
 
196
281
  @permittivity_at_frequency.setter
197
- def permittivity_at_frequency(self, value):
198
- if self._edb_material_def.GetDielectricMaterialModel():
199
- self._edb_material_def.GetDielectricMaterialModel().SetRelativePermitivityAtFrequency(value)
282
+ def permittivity_at_frequency(self, value: Union[int, float]):
283
+ """Set material relative permittivity at frequency."""
284
+ if self.__dc_model:
285
+ self.__dc_model.SetRelativePermitivityAtFrequency(value)
286
+ self.__properties.permittivity_at_frequency = value
200
287
 
201
288
  @property
202
289
  def magnetic_loss_tangent(self):
203
- """Retrieve material magnetic loss tangent."""
204
- material_id = self._edb.definition.MaterialPropertyId.MagneticLossTangent
205
- self._magnetic_loss_tangent = self._get_property(material_id)
206
- return self._magnetic_loss_tangent
290
+ """Get material magnetic loss tangent."""
291
+ if self.__properties.magnetic_loss_tangent is None:
292
+ material_property_id = self.__edb_definition.MaterialPropertyId.MagneticLossTangent
293
+ self.__properties.magnetic_loss_tangent = self.__property_value(material_property_id)
294
+ return self.__properties.magnetic_loss_tangent
207
295
 
208
296
  @magnetic_loss_tangent.setter
209
297
  def magnetic_loss_tangent(self, value):
210
- material_id = self._edb.definition.MaterialPropertyId.MagneticLossTangent
211
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
212
- self._magnetic_loss_tangent = value
298
+ """Set material magnetic loss tangent."""
299
+ edb_value = self.__edb_value(value)
300
+ material_property_id = self.__edb_definition.MaterialPropertyId.MagneticLossTangent
301
+ self.__material_def.SetProperty(material_property_id, edb_value)
302
+ self.__properties.magnetic_loss_tangent = edb_value.ToDouble()
213
303
 
214
304
  @property
215
305
  def thermal_conductivity(self):
216
- """Retrieve material thermal conductivity."""
217
- material_id = self._edb.definition.MaterialPropertyId.ThermalConductivity
218
- self._thermal_conductivity = self._get_property(material_id)
219
- return self._thermal_conductivity
306
+ """Get material thermal conductivity."""
307
+ if self.__properties.thermal_conductivity is None:
308
+ material_property_id = self.__edb_definition.MaterialPropertyId.ThermalConductivity
309
+ self.__properties.thermal_conductivity = self.__property_value(material_property_id)
310
+ return self.__properties.thermal_conductivity
220
311
 
221
312
  @thermal_conductivity.setter
222
313
  def thermal_conductivity(self, value):
223
- material_id = self._edb.definition.MaterialPropertyId.ThermalConductivity
224
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
225
- self._thermal_conductivity = value
314
+ """Set material thermal conductivity."""
315
+ edb_value = self.__edb_value(value)
316
+ material_property_id = self.__edb_definition.MaterialPropertyId.ThermalConductivity
317
+ self.__material_def.SetProperty(material_property_id, edb_value)
318
+ self.__properties.thermal_conductivity = edb_value.ToDouble()
226
319
 
227
320
  @property
228
321
  def mass_density(self):
229
- """Retrieve material mass density."""
230
- material_id = self._edb.definition.MaterialPropertyId.MassDensity
231
- self._mass_density = self._get_property(material_id)
232
- return self._mass_density
322
+ """Get material mass density."""
323
+ if self.__properties.thermal_conductivity is None:
324
+ material_property_id = self.__edb_definition.MaterialPropertyId.MassDensity
325
+ self.__properties.mass_density = self.__property_value(material_property_id)
326
+ return self.__properties.mass_density
233
327
 
234
328
  @mass_density.setter
235
329
  def mass_density(self, value):
236
- material_id = self._edb.definition.MaterialPropertyId.MassDensity
237
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
238
- self._mass_density = value
330
+ """Set material mass density."""
331
+ edb_value = self.__edb_value(value)
332
+ material_property_id = self.__edb_definition.MaterialPropertyId.MassDensity
333
+ self.__material_def.SetProperty(material_property_id, edb_value)
334
+ self.__properties.mass_density = edb_value.ToDouble()
239
335
 
240
336
  @property
241
337
  def youngs_modulus(self):
242
- """Retrieve material Young's Modulus."""
243
- material_id = self._edb.definition.MaterialPropertyId.YoungsModulus
244
- self._youngs_modulus = self._get_property(material_id)
245
- return self._youngs_modulus
338
+ """Get material youngs modulus."""
339
+ if self.__properties.youngs_modulus is None:
340
+ material_property_id = self.__edb_definition.MaterialPropertyId.YoungsModulus
341
+ self.__properties.youngs_modulus = self.__property_value(material_property_id)
342
+ return self.__properties.youngs_modulus
246
343
 
247
344
  @youngs_modulus.setter
248
345
  def youngs_modulus(self, value):
249
- material_id = self._edb.definition.MaterialPropertyId.YoungsModulus
250
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
251
- self._youngs_modulus = value
346
+ """Set material youngs modulus."""
347
+ edb_value = self.__edb_value(value)
348
+ material_property_id = self.__edb_definition.MaterialPropertyId.YoungsModulus
349
+ self.__material_def.SetProperty(material_property_id, edb_value)
350
+ self.__properties.youngs_modulus = edb_value.ToDouble()
252
351
 
253
352
  @property
254
353
  def specific_heat(self):
255
- """Retrieve material Specific Heat."""
256
- material_id = self._edb.definition.MaterialPropertyId.SpecificHeat
257
- self._specific_heat = self._get_property(material_id)
258
- return self._specific_heat
354
+ """Get material specific heat."""
355
+ if self.__properties.specific_heat is None:
356
+ material_property_id = self.__edb_definition.MaterialPropertyId.SpecificHeat
357
+ self.__properties.specific_heat = self.__property_value(material_property_id)
358
+ return self.__properties.specific_heat
259
359
 
260
360
  @specific_heat.setter
261
361
  def specific_heat(self, value):
262
- material_id = self._edb.definition.MaterialPropertyId.SpecificHeat
263
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
264
- self._specific_heat = value
362
+ """Set material specific heat."""
363
+ edb_value = self.__edb_value(value)
364
+ material_property_id = self.__edb_definition.MaterialPropertyId.SpecificHeat
365
+ self.__material_def.SetProperty(material_property_id, edb_value)
366
+ self.__properties.specific_heat = edb_value.ToDouble()
265
367
 
266
368
  @property
267
369
  def poisson_ratio(self):
268
- """Retrieve material Poisson Ratio."""
269
- material_id = self._edb.definition.MaterialPropertyId.PoissonsRatio
270
- self._poisson_ratio = self._get_property(material_id)
271
- return self._poisson_ratio
370
+ """Get material poisson ratio."""
371
+ if self.__properties.specific_heat is None:
372
+ material_property_id = self.__edb_definition.MaterialPropertyId.PoissonsRatio
373
+ self.__properties.poisson_ratio = self.__property_value(material_property_id)
374
+ return self.__properties.poisson_ratio
272
375
 
273
376
  @poisson_ratio.setter
274
377
  def poisson_ratio(self, value):
275
- material_id = self._edb.definition.MaterialPropertyId.PoissonsRatio
276
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
277
- self._poisson_ratio = value
378
+ """Set material poisson ratio."""
379
+ edb_value = self.__edb_value(value)
380
+ material_property_id = self.__edb_definition.MaterialPropertyId.PoissonsRatio
381
+ self.__material_def.SetProperty(material_property_id, edb_value)
382
+ self.__properties.poisson_ratio = edb_value.ToDouble()
278
383
 
279
384
  @property
280
385
  def thermal_expansion_coefficient(self):
281
- """Retrieve material Thermal Coefficient.."""
282
- material_id = self._edb.definition.MaterialPropertyId.ThermalExpansionCoefficient
283
- self._thermal_expansion_coefficient = self._get_property(material_id)
284
- return self._thermal_expansion_coefficient
386
+ """Get material thermal coefficient."""
387
+ if self.__properties.thermal_expansion_coefficient is None:
388
+ material_property_id = self.__edb_definition.MaterialPropertyId.ThermalExpansionCoefficient
389
+ self.__properties.thermal_expansion_coefficient = self.__property_value(material_property_id)
390
+ return self.__properties.thermal_expansion_coefficient
285
391
 
286
392
  @thermal_expansion_coefficient.setter
287
393
  def thermal_expansion_coefficient(self, value):
288
- material_id = self._edb.definition.MaterialPropertyId.ThermalExpansionCoefficient
289
- self._edb_material_def.SetProperty(material_id, self._edb_value(value))
290
- self._thermal_expansion_coefficient = value
394
+ """Set material thermal coefficient."""
395
+ edb_value = self.__edb_value(value)
396
+ material_property_id = self.__edb_definition.MaterialPropertyId.ThermalExpansionCoefficient
397
+ self.__material_def.SetProperty(material_property_id, self.__edb_value(value))
398
+ self.__properties.thermal_expansion_coefficient = edb_value.ToDouble()
291
399
 
292
400
  @pyedb_function_handler()
293
- def _json_format(self):
294
- out_dict = {}
295
- if self.permittivity == 0: # pragma no cover
296
- self.permittivity = 1.0
297
- if self.permeability == 0: # pragma no cover
298
- self.permeability = 1.0
299
- self._name = self.name
300
- self._conductivity = self.conductivity
301
- self._loss_tangent = self.loss_tangent
302
- self._magnetic_loss_tangent = self.magnetic_loss_tangent
303
- self._mass_density = self.mass_density
304
- self._permittivity = self.permittivity
305
- self._permeability = self.permeability
306
- self._poisson_ratio = self.poisson_ratio
307
- self._specific_heat = self.specific_heat
308
- self._thermal_conductivity = self.thermal_conductivity
309
- self._youngs_modulus = self.youngs_modulus
310
- self._thermal_expansion_coefficient = self.thermal_expansion_coefficient
311
- self._dc_conductivity = self.dc_conductivity
312
- self._dc_permittivity = self.dc_permittivity
313
- self._dielectric_model_frequency = self.dielectric_model_frequency
314
- self._loss_tangent_at_frequency = self.loss_tangent_at_frequency
315
- self._permittivity_at_frequency = self.permittivity_at_frequency
316
- for k, v in self.__dict__.items():
317
- if not k == "_pclass" and not k == "_edb_material_def":
318
- out_dict[k[1:]] = v
319
- return out_dict
401
+ def to_dict(self):
402
+ """Convert material into dictionary."""
403
+ self.__load_all_properties()
404
+
405
+ res = {"name": self.name}
406
+ res.update(self.__properties.model_dump())
407
+ return res
320
408
 
321
409
  @pyedb_function_handler()
322
- def _load(self, input_dict):
323
- default_material = {
324
- "name": "default",
325
- "conductivity": 0,
326
- "loss_tangent": 0,
327
- "magnetic_loss_tangent": 0,
328
- "mass_density": 0,
329
- "permittivity": 1,
330
- "permeability": 1,
331
- "poisson_ratio": 0,
332
- "specific_heat": 0,
333
- "thermal_conductivity": 0,
334
- "youngs_modulus": 0,
335
- "thermal_expansion_coefficient": 0,
336
- "dielectric_model_frequency": None,
337
- "dc_permittivity": None,
338
- }
410
+ def update(self, input_dict: dict):
339
411
  if input_dict:
340
- for k, v in input_dict.items():
341
- default_material[k] = v
342
-
343
- self.conductivity = default_material["conductivity"]
344
- self.loss_tangent = default_material["loss_tangent"]
345
- self.magnetic_loss_tangent = default_material["magnetic_loss_tangent"]
346
- self.mass_density = default_material["mass_density"]
347
- self.permittivity = default_material["permittivity"]
348
- self.permeability = default_material["permeability"]
349
- self.poisson_ratio = default_material["poisson_ratio"]
350
- self.specific_heat = default_material["specific_heat"]
351
- self.thermal_conductivity = default_material["thermal_conductivity"]
352
- self.youngs_modulus = default_material["youngs_modulus"]
353
- self.thermal_expansion_coefficient = default_material["thermal_expansion_coefficient"]
354
- if default_material["dielectric_model_frequency"] is not None: # pragma: no cover
355
- if self._edb_material_def.GetDielectricMaterialModel():
356
- model = self._edb_material_def.GetDielectricMaterialModel()
357
- self.dielectric_model_frequency = default_material["dielectric_model_frequency"]
358
- self.loss_tangent_at_frequency = default_material["loss_tangent_at_frequency"]
359
- self.permittivity_at_frequency = default_material["permittivity_at_frequency"]
360
- if default_material["dc_permittivity"] is not None:
361
- model.SetUseDCRelativePermitivity(True)
362
- self.dc_permittivity = default_material["dc_permittivity"]
363
- self.dc_conductivity = default_material["dc_conductivity"]
364
- else:
365
- if not self._pclass.add_djordjevicsarkar_material(
366
- default_material["name"],
367
- default_material["permittivity_at_frequency"],
368
- default_material["loss_tangent_at_frequency"],
369
- default_material["dielectric_model_frequency"],
370
- default_material["dc_permittivity"],
371
- default_material["dc_conductivity"],
372
- ):
373
- self._pclass._pedb.logger.warning(
374
- 'Cannot set DS model for material "{}". Check for realistic '
375
- "values that define DS Model".format(default_material["name"])
376
- )
412
+ # Update attributes
413
+ for attribute in ATTRIBUTES:
414
+ if attribute in input_dict:
415
+ setattr(self, attribute, input_dict[attribute])
416
+ if "loss_tangent" in input_dict: # pragma: no cover
417
+ setattr(self, "loss_tangent", input_dict["loss_tangent"])
418
+
419
+ # Update DS model
420
+ # NOTE: Contrary to before we don't test 'dielectric_model_frequency' only
421
+ if any(map(lambda attribute: input_dict.get(attribute, None) is not None, DC_ATTRIBUTES)):
422
+ if not self.__dc_model:
423
+ self.__dc_model = self.__edb_definition.DjordjecvicSarkarModel()
424
+ for attribute in DC_ATTRIBUTES:
425
+ if attribute in input_dict:
426
+ if attribute == "dc_permittivity" and input_dict[attribute] is not None:
427
+ self.__dc_model.SetUseDCRelativePermitivity(True)
428
+ setattr(self, attribute, input_dict[attribute])
429
+ self.__material_def.SetDielectricMaterialModel(self.__dc_model)
430
+ # Unset DS model if it is already assigned to the material in the database
431
+ elif self.__dc_model:
432
+ self.__material_def.SetDielectricMaterialModel(self.__edb_value(None))
433
+
434
+ @pyedb_function_handler()
435
+ def __edb_value(self, value):
436
+ """Convert a value to an EDB value.
437
+
438
+ Parameters
439
+ ----------
440
+ val : str, float, int
441
+ """
442
+ return self.__edb.edb_value(value)
443
+
444
+ @pyedb_function_handler()
445
+ def __load_all_properties(self):
446
+ """Load all properties of the material."""
447
+ for property in self.__properties.model_dump().keys():
448
+ _ = getattr(self, property)
449
+
450
+ @pyedb_function_handler()
451
+ def __property_value(self, material_property_id):
452
+ """Get property value from a material property id."""
453
+ if is_ironpython: # pragma: no cover
454
+ property_box = _clr.StrongBox[float]()
455
+ self.__material_def.GetProperty(material_property_id, property_box)
456
+ return float(property_box)
457
+ else:
458
+ _, property_box = self.__material_def.GetProperty(material_property_id)
459
+ if isinstance(property_box, float):
460
+ return property_box
377
461
  else:
378
- # To unset DS model if already assigned to the material in database
379
- if self._edb_material_def.GetDielectricMaterialModel():
380
- self._edb_material_def.SetDielectricMaterialModel(self._edb_value(None))
462
+ return property_box.ToDouble()
463
+
464
+ # def __reset_property(self, name):
465
+ # """Reset a property using the default value of the EDB API.
466
+ #
467
+ # This method consists in resetting the value of a property by updating the inner property
468
+ # to ``None`` and accessing the property afterward. When one wants to access a property
469
+ # whose stored inner value is ``None``, the value is updated to the EDB API default value
470
+ # associated to that property.
471
+ # """
472
+ # # Update inner property to None
473
+ # setattr(self.__properties, name, None)
474
+ # # Trigger get value on the property
475
+ # _ = getattr(self, name)
381
476
 
382
477
 
383
478
  class Materials(object):
384
479
  """Manages EDB methods for material management accessible from `Edb.materials` property."""
385
480
 
386
- def __getitem__(self, item):
387
- return self.materials[item]
481
+ def __init__(self, edb: Edb):
482
+ self.__edb = edb
483
+ self.__edb_definition = edb.edb_api.definition
484
+ self.__syslib = os.path.join(self.__edb.base_path, "syslib")
485
+ self.__materials: dict[str, Material] = {
486
+ material_def.GetName(): Material(self.__edb, material_def)
487
+ for material_def in list(self.__edb.active_db.MaterialDefs)
488
+ }
388
489
 
389
- def __init__(self, pedb):
390
- self._pedb = pedb
391
- self._syslib = os.path.join(self._pedb.base_path, "syslib")
392
- if not self.materials:
393
- self.add_material("air")
394
- self.add_material("copper", 1, 0.999991, 5.8e7, 0, 0)
395
- self.add_material("fr4_epoxy", 4.4, 1, 0, 0.02, 0)
396
- self.add_material("solder_mask", 3.1, 1, 0, 0.035, 0)
490
+ def __contains__(self, item):
491
+ if isinstance(item, Material):
492
+ return item.name in self.__materials
493
+ else:
494
+ return item in self.__materials
495
+
496
+ def __getitem__(self, item):
497
+ return self.__materials[item]
397
498
 
398
499
  @property
399
500
  def syslib(self):
400
- """Retrieve the project sys library."""
401
- return self._syslib
402
-
403
- @pyedb_function_handler()
404
- def _edb_value(self, value):
405
- return self._pedb.edb_value(value)
501
+ """Get the project sys library."""
502
+ return self.__syslib
406
503
 
407
504
  @property
408
- def _edb(self):
409
- return self._pedb.edb_api
505
+ def materials(self):
506
+ """Get materials."""
507
+ return self.__materials
410
508
 
411
- @property
412
- def _db(self):
413
- return self._pedb.active_db
509
+ def __edb_value(self, value):
510
+ """Convert a value to an EDB value.
414
511
 
415
- @property
416
- def materials(self):
417
- """Retrieve dictionary of material from material library."""
418
- return {obj.GetName(): Material(self, obj) for obj in list(self._db.MaterialDefs)}
512
+ Parameters
513
+ ----------
514
+ val : str, float, int
515
+ """
516
+ return self.__edb.edb_value(value)
419
517
 
420
518
  @pyedb_function_handler()
421
- def add_material(
422
- self,
423
- name="air",
424
- permittivity=1.0006,
425
- permeability=1.0000004,
426
- conductivity=0,
427
- dielectric_loss_tangent=0,
428
- magnetic_loss_tangent=0,
429
- ):
519
+ def add_material(self, name: str, **kwargs):
430
520
  """Add a new material.
431
521
 
432
522
  Parameters
433
523
  ----------
434
- name : str, optional
435
- Material Name. The default is ``"air"``.
436
- permittivity : float, str, optional
437
- Material permittivity. The default is ``1.0006``.
438
- permeability : float, str, optional
439
- Material permeability. The default is ``1.0000004``.
440
- conductivity : float, str, optional
441
- Material conductivity. The default is ``0``.
442
- dielectric_loss_tangent : float, str, optional
443
- Material dielectric loss tangent. The default is ``0``.
444
- magnetic_loss_tangent : float, str, optional
445
- Material magnetic loss tangent. The default is ``0``.
524
+ name : str
525
+ Material name.
446
526
 
447
527
  Returns
448
528
  -------
449
529
  :class:`pyedb.dotnet.edb_core.materials.Material`
450
530
  """
451
- if not name in self.materials:
452
- self._edb.definition.MaterialDef.Create(self._db, name)
453
- new_material = self.materials[name]
454
- new_material.permittivity = permittivity
455
- new_material.permeability = permeability
456
- new_material.conductivity = conductivity
457
- new_material.loss_tangent = dielectric_loss_tangent
458
- new_material.magnetic_loss_tangent = magnetic_loss_tangent
459
- return new_material
460
- else: # pragma: no cover
461
- warnings.warn("Material {} already exists in material library.".format(name))
462
- return False
531
+ if name in self.__materials:
532
+ raise ValueError(f"Material {name} already exists in material library.")
533
+
534
+ material_def = self.__edb_definition.MaterialDef.Create(self.__edb.active_db, name)
535
+ material = Material(self.__edb, material_def)
536
+ attributes_input_dict = {key: val for (key, val) in kwargs.items() if key in ATTRIBUTES + DC_ATTRIBUTES}
537
+ if "loss_tangent" in kwargs: # pragma: no cover
538
+ warnings.warn(
539
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
540
+ "Use key dielectric_loss_tangent instead.",
541
+ DeprecationWarning,
542
+ )
543
+ attributes_input_dict["dielectric_loss_tangent"] = kwargs["loss_tangent"]
544
+ if attributes_input_dict:
545
+ material.update(attributes_input_dict)
546
+
547
+ self.__materials[name] = material
548
+ return material
463
549
 
464
550
  @pyedb_function_handler()
465
- def add_conductor_material(self, name, conductivity):
466
- """Add a new conductor material in library.
551
+ def add_conductor_material(self, name, conductivity, **kwargs):
552
+ """Add a new conductor material.
467
553
 
468
554
  Parameters
469
555
  ----------
470
556
  name : str
471
557
  Name of the new material.
472
- conductivity : float
558
+ conductivity : str, float, int
473
559
  Conductivity of the new material.
474
560
 
475
561
  Returns
@@ -477,99 +563,91 @@ class Materials(object):
477
563
  :class:`pyedb.dotnet.edb_core.materials.Material`
478
564
 
479
565
  """
480
- if not name in self.materials:
481
- self._edb.definition.MaterialDef.Create(self._db, name)
482
- new_material = self.materials[name]
483
- new_material.conductivity = conductivity
484
- new_material.permittivity = 1
485
- new_material.permeability = 1
486
- return new_material
487
- else: # pragma: no cover
488
- warnings.warn("Material {} already exists in material library.".format(name))
489
- return False
566
+ extended_kwargs = {key: value for (key, value) in kwargs.items()}
567
+ extended_kwargs["conductivity"] = conductivity
568
+ material = self.add_material(name, **extended_kwargs)
569
+
570
+ return material
490
571
 
491
572
  @pyedb_function_handler()
492
- def add_dielectric_material(self, name, permittivity, loss_tangent, permeability=1):
573
+ def add_dielectric_material(self, name, permittivity, dielectric_loss_tangent, **kwargs):
493
574
  """Add a new dielectric material in library.
494
575
 
495
576
  Parameters
496
577
  ----------
497
578
  name : str
498
579
  Name of the new material.
499
- permittivity : float
580
+ permittivity : str, float, int
500
581
  Permittivity of the new material.
501
- loss_tangent : float
502
- Loss tangent of the new material.
503
- permeability : float
504
- Permeability of the new material.
582
+ dielectric_loss_tangent : str, float, int
583
+ Dielectric loss tangent of the new material.
505
584
 
506
585
  Returns
507
586
  -------
508
587
  :class:`pyedb.dotnet.edb_core.materials.Material`
509
588
  """
510
- if not name in self.materials:
511
- self._edb.definition.MaterialDef.Create(self._db, name)
512
- new_material = self.materials[name]
513
- new_material.permittivity = permittivity
514
- new_material.loss_tangent = loss_tangent
515
- new_material.permeability = permeability
516
- return new_material
517
- else:
518
- warnings.warn("Material {} already exists in material library.".format(name))
519
- return False
589
+ extended_kwargs = {key: value for (key, value) in kwargs.items()}
590
+ extended_kwargs["permittivity"] = permittivity
591
+ extended_kwargs["dielectric_loss_tangent"] = dielectric_loss_tangent
592
+ material = self.add_material(name, **extended_kwargs)
520
593
 
521
- @pyedb_function_handler()
522
- def get_djordjevicsarkar_model(self, material_name=None):
523
- """Djordjevic-Sarkar model if present.
524
-
525
- Parameters
526
- ----------
527
- material_name : str
528
-
529
- Returns
530
- -------
531
-
532
- """
533
- material = self.materials[material_name]
534
- if material:
535
- return material.GetDielectricMaterialModel()
594
+ return material
536
595
 
537
596
  @pyedb_function_handler()
538
- def add_djordjevicsarkar_material(
539
- self, name, permittivity, loss_tangent, test_frequency, dc_permittivity=None, dc_conductivity=None
597
+ def add_djordjevicsarkar_dielectric(
598
+ self,
599
+ name,
600
+ permittivity_at_frequency,
601
+ loss_tangent_at_frequency,
602
+ dielectric_model_frequency,
603
+ dc_conductivity=None,
604
+ dc_permittivity=None,
605
+ **kwargs,
540
606
  ):
541
- """Create a Djordjevic_Sarkar dielectric.
607
+ """Add a dielectric using the Djordjevic-Sarkar model.
542
608
 
543
609
  Parameters
544
610
  ----------
545
611
  name : str
546
612
  Name of the dielectric.
547
- permittivity : float
613
+ permittivity_at_frequency : str, float, int
548
614
  Relative permittivity of the dielectric.
549
- loss_tangent : float
615
+ loss_tangent_at_frequency : str, float, int
550
616
  Loss tangent for the material.
551
- test_frequency : float
617
+ dielectric_model_frequency : str, float, int
552
618
  Test frequency in GHz for the dielectric.
553
- dc_permittivity : float, optional
554
- DC Relative permittivity of the dielectric.
555
- dc_conductivity : float, optional
556
- DC Conductivity of the dielectric.
557
619
 
558
620
  Returns
559
621
  -------
560
622
  :class:`pyedb.dotnet.edb_core.materials.Material`
561
- Material definition.
562
623
  """
563
- material_def = self._edb.definition.DjordjecvicSarkarModel()
564
- material_def.SetFrequency(test_frequency)
565
- material_def.SetLossTangentAtFrequency(self._edb_value(loss_tangent))
566
- material_def.SetRelativePermitivityAtFrequency(permittivity)
624
+ if name in self.__materials:
625
+ raise ValueError(f"Material {name} already exists in material library.")
626
+
627
+ material_model = self.__edb_definition.DjordjecvicSarkarModel()
628
+ material_model.SetRelativePermitivityAtFrequency(permittivity_at_frequency)
629
+ material_model.SetLossTangentAtFrequency(self.__edb_value(loss_tangent_at_frequency))
630
+ material_model.SetFrequency(dielectric_model_frequency)
567
631
  if dc_conductivity is not None:
568
- material_def.SetDCConductivity(dc_conductivity)
632
+ material_model.SetDCConductivity(dc_conductivity)
569
633
  if dc_permittivity is not None:
570
- material_def.SetUseDCRelativePermitivity(True)
571
- material_def.SetDCRelativePermitivity(dc_permittivity)
572
- return self._add_dielectric_material_model(name, material_def)
634
+ material_model.SetUseDCRelativePermitivity(True)
635
+ material_model.SetDCRelativePermitivity(dc_permittivity)
636
+ try:
637
+ material = self.__add_dielectric_material_model(name, material_model)
638
+ for key, value in kwargs.items():
639
+ setattr(material, key, value)
640
+ if "loss_tangent" in kwargs: # pragma: no cover
641
+ warnings.warn(
642
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
643
+ "Use key dielectric_loss_tangent instead.",
644
+ DeprecationWarning,
645
+ )
646
+ setattr(material, "dielectric_loss_tangent", kwargs["loss_tangent"])
647
+ self.__materials[name] = material
648
+ return material
649
+ except MaterialModelException:
650
+ raise ValueError("Use realistic values to define DS model.")
573
651
 
574
652
  @pyedb_function_handler()
575
653
  def add_debye_material(
@@ -581,42 +659,61 @@ class Materials(object):
581
659
  loss_tangent_high,
582
660
  lower_freqency,
583
661
  higher_frequency,
662
+ **kwargs,
584
663
  ):
585
- """Create a dielectric with the Debye model.
664
+ """Add a dielectric with the Debye model.
586
665
 
587
666
  Parameters
588
667
  ----------
589
668
  name : str
590
669
  Name of the dielectric.
591
- permittivity_low : float
670
+ permittivity_low : float, int
592
671
  Relative permittivity of the dielectric at the frequency specified
593
672
  for ``lower_frequency``.
594
- permittivity_high : float
673
+ permittivity_high : float, int
595
674
  Relative permittivity of the dielectric at the frequency specified
596
675
  for ``higher_frequency``.
597
- loss_tangent_low : float
676
+ loss_tangent_low : float, int
598
677
  Loss tangent for the material at the frequency specified
599
678
  for ``lower_frequency``.
600
- loss_tangent_high : float
679
+ loss_tangent_high : float, int
601
680
  Loss tangent for the material at the frequency specified
602
681
  for ``higher_frequency``.
603
- lower_freqency : float
682
+ lower_freqency : str, float, int
604
683
  Value for the lower frequency.
605
- higher_frequency : float
684
+ higher_frequency : str, float, int
606
685
  Value for the higher frequency.
607
686
 
608
687
  Returns
609
688
  -------
610
689
  :class:`pyedb.dotnet.edb_core.materials.Material`
611
- Material definition.
612
690
  """
613
- material_def = self._edb.definition.DebyeModel()
614
- material_def.SetFrequencyRange(lower_freqency, higher_frequency)
615
- material_def.SetLossTangentAtHighLowFrequency(loss_tangent_low, loss_tangent_high)
616
- material_def.SetRelativePermitivityAtHighLowFrequency(
617
- self._edb_value(permittivity_low), self._edb_value(permittivity_high)
691
+ if name in self.__materials:
692
+ raise ValueError(f"Material {name} already exists in material library.")
693
+
694
+ material_model = self.__edb_definition.DebyeModel()
695
+ # FIXME: Seems like there is a bug here (we need to provide higher value for
696
+ # lower_freqency than higher_frequency)
697
+ material_model.SetFrequencyRange(lower_freqency, higher_frequency)
698
+ material_model.SetLossTangentAtHighLowFrequency(loss_tangent_low, loss_tangent_high)
699
+ material_model.SetRelativePermitivityAtHighLowFrequency(
700
+ self.__edb_value(permittivity_low), self.__edb_value(permittivity_high)
618
701
  )
619
- return self._add_dielectric_material_model(name, material_def)
702
+ try:
703
+ material = self.__add_dielectric_material_model(name, material_model)
704
+ for key, value in kwargs.items():
705
+ setattr(material, key, value)
706
+ if "loss_tangent" in kwargs: # pragma: no cover
707
+ warnings.warn(
708
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
709
+ "Use key dielectric_loss_tangent instead.",
710
+ DeprecationWarning,
711
+ )
712
+ setattr(material, "dielectric_loss_tangent", kwargs["loss_tangent"])
713
+ self.__materials[name] = material
714
+ return material
715
+ except MaterialModelException:
716
+ raise ValueError("Use realistic values to define Debye model.")
620
717
 
621
718
  @pyedb_function_handler()
622
719
  def add_multipole_debye_material(
@@ -625,8 +722,9 @@ class Materials(object):
625
722
  frequencies,
626
723
  permittivities,
627
724
  loss_tangents,
725
+ **kwargs,
628
726
  ):
629
- """Create a dielectric with the Multipole Debye model.
727
+ """Add a dielectric with the Multipole Debye model.
630
728
 
631
729
  Parameters
632
730
  ----------
@@ -642,7 +740,6 @@ class Materials(object):
642
740
  Returns
643
741
  -------
644
742
  :class:`pyedb.dotnet.edb_core.materials.Material`
645
- Material definition.
646
743
 
647
744
  Examples
648
745
  --------
@@ -653,32 +750,58 @@ class Materials(object):
653
750
  >>> loss_tan = [0.025, 0.026, 0.027, 0.028, 0.029, 0.030]
654
751
  >>> diel = edb.materials.add_multipole_debye_material("My_MP_Debye", freq, rel_perm, loss_tan)
655
752
  """
753
+ if name in self.__materials:
754
+ raise ValueError(f"Material {name} already exists in material library.")
755
+
656
756
  frequencies = [float(i) for i in frequencies]
657
757
  permittivities = [float(i) for i in permittivities]
658
758
  loss_tangents = [float(i) for i in loss_tangents]
659
- material_def = self._edb.definition.MultipoleDebyeModel()
660
- material_def.SetParameters(
759
+ material_model = self.__edb_definition.MultipoleDebyeModel()
760
+ material_model.SetParameters(
661
761
  convert_py_list_to_net_list(frequencies),
662
762
  convert_py_list_to_net_list(permittivities),
663
763
  convert_py_list_to_net_list(loss_tangents),
664
764
  )
665
- return self._add_dielectric_material_model(name, material_def)
765
+ try:
766
+ material = self.__add_dielectric_material_model(name, material_model)
767
+ for key, value in kwargs.items():
768
+ setattr(material, key, value)
769
+ if "loss_tangent" in kwargs: # pragma: no cover
770
+ warnings.warn(
771
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
772
+ "Use key dielectric_loss_tangent instead.",
773
+ DeprecationWarning,
774
+ )
775
+ setattr(material, "dielectric_loss_tangent", kwargs["loss_tangent"])
776
+ self.__materials[name] = material
777
+ return material
778
+ except MaterialModelException:
779
+ raise ValueError("Use realistic values to define Multipole Debye model.")
666
780
 
667
781
  @pyedb_function_handler()
668
- def _add_dielectric_material_model(self, name, material_model):
669
- if self._edb.definition.MaterialDef.FindByName(self._db, name).IsNull():
670
- self._edb.definition.MaterialDef.Create(self._db, name)
671
- material_def = self._edb.definition.MaterialDef.FindByName(self._db, name)
782
+ def __add_dielectric_material_model(self, name, material_model):
783
+ """Add a dielectric material model.
784
+
785
+ Parameters
786
+ ----------
787
+ name : str
788
+ Name of the dielectric.
789
+ material_model : Any
790
+ Dielectric material model.
791
+ """
792
+ if self.__edb_definition.MaterialDef.FindByName(self.__edb.active_db, name).IsNull():
793
+ self.__edb_definition.MaterialDef.Create(self.__edb.active_db, name)
794
+ material_def = self.__edb_definition.MaterialDef.FindByName(self.__edb.active_db, name)
672
795
  succeeded = material_def.SetDielectricMaterialModel(material_model)
673
796
  if succeeded:
674
- return material_def
675
- return False
797
+ material = Material(self.__edb, material_def)
798
+ return material
799
+ raise MaterialModelException("Set dielectric material model failed.")
676
800
 
677
801
  @pyedb_function_handler()
678
802
  def duplicate(self, material_name, new_material_name):
679
803
  """Duplicate a material from the database.
680
804
 
681
-
682
805
  Parameters
683
806
  ----------
684
807
  material_name : str
@@ -688,75 +811,72 @@ class Materials(object):
688
811
 
689
812
  Returns
690
813
  -------
691
- EDB material : class: 'Ansys.Ansoft.Edb.definition.MaterialDef'
814
+ :class:`pyedb.dotnet.edb_core.materials.Material`
815
+ """
816
+ if new_material_name in self.__materials:
817
+ raise ValueError(f"Material {new_material_name} already exists in material library.")
692
818
 
819
+ material = self.materials[material_name]
820
+ material_def = self.__edb_definition.MaterialDef.Create(self.__edb.active_db, new_material_name)
821
+ material_dict = material.to_dict()
822
+ new_material = Material(self.__edb, material_def)
823
+ new_material.update(material_dict)
693
824
 
694
- Examples
695
- --------
825
+ self.__materials[new_material_name] = new_material
826
+ return new_material
696
827
 
697
- >>> from pyedb import Edb
698
- >>> edb_app = Edb()
699
- >>> my_material = edb_app.materials.duplicate("copper", "my_new_copper")
828
+ @pyedb_function_handler()
829
+ def delete_material(self, material_name):
830
+ """Remove a material from the database."""
831
+ material_def = self.__edb_definition.MaterialDef.FindByName(self.__edb.active_db, material_name)
832
+ if material_def.IsNull():
833
+ raise ValueError(f"Cannot find material {material_name}.")
834
+ material_def.Delete()
835
+ del self.__materials[material_name]
700
836
 
701
- """
702
- material_list = {i.lower(): i for i in list(self.materials.keys())}
703
- if material_name.lower() in material_list and new_material_name not in self.materials:
704
- material_name = material_list[material_name.lower()]
705
- permittivity = self._edb_value(self.materials[material_name].permittivity)
706
- permeability = self._edb_value(self.materials[material_name].permeability)
707
- conductivity = self._edb_value(self.materials[material_name].conductivity)
708
- dielectric_loss_tangent = self._edb_value(self.materials[material_name].loss_tangent)
709
- magnetic_loss_tangent = self._edb_value(self.materials[material_name].magnetic_loss_tangent)
710
- thermal_conductivity = self._edb_value(self.materials[material_name].thermal_conductivity)
711
- thermal_expansion_coefficient = self._edb_value(self.materials[material_name].thermal_expansion_coefficient)
712
- youngs_modulus = self._edb_value(self.materials[material_name].youngs_modulus)
713
- poisson_ratio = self._edb_value(self.materials[material_name].poisson_ratio)
714
- mass_density = self._edb_value(self.materials[material_name].mass_density)
715
- material_model = self.materials[material_name]._edb_material_def.GetDielectricMaterialModel()
716
- edb_material = self._edb.definition.MaterialDef.Create(self._db, new_material_name)
717
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.Permittivity, permittivity)
718
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.Permeability, permeability)
719
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.Conductivity, conductivity)
720
- edb_material.SetProperty(
721
- self._edb.definition.MaterialPropertyId.DielectricLossTangent, dielectric_loss_tangent
722
- )
723
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.ThermalConductivity, thermal_conductivity)
724
- edb_material.SetProperty(
725
- self._edb.definition.MaterialPropertyId.ThermalExpansionCoefficient, thermal_expansion_coefficient
837
+ @pyedb_function_handler()
838
+ def update_material(self, material_name, input_dict):
839
+ """Update material attributes."""
840
+ if material_name not in self.__materials:
841
+ raise ValueError(f"Material {material_name} does not exist in material library.")
842
+
843
+ material = self[material_name]
844
+ attributes_input_dict = {key: val for (key, val) in input_dict.items() if key in ATTRIBUTES + DC_ATTRIBUTES}
845
+ if "loss_tangent" in input_dict: # pragma: no cover
846
+ warnings.warn(
847
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
848
+ "Use key dielectric_loss_tangent instead.",
849
+ DeprecationWarning,
726
850
  )
727
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.MassDensity, mass_density)
728
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.YoungsModulus, youngs_modulus)
729
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.PoissonsRatio, poisson_ratio)
730
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.MagneticLossTangent, magnetic_loss_tangent)
731
- edb_material.SetProperty(self._edb.definition.MaterialPropertyId.MagneticLossTangent, magnetic_loss_tangent)
732
- edb_material.SetDielectricMaterialModel(material_model)
733
-
734
- return edb_material
851
+ attributes_input_dict["dielectric_loss_tangent"] = input_dict["loss_tangent"]
852
+ if attributes_input_dict:
853
+ material.update(attributes_input_dict)
854
+ self.__materials[material_name] = material
855
+ return material
735
856
 
736
857
  @pyedb_function_handler()
737
- def _load_materials(self, material=None):
738
- if self.materials:
739
- mat_keys = [i.lower() for i in self.materials.keys()]
740
- mat_keys_case = [i for i in self.materials.keys()]
741
- else:
742
- mat_keys = []
743
- mat_keys_case = []
744
-
745
- if not material:
746
- return
747
- if material["name"].lower() not in mat_keys:
748
- if "conductivity" not in material:
749
- self.add_dielectric_material(material["name"], material["permittivity"], material["loss_tangent"])
750
- elif material["conductivity"] > 1e4:
751
- self.add_conductor_material(material["name"], material["conductivity"])
858
+ def load_material(self, material):
859
+ """Load material."""
860
+ if material:
861
+ material_name = material["name"]
862
+ material_conductivity = material.get("conductivity", None)
863
+ if material_conductivity and material_conductivity > 1e4:
864
+ self.add_conductor_material(material_name, material_conductivity)
752
865
  else:
753
- self.add_dielectric_material(material["name"], material["permittivity"], material["loss_tangent"])
754
- self.materials[material["name"]]._load(material)
755
- else:
756
- self.materials[mat_keys_case[mat_keys.index(material["name"].lower())]]._load(material)
866
+ material_permittivity = material["permittivity"]
867
+ if "loss_tangent" in material: # pragma: no cover
868
+ warnings.warn(
869
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
870
+ "Use key dielectric_loss_tangent instead.",
871
+ DeprecationWarning,
872
+ )
873
+ material_dlt = material["loss_tangent"]
874
+ else:
875
+ material_dlt = material["dielectric_loss_tangent"]
876
+ self.add_dielectric_material(material_name, material_permittivity, material_dlt)
757
877
 
758
878
  @pyedb_function_handler()
759
- def material_name_to_id(self, property_name):
879
+ def material_property_to_id(self, property_name):
760
880
  """Convert a material property name to a material property ID.
761
881
 
762
882
  Parameters
@@ -766,116 +886,148 @@ class Materials(object):
766
886
 
767
887
  Returns
768
888
  -------
769
- ID of the material property.
889
+ Any
770
890
  """
771
- props = {
772
- "Permittivity": self._edb.definition.MaterialPropertyId.Permittivity,
773
- "Permeability": self._edb.definition.MaterialPropertyId.Permeability,
774
- "Conductivity": self._edb.definition.MaterialPropertyId.Conductivity,
775
- "DielectricLossTangent": self._edb.definition.MaterialPropertyId.DielectricLossTangent,
776
- "MagneticLossTangent": self._edb.definition.MaterialPropertyId.MagneticLossTangent,
777
- "ThermalConductivity": self._edb.definition.MaterialPropertyId.ThermalConductivity,
778
- "MassDensity": self._edb.definition.MaterialPropertyId.MassDensity,
779
- "SpecificHeat": self._edb.definition.MaterialPropertyId.SpecificHeat,
780
- "YoungsModulus": self._edb.definition.MaterialPropertyId.YoungsModulus,
781
- "PoissonsRatio": self._edb.definition.MaterialPropertyId.PoissonsRatio,
782
- "ThermalExpansionCoefficient": self._edb.definition.MaterialPropertyId.ThermalExpansionCoefficient,
783
- "InvalidProperty": self._edb.definition.MaterialPropertyId.InvalidProperty,
891
+ material_property_id = self.__edb_definition.MaterialPropertyId
892
+ property_name_to_id = {
893
+ "Permittivity": material_property_id.Permittivity,
894
+ "Permeability": material_property_id.Permeability,
895
+ "Conductivity": material_property_id.Conductivity,
896
+ "DielectricLossTangent": material_property_id.DielectricLossTangent,
897
+ "MagneticLossTangent": material_property_id.MagneticLossTangent,
898
+ "ThermalConductivity": material_property_id.ThermalConductivity,
899
+ "MassDensity": material_property_id.MassDensity,
900
+ "SpecificHeat": material_property_id.SpecificHeat,
901
+ "YoungsModulus": material_property_id.YoungsModulus,
902
+ "PoissonsRatio": material_property_id.PoissonsRatio,
903
+ "ThermalExpansionCoefficient": material_property_id.ThermalExpansionCoefficient,
904
+ "InvalidProperty": material_property_id.InvalidProperty,
784
905
  }
785
906
 
786
- found_el = difflib.get_close_matches(property_name, list(props.keys()), 1, 0.7)
787
- if found_el:
788
- return props[found_el[0]]
907
+ if property_name == "loss_tangent":
908
+ warnings.warn(
909
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
910
+ "Use key dielectric_loss_tangent instead.",
911
+ DeprecationWarning,
912
+ )
913
+ property_name = "dielectric_loss_tangent"
914
+ match = difflib.get_close_matches(property_name, property_name_to_id, 1, 0.7)
915
+ if match:
916
+ return property_name_to_id[match[0]]
789
917
  else:
790
- return self._edb.definition.MaterialPropertyId.InvalidProperty
918
+ return property_name_to_id["InvalidProperty"]
791
919
 
792
920
  @pyedb_function_handler()
793
- def get_property_by_material_name(self, property_name, material_name):
794
- """Get the property of a material. If it is executed in IronPython,
795
- you must only use the first element of the returned tuple, which is a float.
921
+ def load_amat(self, amat_file):
922
+ """Load materials from an AMAT file.
796
923
 
797
924
  Parameters
798
925
  ----------
799
- material_name : str
800
- Name of the existing material.
801
- property_name : str
802
- Name of the material property.
803
- ``permittivity``
804
- ``permeability``
805
- ``conductivity``
806
- ``dielectric_loss_tangent``
807
- ``magnetic_loss_tangent``
926
+ amat_file : str
927
+ Full path to the AMAT file to read and add to the Edb.
808
928
 
809
929
  Returns
810
930
  -------
811
- float
812
- The float value of the property.
813
-
814
-
815
- Examples
816
- --------
817
- >>> from pyedb import Edb
818
- >>> edb_app = Edb()
819
- >>> returned_tuple = edb_app.materials.get_property_by_material_name("conductivity", "copper")
820
- >>> edb_value = returned_tuple[0]
821
- >>> float_value = returned_tuple[1]
822
-
931
+ bool
823
932
  """
824
- if self._edb.definition.MaterialDef.FindByName(self._pedb._db, material_name).IsNull():
825
- self._pedb.logger.error("This material doesn't exists.")
826
- else:
827
- original_material = self._edb.definition.MaterialDef.FindByName(self._pedb._db, material_name)
828
- if is_ironpython: # pragma: no cover
829
- property_box = _clr.StrongBox[float]()
830
- original_material.GetProperty(self.material_name_to_id(property_name), property_box)
831
- return float(property_box)
933
+ if not os.path.exists(amat_file):
934
+ raise FileNotFoundError(f"File path {amat_file} does not exist.")
935
+ materials_dict = self.read_materials(amat_file)
936
+ for material_name, material_properties in materials_dict.items():
937
+ if not material_name in self:
938
+ if "tangent_delta" in material_properties:
939
+ material_properties["dielectric_loss_tangent"] = material_properties["tangent_delta"]
940
+ del material_properties["tangent_delta"]
941
+ elif "loss_tangent" in material_properties: # pragma: no cover
942
+ warnings.warn(
943
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
944
+ "Use key dielectric_loss_tangent instead.",
945
+ DeprecationWarning,
946
+ )
947
+ material_properties["dielectric_loss_tangent"] = material_properties["loss_tangent"]
948
+ del material_properties["loss_tangent"]
949
+ self.add_material(material_name, **material_properties)
832
950
  else:
833
- _, property_box = original_material.GetProperty(
834
- self.material_name_to_id(property_name), self._edb_value(0.0)
835
- )
836
- if isinstance(property_box, float):
837
- return property_box
838
- else:
839
- return property_box.ToDouble()
840
- return False
951
+ self.__edb.logger.warning(f"Material {material_name} already exist and was not loaded from AMAT file.")
952
+ return True
841
953
 
842
954
  @pyedb_function_handler()
843
- def load_amat(self, amat_file):
844
- """Load materials from an AMAT file.
955
+ def iterate_materials_in_amat(self, amat_file=None):
956
+ """Iterate over material description in an AMAT file.
845
957
 
846
958
  Parameters
847
959
  ----------
848
960
  amat_file : str
849
- Full path to the AMAT file to read and add to the Edb.
961
+ Full path to the AMAT file to read.
850
962
 
851
- Returns
852
- -------
853
- bool
963
+ Yields
964
+ ------
965
+ dict
854
966
  """
855
- if not os.path.exists(amat_file):
856
- self._pedb.logger.error("File path {} does not exist.".format(amat_file))
857
- material_dict = self.read_materials(amat_file)
858
- for material_name, material in material_dict.items():
859
- if not material_name in list(self.materials.keys()):
860
- new_material = self.add_material(name=material_name)
861
- properties = [
862
- "permittivity",
863
- "conductivity",
864
- "mass_density",
865
- "permeability",
866
- "specific_heat",
867
- "thermal_expansion_coefficient",
868
- ]
869
- for mat_prop_name, mat_prop_value in material.items():
870
- if mat_prop_name in properties:
871
- setattr(new_material, mat_prop_name, mat_prop_value)
872
- if mat_prop_name == "tangent_delta":
873
- new_material.loss_tangent = mat_prop_value
874
- return True
967
+ if amat_file is None:
968
+ amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
969
+
970
+ begin_regex = re.compile(r"^\$begin '(.+)'")
971
+ end_regex = re.compile(r"^\$end '(.+)'")
972
+ material_properties = ATTRIBUTES.copy()
973
+ # Remove cases manually handled
974
+ material_properties.remove("conductivity")
975
+
976
+ with open(amat_file, "r") as amat_fh:
977
+ in_material_def = False
978
+ material_description = {}
979
+ for line in amat_fh:
980
+ if in_material_def:
981
+ # Yield material definition
982
+ if end_regex.search(line):
983
+ in_material_def = False
984
+ yield material_description
985
+ material_description = {}
986
+ # Extend material definition if possible
987
+ else:
988
+ for material_property in material_properties:
989
+ if material_property in line:
990
+ value = get_line_float_value(line)
991
+ if value is not None:
992
+ material_description[material_property] = value
993
+ break
994
+ # Extra case to cover bug in syslib AMAT file (see #364)
995
+ if "thermal_expansion_coeffcient" in line:
996
+ value = get_line_float_value(line)
997
+ if value is not None:
998
+ material_description["thermal_expansion_coefficient"] = value
999
+ # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1000
+ if "conductivity" in line and "thermal_conductivity" not in line:
1001
+ value = get_line_float_value(line)
1002
+ if value is not None:
1003
+ material_description["conductivity"] = value
1004
+ # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1005
+ if (
1006
+ "loss_tangent" in line
1007
+ and "dielectric_loss_tangent" not in line
1008
+ and "magnetic_loss_tangent" not in line
1009
+ ):
1010
+ warnings.warn(
1011
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
1012
+ "Use key dielectric_loss_tangent instead.",
1013
+ DeprecationWarning,
1014
+ )
1015
+ value = get_line_float_value(line)
1016
+ if value is not None:
1017
+ material_description["dielectric_loss_tangent"] = value
1018
+ # Check if we reach the beginning of a material description
1019
+ else:
1020
+ match = begin_regex.search(line)
1021
+ if match:
1022
+ material_name = match.group(1)
1023
+ # Skip unwanted data
1024
+ if material_name in ("$index$", "$base_index$"):
1025
+ continue
1026
+ material_description["name"] = match.group(1)
1027
+ in_material_def = True
875
1028
 
876
- @staticmethod
877
1029
  @pyedb_function_handler()
878
- def read_materials(amat_file):
1030
+ def read_materials(self, amat_file):
879
1031
  """Read materials from an AMAT file.
880
1032
 
881
1033
  Parameters
@@ -886,75 +1038,41 @@ class Materials(object):
886
1038
  Returns
887
1039
  -------
888
1040
  dict
889
- {material name: dict of material property to value}.
1041
+ {material name: dict of material properties}.
890
1042
  """
1043
+ res = {}
1044
+ for material in self.iterate_materials_in_amat(amat_file):
1045
+ material_name = material["name"]
1046
+ res[material_name] = {}
1047
+ for material_property, value in material.items():
1048
+ if material_property != "name":
1049
+ res[material_name][material_property] = value
891
1050
 
892
- def get_line_float_value(line):
893
- """Retrieve the float value expected in the line of an AMAT file.
894
- The associated string is expected to follow one of the following cases:
895
- - simple('permittivity', 12.)
896
- - permittivity='12'.
897
- """
898
- try:
899
- return float(re.split(",|=", line)[-1].strip(")'"))
900
- except ValueError:
901
- return None
1051
+ return res
902
1052
 
903
- res = {}
904
- _begin_search = re.compile(r"^\$begin '(.+)'")
905
- _end_search = re.compile(r"^\$end '(.+)'")
906
- amat_keys = [
907
- "thermal_conductivity",
908
- "permittivity",
909
- "dielectric_loss_tangent",
910
- "permeability",
911
- "magnetic_loss_tangent",
912
- "thermal_expansion_coeffcient",
913
- "specific_heat",
914
- "mass_density",
915
- ]
916
- keys = [
917
- "thermal_conductivity",
918
- "permittivity",
919
- "tangent_delta",
920
- "permeability",
921
- "magnetic_loss_tangent",
922
- "thermal_expansion_coeffcient",
923
- "specific_heat",
924
- "mass_density",
925
- ]
1053
+ @pyedb_function_handler()
1054
+ def read_syslib_material(self, material_name):
1055
+ """Read a specific material from syslib AMAT file.
926
1056
 
927
- with open(amat_file, "r") as amat_fh:
928
- raw_lines = amat_fh.read().splitlines()
929
- mat_found = ""
930
- for line in raw_lines:
931
- b = _begin_search.search(line)
932
- if b: # walk down a level
933
- mat_found = b.group(1)
934
- res.setdefault(mat_found, {})
935
- if mat_found:
936
- for amat_key, key in zip(amat_keys, keys):
937
- if amat_key in line:
938
- value = get_line_float_value(line)
939
- if value is not None:
940
- res[mat_found][key] = value
941
- # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
942
- if "conductivity" in line and "thermal_conductivity" not in line:
943
- value = get_line_float_value(line)
944
- if value is not None:
945
- res[mat_found]["conductivity"] = value
946
- end = _end_search.search(line)
947
- if end:
948
- mat_found = ""
949
-
950
- # Clean unwanted data
951
- try:
952
- del res["$index$"]
953
- except KeyError:
954
- pass
955
- try:
956
- del res["$base_index$"]
957
- except KeyError:
958
- pass
1057
+ Parameters
1058
+ ----------
1059
+ material_name : str
1060
+ Name of the material.
959
1061
 
1062
+ Returns
1063
+ -------
1064
+ dict
1065
+ {material name: dict of material properties}.
1066
+ """
1067
+ res = {}
1068
+ amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
1069
+ for material in self.iterate_materials_in_amat(amat_file):
1070
+ iter_material_name = material["name"]
1071
+ if iter_material_name == material_name:
1072
+ for material_property, value in material.items():
1073
+ if material_property != "name":
1074
+ res[material_property] = value
1075
+ return res
1076
+
1077
+ self.__edb.logger.error(f"Material {material_name} does not exist in syslib AMAT file.")
960
1078
  return res