pyedb 0.52.0__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.

@@ -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 pyedb import Edb
24
- from pyedb.configuration.cfg_common import CfgBase
24
+ from pydantic import BaseModel, Field
25
25
 
26
26
 
27
- class CfgMaterialPropertyThermalModifier:
28
- def __init__(self, **kwargs):
29
- self.property_name = kwargs["property_name"]
30
- self.basic_quadratic_c1 = kwargs.get("basic_quadratic_c1", 0)
31
- self.basic_quadratic_c2 = kwargs.get("basic_quadratic_c2", 0)
32
- self.basic_quadratic_temperature_reference = kwargs.get("basic_quadratic_temperature_reference", 22)
33
- self.advanced_quadratic_lower_limit = kwargs.get("advanced_quadratic_lower_limit", -273.15)
34
- self.advanced_quadratic_upper_limit = kwargs.get("advanced_quadratic_upper_limit", 1000)
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
- def to_dict(self):
41
- return {
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
- thermal_modifiers = kwargs.get("thermal_modifiers")
68
- if thermal_modifiers:
69
- self.thermal_modifiers = [CfgMaterialPropertyThermalModifier(**i) for i in thermal_modifiers]
60
+ class CfgMaterial(MaterialProperties):
61
+ name: str
62
+ thermal_modifiers: Optional[list[CfgMaterialPropertyThermalModifier]] = None
70
63
 
71
64
 
72
- class CfgLayer(CfgBase):
73
- def __init__(self, **kwargs):
74
- self.name = kwargs.get("name", None)
75
- self.type = kwargs.get("type", None)
76
- self.material = kwargs.get("material", None)
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 CfgStackup:
84
- class Grpc:
85
- def __init__(self, parent):
86
- self.parent = parent
87
- self._pedb = parent._pedb
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
- input_signal_layers = [i for i in self.parent.layers if i.type.lower() == "signal"]
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
- def __create_stackup(self):
105
- layers = list()
106
- layers.extend(self.parent.layers)
107
- for l_attrs in layers:
108
- attrs = l_attrs.get_attributes()
109
- self._pedb.stackup.add_layer_bottom(**attrs)
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
- removal_list = []
117
- lc_signal_layers = []
118
- for name, obj in self._pedb.stackup.all_layers.items():
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
- # update all signal layers
127
- id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
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
- # add all dielectric layers. Dielectric layers must be added last. Otherwise,
138
- # dielectric layer will occupy signal and document layer id.
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))