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.
- pyedb/__init__.py +1 -1
- pyedb/dotnet/clr_module.py +1 -1
- pyedb/dotnet/edb.py +7 -7
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/edb_core/components.py +15 -12
- pyedb/dotnet/edb_core/configuration.py +232 -25
- pyedb/dotnet/edb_core/definition/component_def.py +10 -1
- pyedb/dotnet/edb_core/definition/component_model.py +1 -1
- pyedb/dotnet/edb_core/definition/definition_obj.py +1 -1
- pyedb/dotnet/edb_core/definition/definitions.py +8 -2
- pyedb/dotnet/edb_core/definition/package_def.py +61 -15
- pyedb/dotnet/edb_core/dotnet/database.py +5 -4
- pyedb/dotnet/edb_core/edb_data/components_data.py +3 -2
- pyedb/dotnet/edb_core/edb_data/connectable.py +1 -1
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +14 -13
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +2 -2
- pyedb/dotnet/edb_core/edb_data/layer_data.py +9 -3
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +6 -5
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +16 -13
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +7 -1
- pyedb/dotnet/edb_core/edb_data/sources.py +10 -0
- pyedb/dotnet/edb_core/geometry/__init__.py +0 -0
- pyedb/dotnet/edb_core/{edb_data/obj_base.py → geometry/point_data.py} +12 -26
- pyedb/dotnet/edb_core/geometry/polygon_data.py +77 -0
- pyedb/dotnet/edb_core/layout.py +59 -0
- pyedb/dotnet/edb_core/materials.py +715 -597
- pyedb/dotnet/edb_core/nets.py +3 -3
- pyedb/dotnet/edb_core/obj_base.py +94 -0
- pyedb/dotnet/edb_core/padstack.py +57 -6
- pyedb/dotnet/edb_core/siwave.py +11 -4
- pyedb/dotnet/edb_core/stackup.py +152 -131
- pyedb/dotnet/edb_core/utilities/__init__.py +3 -0
- pyedb/dotnet/edb_core/utilities/heatsink.py +69 -0
- pyedb/dotnet/sim_setup_data/data/siw_dc_ir_settings.py +46 -0
- pyedb/edb_logger.py +15 -1
- pyedb/exceptions.py +6 -0
- pyedb/generic/filesystem.py +7 -3
- pyedb/generic/general_methods.py +4 -0
- pyedb/generic/process.py +4 -1
- pyedb/generic/settings.py +30 -8
- pyedb/siwave.py +50 -1
- {pyedb-0.7.0.dist-info → pyedb-0.8.0.dist-info}/METADATA +31 -53
- {pyedb-0.7.0.dist-info → pyedb-0.8.0.dist-info}/RECORD +46 -39
- /pyedb/dotnet/edb_core/{edb_data → utilities}/simulation_setup.py +0 -0
- {pyedb-0.7.0.dist-info → pyedb-0.8.0.dist-info}/LICENSE +0 -0
- {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
|
-
"""
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
72
|
-
|
|
122
|
+
def name(self):
|
|
123
|
+
"""Material name."""
|
|
124
|
+
return self.__name
|
|
73
125
|
|
|
74
126
|
@property
|
|
75
|
-
def
|
|
76
|
-
|
|
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
|
-
|
|
94
|
-
self.
|
|
95
|
-
|
|
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
|
-
"""
|
|
100
|
-
|
|
101
|
-
self.
|
|
102
|
-
self.
|
|
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
|
-
"""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
"""
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
"""
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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.
|
|
147
|
-
|
|
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
|
-
|
|
152
|
-
|
|
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.
|
|
158
|
-
|
|
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
|
-
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
179
|
-
|
|
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
|
-
|
|
184
|
-
|
|
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
|
-
|
|
189
|
-
|
|
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
|
-
|
|
194
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
"""
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
"""
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
"""
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
"""
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
"""
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
"""
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
"""
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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
|
|
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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
|
387
|
-
|
|
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
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
self.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
"""
|
|
401
|
-
return self.
|
|
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
|
|
409
|
-
|
|
505
|
+
def materials(self):
|
|
506
|
+
"""Get materials."""
|
|
507
|
+
return self.__materials
|
|
410
508
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
return self._pedb.active_db
|
|
509
|
+
def __edb_value(self, value):
|
|
510
|
+
"""Convert a value to an EDB value.
|
|
414
511
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
|
435
|
-
Material
|
|
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
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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,
|
|
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
|
-
|
|
502
|
-
|
|
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
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
|
|
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
|
|
539
|
-
self,
|
|
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
|
-
"""
|
|
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
|
-
|
|
613
|
+
permittivity_at_frequency : str, float, int
|
|
548
614
|
Relative permittivity of the dielectric.
|
|
549
|
-
|
|
615
|
+
loss_tangent_at_frequency : str, float, int
|
|
550
616
|
Loss tangent for the material.
|
|
551
|
-
|
|
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
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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
|
-
|
|
632
|
+
material_model.SetDCConductivity(dc_conductivity)
|
|
569
633
|
if dc_permittivity is not None:
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
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
|
-
"""
|
|
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
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
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
|
-
|
|
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
|
-
"""
|
|
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
|
-
|
|
660
|
-
|
|
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
|
-
|
|
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
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
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
|
-
|
|
675
|
-
|
|
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
|
-
|
|
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
|
-
|
|
695
|
-
|
|
825
|
+
self.__materials[new_material_name] = new_material
|
|
826
|
+
return new_material
|
|
696
827
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
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
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
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
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
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
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
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
|
|
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
|
-
|
|
889
|
+
Any
|
|
770
890
|
"""
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
"
|
|
774
|
-
"
|
|
775
|
-
"
|
|
776
|
-
"
|
|
777
|
-
"
|
|
778
|
-
"
|
|
779
|
-
"
|
|
780
|
-
"
|
|
781
|
-
"
|
|
782
|
-
"
|
|
783
|
-
"
|
|
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
|
-
|
|
787
|
-
|
|
788
|
-
|
|
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
|
|
918
|
+
return property_name_to_id["InvalidProperty"]
|
|
791
919
|
|
|
792
920
|
@pyedb_function_handler()
|
|
793
|
-
def
|
|
794
|
-
"""
|
|
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
|
-
|
|
800
|
-
|
|
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
|
-
|
|
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
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
if
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
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
|
-
|
|
834
|
-
|
|
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
|
|
844
|
-
"""
|
|
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
|
|
961
|
+
Full path to the AMAT file to read.
|
|
850
962
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
963
|
+
Yields
|
|
964
|
+
------
|
|
965
|
+
dict
|
|
854
966
|
"""
|
|
855
|
-
if
|
|
856
|
-
self.
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
if
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
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
|