pyedb 0.51.2__py3-none-any.whl → 0.53.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/configuration/cfg_common.py +12 -15
- pyedb/configuration/cfg_data.py +2 -2
- pyedb/configuration/cfg_modeler.py +163 -234
- pyedb/configuration/cfg_stackup.py +62 -249
- pyedb/configuration/configuration.py +356 -409
- pyedb/dotnet/database/components.py +9 -3
- pyedb/dotnet/database/dotnet/database.py +4 -0
- pyedb/dotnet/database/edb_data/layer_data.py +3 -1
- pyedb/dotnet/database/edb_data/padstacks_data.py +8 -2
- pyedb/dotnet/database/layout_validation.py +3 -13
- pyedb/dotnet/database/siwave.py +14 -0
- pyedb/dotnet/database/stackup.py +8 -61
- pyedb/dotnet/database/utilities/simulation_setup.py +1 -1
- pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +894 -0
- pyedb/dotnet/database/utilities/siwave_simulation_setup.py +15 -0
- pyedb/dotnet/edb.py +50 -3
- pyedb/generic/design_types.py +29 -0
- pyedb/generic/grpc_warnings.py +5 -0
- pyedb/grpc/database/__init__.py +0 -1
- pyedb/grpc/database/components.py +102 -81
- pyedb/grpc/database/control_file.py +240 -193
- pyedb/grpc/database/definition/materials.py +7 -7
- pyedb/grpc/database/definitions.py +7 -5
- pyedb/grpc/database/hierarchy/pin_pair_model.py +1 -1
- pyedb/grpc/database/modeler.py +105 -77
- pyedb/grpc/database/net/differential_pair.py +2 -1
- pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +961 -0
- pyedb/grpc/database/siwave.py +14 -0
- pyedb/grpc/database/source_excitations.py +10 -10
- pyedb/grpc/edb.py +156 -180
- pyedb/grpc/edb_init.py +4 -2
- pyedb/siwave_core/cpa/simulation_setup_data_model.py +132 -0
- pyedb/siwave_core/product_properties.py +198 -0
- {pyedb-0.51.2.dist-info → pyedb-0.53.0.dist-info}/METADATA +16 -14
- {pyedb-0.51.2.dist-info → pyedb-0.53.0.dist-info}/RECORD +38 -33
- {pyedb-0.51.2.dist-info → pyedb-0.53.0.dist-info}/WHEEL +1 -1
- {pyedb-0.51.2.dist-info → pyedb-0.53.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -19,272 +19,85 @@
|
|
|
19
19
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
# SOFTWARE.
|
|
22
|
+
from typing import List, Optional, Union
|
|
22
23
|
|
|
23
|
-
from
|
|
24
|
-
from pyedb.configuration.cfg_common import CfgBase
|
|
24
|
+
from pydantic import BaseModel, Field
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class CfgMaterialPropertyThermalModifier:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
class CfgMaterialPropertyThermalModifier(BaseModel):
|
|
28
|
+
property_name: str
|
|
29
|
+
basic_quadratic_c1: float = 0
|
|
30
|
+
basic_quadratic_c2: float = 0
|
|
31
|
+
basic_quadratic_temperature_reference: float = 22
|
|
32
|
+
advanced_quadratic_lower_limit: float = -273.15
|
|
33
|
+
advanced_quadratic_upper_limit: float = 1000
|
|
34
|
+
advanced_quadratic_auto_calculate: bool = True
|
|
35
|
+
advanced_quadratic_lower_constant: float = 1
|
|
36
|
+
advanced_quadratic_upper_constant: float = 1
|
|
35
37
|
|
|
36
|
-
self.advanced_quadratic_auto_calculate = kwargs.get("advanced_quadratic_auto_calculate", True)
|
|
37
|
-
self.advanced_quadratic_lower_constant = kwargs.get("advanced_quadratic_lower_constant", 1)
|
|
38
|
-
self.advanced_quadratic_upper_constant = kwargs.get("advanced_quadratic_upper_constant", 1)
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"property_name": self.property_name,
|
|
43
|
-
"basic_quadratic_c1": self.basic_quadratic_c1,
|
|
44
|
-
"basic_quadratic_c2": self.basic_quadratic_c2,
|
|
45
|
-
"basic_quadratic_temperature_reference": self.basic_quadratic_temperature_reference,
|
|
46
|
-
"advanced_quadratic_lower_limit": self.advanced_quadratic_lower_limit,
|
|
47
|
-
"advanced_quadratic_upper_limit": self.advanced_quadratic_upper_limit,
|
|
48
|
-
"advanced_quadratic_auto_calculate": self.advanced_quadratic_auto_calculate,
|
|
49
|
-
"advanced_quadratic_lower_constant": self.advanced_quadratic_lower_constant,
|
|
50
|
-
"advanced_quadratic_upper_constant": self.advanced_quadratic_upper_constant,
|
|
51
|
-
}
|
|
39
|
+
class MaterialProperties(BaseModel):
|
|
40
|
+
"""Store material properties."""
|
|
52
41
|
|
|
42
|
+
conductivity: Optional[Union[str, float]] = None
|
|
43
|
+
dielectric_loss_tangent: Optional[Union[str, float]] = None
|
|
44
|
+
magnetic_loss_tangent: Optional[Union[str, float]] = None
|
|
45
|
+
mass_density: Optional[Union[str, float]] = None
|
|
46
|
+
permittivity: Optional[Union[str, float]] = None
|
|
47
|
+
permeability: Optional[Union[str, float]] = None
|
|
48
|
+
poisson_ratio: Optional[Union[str, float]] = None
|
|
49
|
+
specific_heat: Optional[Union[str, float]] = None
|
|
50
|
+
thermal_conductivity: Optional[Union[str, float]] = None
|
|
51
|
+
youngs_modulus: Optional[Union[str, float]] = None
|
|
52
|
+
thermal_expansion_coefficient: Optional[Union[str, float]] = None
|
|
53
|
+
dc_conductivity: Optional[Union[str, float]] = None
|
|
54
|
+
dc_permittivity: Optional[Union[str, float]] = None
|
|
55
|
+
dielectric_model_frequency: Optional[Union[str, float]] = None
|
|
56
|
+
loss_tangent_at_frequency: Optional[Union[str, float]] = None
|
|
57
|
+
permittivity_at_frequency: Optional[Union[str, float]] = None
|
|
53
58
|
|
|
54
|
-
class CfgMaterial(CfgBase):
|
|
55
|
-
def __init__(self, **kwargs):
|
|
56
|
-
self.name = kwargs.get("name", None)
|
|
57
|
-
self.permittivity = kwargs.get("permittivity", None)
|
|
58
|
-
self.conductivity = kwargs.get("conductivity", None)
|
|
59
|
-
self.dielectric_loss_tangent = kwargs.get("dielectric_loss_tangent", None)
|
|
60
|
-
self.magnetic_loss_tangent = kwargs.get("magnetic_loss_tangent", None)
|
|
61
|
-
self.mass_density = kwargs.get("mass_density", None)
|
|
62
|
-
self.permeability = kwargs.get("permeability", None)
|
|
63
|
-
self.poisson_ratio = kwargs.get("poisson_ratio", None)
|
|
64
|
-
self.specific_heat = kwargs.get("specific_heat", None)
|
|
65
|
-
self.thermal_conductivity = kwargs.get("thermal_conductivity", None)
|
|
66
59
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
class CfgMaterial(MaterialProperties):
|
|
61
|
+
name: str
|
|
62
|
+
thermal_modifiers: Optional[list[CfgMaterialPropertyThermalModifier]] = None
|
|
70
63
|
|
|
71
64
|
|
|
72
|
-
class
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
self.fill_material = kwargs.get("fill_material", None)
|
|
78
|
-
self.thickness = kwargs.get("thickness", None)
|
|
79
|
-
self.roughness = kwargs.get("roughness", None)
|
|
80
|
-
self.etching = kwargs.get("etching", None)
|
|
65
|
+
class RoughnessSideModel(BaseModel):
|
|
66
|
+
model: str
|
|
67
|
+
nodule_radius: Optional[str] = None # e.g., '0.1um'
|
|
68
|
+
surface_ratio: Optional[str] = None # e.g., '1'
|
|
69
|
+
roughness: Optional[str] = None # e.g., '2um' for non-huray
|
|
81
70
|
|
|
82
71
|
|
|
83
|
-
class
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
72
|
+
class RoughnessModel(BaseModel):
|
|
73
|
+
enabled: Optional[bool] = False
|
|
74
|
+
top: Optional[RoughnessSideModel] = None
|
|
75
|
+
bottom: Optional[RoughnessSideModel] = None
|
|
76
|
+
side: Optional[RoughnessSideModel] = None
|
|
88
77
|
|
|
89
|
-
def apply(self):
|
|
90
|
-
"""Apply configuration settings to the current design"""
|
|
91
|
-
if len(self.parent.materials):
|
|
92
|
-
self.__apply_materials()
|
|
93
78
|
|
|
94
|
-
|
|
79
|
+
class EtchingModel(BaseModel):
|
|
80
|
+
factor: Optional[Union[float, str]] = 0.5
|
|
81
|
+
etch_power_ground_nets: Optional[bool] = False
|
|
82
|
+
enabled: Optional[bool] = False
|
|
95
83
|
|
|
96
|
-
if len(self.parent.layers):
|
|
97
|
-
if len(self._pedb.stackup.signal_layers) == 0:
|
|
98
|
-
self.__create_stackup()
|
|
99
|
-
elif not len(input_signal_layers) == len(self._pedb.stackup.signal_layers):
|
|
100
|
-
raise Exception(f"Input signal layer count do not match.")
|
|
101
|
-
else:
|
|
102
|
-
self.__apply_layers()
|
|
103
84
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
85
|
+
class CfgLayer(BaseModel):
|
|
86
|
+
name: Optional[str] = None
|
|
87
|
+
type: Optional[str] = None
|
|
88
|
+
material: Optional[str] = None
|
|
89
|
+
fill_material: Optional[str] = None
|
|
90
|
+
thickness: Optional[Union[float, str]] = None
|
|
91
|
+
roughness: Optional[RoughnessModel] = None
|
|
92
|
+
etching: Optional[EtchingModel] = None
|
|
110
93
|
|
|
111
|
-
def __apply_layers(self):
|
|
112
|
-
"""Apply layer settings to the current design"""
|
|
113
|
-
layers = list()
|
|
114
|
-
layers.extend(self.parent.layers)
|
|
115
94
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if obj.type == "dielectric":
|
|
120
|
-
removal_list.append(name)
|
|
121
|
-
elif obj.type == "signal":
|
|
122
|
-
lc_signal_layers.append(obj.id)
|
|
123
|
-
for l in removal_list:
|
|
124
|
-
self._pedb.stackup.remove_layer(l)
|
|
95
|
+
class CfgStackup(BaseModel):
|
|
96
|
+
materials: List[CfgMaterial] = Field(default_factory=list)
|
|
97
|
+
layers: List[CfgLayer] = Field(default_factory=list)
|
|
125
98
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
signal_idx = 0
|
|
129
|
-
for l in layers:
|
|
130
|
-
if l.type == "signal":
|
|
131
|
-
layer_id = lc_signal_layers[signal_idx]
|
|
132
|
-
layer_name = id_name[layer_id]
|
|
133
|
-
attrs = l.get_attributes()
|
|
134
|
-
self._pedb.stackup.layers[layer_name].update(**attrs)
|
|
135
|
-
signal_idx = signal_idx + 1
|
|
99
|
+
def add_material(self, name, **kwargs):
|
|
100
|
+
self.materials.append(CfgMaterial(name=name, **kwargs))
|
|
136
101
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
prev_layer_clone = None
|
|
140
|
-
l = layers.pop(0)
|
|
141
|
-
if l.type == "signal":
|
|
142
|
-
prev_layer_clone = self._pedb.stackup.layers[l.name]
|
|
143
|
-
else:
|
|
144
|
-
attrs = l.get_attributes()
|
|
145
|
-
prev_layer_clone = self._pedb.stackup.add_layer_top(**attrs)
|
|
146
|
-
for idx, l in enumerate(layers):
|
|
147
|
-
if l.type == "dielectric":
|
|
148
|
-
attrs = l.get_attributes()
|
|
149
|
-
prev_layer_clone = self._pedb.stackup.add_layer_below(
|
|
150
|
-
base_layer_name=prev_layer_clone.name, **attrs
|
|
151
|
-
)
|
|
152
|
-
elif l.type == "signal":
|
|
153
|
-
prev_layer_clone = self._pedb.stackup.layers[l.name]
|
|
154
|
-
|
|
155
|
-
def __apply_materials(self):
|
|
156
|
-
"""Apply material settings to the current design"""
|
|
157
|
-
materials_in_db = {i.lower(): i for i, _ in self._pedb.materials.materials.items()}
|
|
158
|
-
for mat_in_cfg in self.parent.materials:
|
|
159
|
-
if mat_in_cfg.name.lower() in materials_in_db:
|
|
160
|
-
self._pedb.materials.delete_material(materials_in_db[mat_in_cfg.name.lower()])
|
|
161
|
-
|
|
162
|
-
attrs = mat_in_cfg.get_attributes()
|
|
163
|
-
mat = self._pedb.materials.add_material(**attrs)
|
|
164
|
-
|
|
165
|
-
for i in attrs.get("thermal_modifiers", []):
|
|
166
|
-
mat.set_thermal_modifier(**i.to_dict())
|
|
167
|
-
|
|
168
|
-
def get_materials_from_db(self):
|
|
169
|
-
materials = []
|
|
170
|
-
for name, p in self._pedb.materials.materials.items():
|
|
171
|
-
mat = {}
|
|
172
|
-
for p_name in CfgMaterial().__dict__:
|
|
173
|
-
mat[p_name] = getattr(p, p_name, None)
|
|
174
|
-
materials.append(mat)
|
|
175
|
-
return materials
|
|
176
|
-
|
|
177
|
-
def get_layers_from_db(self):
|
|
178
|
-
layers = []
|
|
179
|
-
for name, obj in self._pedb.stackup.all_layers.items():
|
|
180
|
-
layers.append(obj.properties)
|
|
181
|
-
return layers
|
|
182
|
-
|
|
183
|
-
def get_data_from_db(self):
|
|
184
|
-
"""Get configuration data from layout.
|
|
185
|
-
|
|
186
|
-
Returns
|
|
187
|
-
-------
|
|
188
|
-
dict
|
|
189
|
-
"""
|
|
190
|
-
stackup = {}
|
|
191
|
-
materials = self.get_materials_from_db()
|
|
192
|
-
stackup["materials"] = materials
|
|
193
|
-
layers = self.get_layers_from_db()
|
|
194
|
-
stackup["layers"] = layers
|
|
195
|
-
return stackup
|
|
196
|
-
|
|
197
|
-
class DotNet(Grpc):
|
|
198
|
-
def __init__(self, parent):
|
|
199
|
-
super().__init__(parent)
|
|
200
|
-
|
|
201
|
-
def __apply_layers(self):
|
|
202
|
-
"""Apply layer settings to the current design"""
|
|
203
|
-
layers = list()
|
|
204
|
-
layers.extend(self.parent.layers)
|
|
205
|
-
|
|
206
|
-
removal_list = []
|
|
207
|
-
lc_signal_layers = []
|
|
208
|
-
for name, obj in self._pedb.stackup.all_layers.items():
|
|
209
|
-
if obj.type == "dielectric":
|
|
210
|
-
removal_list.append(name)
|
|
211
|
-
elif obj.type == "signal":
|
|
212
|
-
lc_signal_layers.append(obj.id)
|
|
213
|
-
for l in removal_list:
|
|
214
|
-
self._pedb.stackup.remove_layer(l)
|
|
215
|
-
|
|
216
|
-
# update all signal layers
|
|
217
|
-
id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
|
|
218
|
-
signal_idx = 0
|
|
219
|
-
for l in layers:
|
|
220
|
-
if l.type == "signal":
|
|
221
|
-
layer_id = lc_signal_layers[signal_idx]
|
|
222
|
-
layer_name = id_name[layer_id]
|
|
223
|
-
attrs = l.get_attributes()
|
|
224
|
-
self._pedb.stackup.layers[layer_name].update(**attrs)
|
|
225
|
-
signal_idx = signal_idx + 1
|
|
226
|
-
|
|
227
|
-
# add all dielectric layers. Dielectric layers must be added last. Otherwise,
|
|
228
|
-
# dielectric layer will occupy signal and document layer id.
|
|
229
|
-
prev_layer_clone = None
|
|
230
|
-
l = layers.pop(0)
|
|
231
|
-
if l.type == "signal":
|
|
232
|
-
prev_layer_clone = self._pedb.stackup.layers[l.name]
|
|
233
|
-
else:
|
|
234
|
-
attrs = l.get_attributes()
|
|
235
|
-
prev_layer_clone = self._pedb.stackup.add_layer_top(**attrs)
|
|
236
|
-
for idx, l in enumerate(layers):
|
|
237
|
-
if l.type == "dielectric":
|
|
238
|
-
attrs = l.get_attributes()
|
|
239
|
-
prev_layer_clone = self._pedb.stackup.add_layer_below(
|
|
240
|
-
base_layer_name=prev_layer_clone.name, **attrs
|
|
241
|
-
)
|
|
242
|
-
elif l.type == "signal":
|
|
243
|
-
prev_layer_clone = self._pedb.stackup.layers[l.name]
|
|
244
|
-
|
|
245
|
-
def __init__(self, pedb: Edb, data):
|
|
246
|
-
self._pedb = pedb
|
|
247
|
-
if self._pedb.grpc:
|
|
248
|
-
self.api = self.Grpc(self)
|
|
249
|
-
else:
|
|
250
|
-
self.api = self.DotNet(self)
|
|
251
|
-
self.materials = [CfgMaterial(**mat) for mat in data.get("materials", [])]
|
|
252
|
-
self.layers = [CfgLayer(**lay) for lay in data.get("layers", [])]
|
|
253
|
-
|
|
254
|
-
materials = [m.name for m in self.materials]
|
|
255
|
-
for i in self.layers:
|
|
256
|
-
if i.type == "signal":
|
|
257
|
-
if i.material not in materials:
|
|
258
|
-
self.materials.append(
|
|
259
|
-
CfgMaterial(name=i.material, **self._pedb.materials.default_conductor_property_values)
|
|
260
|
-
)
|
|
261
|
-
materials.append(i.material)
|
|
262
|
-
if i.fill_material not in materials:
|
|
263
|
-
self.materials.append(
|
|
264
|
-
CfgMaterial(name=i.fill_material, **self._pedb.materials.default_dielectric_property_values)
|
|
265
|
-
)
|
|
266
|
-
materials.append(i.fill_material)
|
|
267
|
-
elif i.type == "dielectric":
|
|
268
|
-
if i.material not in materials:
|
|
269
|
-
self.materials.append(
|
|
270
|
-
CfgMaterial(name=i.material, **self._pedb.materials.default_dielectric_property_values)
|
|
271
|
-
)
|
|
272
|
-
materials.append(i.material)
|
|
273
|
-
|
|
274
|
-
def apply(self):
|
|
275
|
-
self.api.apply()
|
|
276
|
-
|
|
277
|
-
def get_materials_from_db(self):
|
|
278
|
-
return self.api.get_materials_from_db()
|
|
279
|
-
|
|
280
|
-
def get_layers_from_db(self):
|
|
281
|
-
return self.api.get_layers_from_db()
|
|
282
|
-
|
|
283
|
-
def get_data_from_db(self):
|
|
284
|
-
"""Get configuration data from layout.
|
|
285
|
-
|
|
286
|
-
Returns
|
|
287
|
-
-------
|
|
288
|
-
dict
|
|
289
|
-
"""
|
|
290
|
-
return self.api.get_data_from_db()
|
|
102
|
+
def add_layer_at_bottom(self, name, **kwargs):
|
|
103
|
+
self.layers.append(CfgLayer(name=name, **kwargs))
|