pyedb 0.10.0__py3-none-any.whl → 0.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyedb might be problematic. Click here for more details.

Files changed (36) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_boundaries.py +115 -0
  3. pyedb/configuration/cfg_components.py +205 -0
  4. pyedb/configuration/cfg_data.py +38 -15
  5. pyedb/configuration/cfg_general.py +34 -0
  6. pyedb/{dotnet/sim_setup_data/data/siw_dc_ir_settings.py → configuration/cfg_nets.py} +18 -21
  7. pyedb/configuration/cfg_padstacks.py +125 -0
  8. pyedb/configuration/cfg_pin_groups.py +58 -0
  9. pyedb/configuration/cfg_ports_sources.py +164 -0
  10. pyedb/configuration/cfg_s_parameter_models.py +60 -0
  11. pyedb/configuration/cfg_setup.py +201 -0
  12. pyedb/configuration/cfg_spice_models.py +49 -0
  13. pyedb/configuration/configuration.py +37 -532
  14. pyedb/dotnet/edb.py +32 -4
  15. pyedb/dotnet/edb_core/components.py +43 -0
  16. pyedb/dotnet/edb_core/edb_data/hfss_pi_simulation_setup_data.py +465 -0
  17. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +17 -1
  18. pyedb/dotnet/edb_core/edb_data/raptor_x_simulation_setup_data.py +0 -4
  19. pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +4 -2
  20. pyedb/dotnet/edb_core/edb_data/sources.py +21 -5
  21. pyedb/dotnet/edb_core/edb_data/terminals.py +2 -1
  22. pyedb/dotnet/edb_core/layout.py +13 -8
  23. pyedb/dotnet/edb_core/padstack.py +23 -3
  24. pyedb/dotnet/edb_core/sim_setup_data/__init__.py +3 -0
  25. pyedb/dotnet/edb_core/sim_setup_data/data/__init__.py +3 -0
  26. pyedb/dotnet/edb_core/sim_setup_data/data/siw_dc_ir_settings.py +235 -0
  27. pyedb/dotnet/edb_core/siwave.py +2 -1
  28. pyedb/dotnet/edb_core/stackup.py +38 -29
  29. pyedb/dotnet/edb_core/utilities/simulation_setup.py +16 -7
  30. pyedb/siwave.py +32 -6
  31. pyedb/siwave_core/icepak.py +153 -0
  32. {pyedb-0.10.0.dist-info → pyedb-0.11.0.dist-info}/METADATA +2 -2
  33. {pyedb-0.10.0.dist-info → pyedb-0.11.0.dist-info}/RECORD +35 -22
  34. pyedb/configuration/cfg_ports.py +0 -149
  35. {pyedb-0.10.0.dist-info → pyedb-0.11.0.dist-info}/LICENSE +0 -0
  36. {pyedb-0.10.0.dist-info → pyedb-0.11.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,164 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ from pyedb.generic.general_methods import pyedb_function_handler
24
+
25
+
26
+ class CfgCircuitElement:
27
+ @property
28
+ def pedb(self):
29
+ """Edb."""
30
+ return self._pdata.pedb
31
+
32
+ @pyedb_function_handler
33
+ def __init__(self, pdata, **kwargs):
34
+ self._pdata = pdata
35
+ self._data = kwargs
36
+ self.name = kwargs.get("name", None)
37
+ self.type = kwargs.get("type", None)
38
+ self.reference_designator = kwargs.get("reference_designator", None)
39
+ self.distributed = kwargs.get("distributed", False)
40
+ self.pos_term_info = kwargs.get("positive_terminal", None) # {"pin" : "A1"}
41
+ self.neg_term_info = kwargs.get("negative_terminal", None)
42
+
43
+ @pyedb_function_handler
44
+ def _create(self):
45
+ """Create step 1."""
46
+ pos_term_info = self.pos_term_info
47
+ if pos_term_info:
48
+ pos_type, pos_value = [[i, j] for i, j in pos_term_info.items()][0]
49
+ pos_objs = dict()
50
+ if self.type == "coax":
51
+ pins = self._get_pins(pos_type, pos_value)
52
+ pins = {f"{self.name}_{self.reference_designator}": i for _, i in pins.items()}
53
+ pos_objs.update(pins)
54
+ elif pos_type == "pin_group":
55
+ pos_objs[pos_value] = self.pedb.siwave.pin_groups[pos_value]
56
+ elif not self.distributed:
57
+ # get pins
58
+ pins = self._get_pins(pos_type, pos_value) # terminal type pin or net
59
+ # create pin group
60
+ pin_group = self._create_pin_group(pins)
61
+ pos_objs.update(pin_group)
62
+ else:
63
+ # get pins
64
+ pins = self._get_pins(pos_type, pos_value) # terminal type pin or net or pin group
65
+ pos_objs.update(pins)
66
+ self._elem_num = len(pos_objs)
67
+
68
+ self.pos_terminals = {i: j.create_terminal(i) for i, j in pos_objs.items()}
69
+
70
+ neg_term_info = self.neg_term_info
71
+ self.neg_terminal = None
72
+ if neg_term_info:
73
+ neg_type, neg_value = [[i, j] for i, j in neg_term_info.items()][0]
74
+ if neg_type == "pin_group":
75
+ pin_group = {neg_value: self.pedb.siwave.pin_groups[neg_value]}
76
+ else:
77
+ # Get pins
78
+ pins = self._get_pins(neg_type, neg_value) # terminal type pin or net
79
+ # create pin group
80
+ pin_group = self._create_pin_group(pins, True)
81
+ self.neg_terminal = [j.create_terminal(i) if not j.terminal else j.terminal for i, j in pin_group.items()][
82
+ 0
83
+ ]
84
+
85
+ @pyedb_function_handler
86
+ def _get_pins(self, terminal_type, terminal_value):
87
+ terminal_value = terminal_value if isinstance(terminal_value, list) else [terminal_value]
88
+
89
+ def get_pin_obj(pin_name):
90
+ return {pin_name: self._pdata.edb_comps[self.reference_designator].pins[pin_name]}
91
+
92
+ pins = dict()
93
+ if terminal_type == "pin":
94
+ for i in terminal_value:
95
+ pins.update(get_pin_obj(i))
96
+ else:
97
+ if terminal_type == "net":
98
+ temp = self._pdata.pedb.components.get_pins(self.reference_designator, terminal_value[0])
99
+ elif terminal_type == "pin_group":
100
+ pin_group = self.pedb.siwave.pin_groups[terminal_value[0]]
101
+ temp = pin_group.pins
102
+ pins.update({f"{self.reference_designator}_{terminal_value[0]}_{i}": j for i, j in temp.items()})
103
+ return pins
104
+
105
+ @pyedb_function_handler
106
+ def _create_pin_group(self, pins, is_ref=False):
107
+ if is_ref:
108
+ pg_name = f"pg_{self.name}_{self.reference_designator}_ref"
109
+ else:
110
+ pg_name = f"pg_{self.name}_{self.reference_designator}"
111
+ pin_names = [i.pin_number for i in pins.values()]
112
+ name, temp = self._pdata.pedb.siwave.create_pin_group(self.reference_designator, pin_names, pg_name)
113
+ return {name: temp}
114
+
115
+
116
+ class CfgPort(CfgCircuitElement):
117
+ """Manage port."""
118
+
119
+ CFG_PORT_TYPE = {"circuit": [str], "coax": [str]}
120
+
121
+ @pyedb_function_handler
122
+ def __init__(self, pdata, **kwargs):
123
+ super().__init__(pdata, **kwargs)
124
+
125
+ @pyedb_function_handler
126
+ def create(self):
127
+ """Create port."""
128
+ self._create()
129
+ is_circuit_port = True if self.type == "circuit" else False
130
+ circuit_elements = []
131
+ for _, j in self.pos_terminals.items():
132
+ elem = self.pedb.create_port(j, self.neg_terminal, is_circuit_port)
133
+ if not self.distributed:
134
+ elem.name = self.name
135
+ circuit_elements.append(elem)
136
+ return circuit_elements
137
+
138
+
139
+ class CfgSources(CfgCircuitElement):
140
+ CFG_SOURCE_TYPE = {"current": [int, float], "voltage": [int, float]}
141
+
142
+ @pyedb_function_handler
143
+ def __init__(self, pdata, **kwargs):
144
+ super().__init__(pdata, **kwargs)
145
+
146
+ self.magnitude = kwargs.get("magnitude", 0.001)
147
+
148
+ @pyedb_function_handler
149
+ def create(self):
150
+ """Create sources."""
151
+ self._create()
152
+ is_circuit_port = True if self.type == "circuit" else False
153
+ circuit_elements = []
154
+ method = self.pedb.create_current_source if self.type == "current" else self.pedb.create_voltage_source
155
+ for _, j in self.pos_terminals.items():
156
+ elem = method(j, self.neg_terminal)
157
+ if not self.distributed:
158
+ elem.name = self.name
159
+ elem.magnitude = self.magnitude
160
+ else:
161
+ elem.name = f"{self.name}_{elem.name}"
162
+ elem.magnitude = self.magnitude / self._elem_num
163
+ circuit_elements.append(elem)
164
+ return circuit_elements
@@ -0,0 +1,60 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ from pathlib import Path
24
+
25
+
26
+ class CfgSParameterModel:
27
+ def __init__(self, pdata, path_lib, sparam_dict):
28
+ self._pedb = pdata.pedb
29
+ self.path_libraries = path_lib
30
+ self._sparam_dict = sparam_dict
31
+ self.name = self._sparam_dict.get("name", "")
32
+ self.component_definition = self._sparam_dict.get("component_definition", "")
33
+ self.file_path = self._sparam_dict.get("file_path", "")
34
+ self.apply_to_all = self._sparam_dict.get("apply_to_all", False)
35
+ self.components = self._sparam_dict.get("components", [])
36
+ self.reference_net = self._sparam_dict.get("reference_net", "")
37
+ self.reference_net_per_component = self._sparam_dict.get("reference_net_per_component", {})
38
+
39
+ def apply(self):
40
+ fpath = self.file_path
41
+ if not Path(fpath).anchor:
42
+ fpath = str(Path(self.path_libraries) / fpath)
43
+ comp_def = self._pedb.definitions.component[self.component_definition]
44
+ comp_def.add_n_port_model(fpath, self.name)
45
+ comp_list = dict()
46
+ if self.apply_to_all:
47
+ comp_list.update(
48
+ {refdes: comp for refdes, comp in comp_def.components.items() if refdes not in self.components}
49
+ )
50
+ else:
51
+ comp_list.update(
52
+ {refdes: comp for refdes, comp in comp_def.components.items() if refdes in self.components}
53
+ )
54
+
55
+ for refdes, comp in comp_list.items():
56
+ if refdes in self.reference_net_per_component:
57
+ ref_net = self.reference_net_per_component[refdes]
58
+ else:
59
+ ref_net = self.reference_net
60
+ comp.use_s_parameter_model(self.name, reference_net=ref_net)
@@ -0,0 +1,201 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ from enum import Enum
24
+
25
+
26
+ class FrequencySweep:
27
+ def __init__(self, sweep_dict=None):
28
+ self._sweep_dict = sweep_dict
29
+ self.name = "PyEDB_sweep"
30
+ self.type = self.SweepType.INTERPOLATING
31
+ self.distribution = [self.Distribution()]
32
+ if sweep_dict:
33
+ self.name = self._sweep_dict.get("name", "PyEDB_sweep")
34
+ frequencies = self._sweep_dict.get("frequencies", None)
35
+ self._map_sweep_type()
36
+ self.distribution = [self.Distribution(dist) for dist in frequencies]
37
+
38
+ class SweepType(Enum):
39
+ INTERPOLATING = 0
40
+ DISCRETE = 1
41
+
42
+ class Distribution:
43
+ def __init__(self, distribution_dict=None):
44
+ self.type = self.DistributionType.LINEAR_STEP
45
+ self.start = "0GHz"
46
+ self.stop = "10GHz"
47
+ self.step = "10MHz"
48
+ self.count = 100
49
+ if distribution_dict:
50
+ self.map(distribution_dict)
51
+
52
+ class DistributionType(Enum):
53
+ LINEAR_STEP = 0
54
+ LINEAR_COUNT = 1
55
+ LOG_SCALE = 2
56
+
57
+ def map(self, distribution_dict):
58
+ distribution_type = distribution_dict.get("distribution", "linear step")
59
+ if distribution_type == "linear step":
60
+ self.type = self.DistributionType.LINEAR_STEP
61
+ elif distribution_type == "linear count":
62
+ self.type = self.DistributionType.LINEAR_COUNT
63
+ elif distribution_type == "log scale":
64
+ self.type = self.DistributionType.LOG_SCALE
65
+ else:
66
+ self.type = self.DistributionType.LINEAR_STEP
67
+ self.start = distribution_dict.get("start", "OGHz")
68
+ self.stop = distribution_dict.get("stop", "10GHz")
69
+ self.step = distribution_dict.get("step", "10MHz")
70
+ self.count = distribution_dict.get("count", 100)
71
+
72
+ def _map_sweep_type(self):
73
+ if self._sweep_dict.get("type", "discrete"):
74
+ self.type = self.SweepType.DISCRETE
75
+ else:
76
+ self.type = self.SweepType.INTERPOLATING
77
+
78
+
79
+ class CfgDcSetup:
80
+ def __init__(self):
81
+ self.dc_slider_position = 1
82
+ self.dcir_settings = DcIrSettings()
83
+
84
+
85
+ class DcIrSettings:
86
+ def __init__(self):
87
+ self.export_dc_thermal_data = True
88
+
89
+
90
+ class CfgSetup:
91
+ def __init__(self, pdata, setup_dict=None):
92
+ self._pedb = pdata.pedb
93
+ self._setup_dict = None
94
+ self.name = "PyEDB_setup"
95
+ self.type = self.SetupType.HFSS
96
+ self.f_adapt = "5GHz"
97
+ self.max_num_passes = 30
98
+ self.max_mag_delta_s = 0.02
99
+ self.sweeps = [FrequencySweep()]
100
+ self.dc_settings = CfgDcSetup()
101
+ self.si_slider_position = 1
102
+ self.pi_slider_position = 1
103
+ if setup_dict:
104
+ self._setup_dict = setup_dict
105
+ self.name = setup_dict.get("name", "PyEDB_setup")
106
+ self._map_setup_type(setup_dict.get("type", None))
107
+ self.f_adapt = setup_dict.get("f_adapt", "5GHz")
108
+ self.max_mag_delta_s = setup_dict.get("max_mag_delta_s", 0.02)
109
+ if setup_dict.get("freq_sweep", None):
110
+ self.sweeps = [FrequencySweep(sweep) for sweep in setup_dict.get("freq_sweep", None)]
111
+ else:
112
+ self.sweeps = []
113
+ self.dc_settings.dc_slider_position = setup_dict.get("dc_slider_position", 1)
114
+ if setup_dict.get("dc_ir_settings", None):
115
+ dc_ir_dict = setup_dict.get("dc_ir_settings")
116
+ self.dc_settings.dcir_settings.export_dc_thermal_data = dc_ir_dict.get("export_dc_thermal_data", True)
117
+
118
+ def _map_setup_type(self, setup_type):
119
+ if setup_type.upper() == "HFSS":
120
+ self.type = self.SetupType.HFSS
121
+ elif setup_type.upper() == "HFSS_PI":
122
+ self.type = self.SetupType.HFSS_PI
123
+ elif setup_type.upper() == "SIWAVE_SYZ":
124
+ self.type = self.SetupType.SIWAVE_SYZ
125
+ elif setup_type.upper() == "SIWAVE_DC":
126
+ self.type = self.SetupType.SIWAVE_DC
127
+ elif setup_type.upper() == "RAPTORX":
128
+ self.type = self.SetupType.RAPTORX
129
+ elif setup_type.upper() == "Q3D":
130
+ self.type = self.SetupType.Q3D
131
+ else:
132
+ self.type = self.SetupType.HFSS
133
+
134
+ class SetupType(Enum):
135
+ HFSS = 0
136
+ SIWAVE_SYZ = 1
137
+ SIWAVE_DC = 2
138
+ HFSS_PI = 3
139
+ RAPTORX = 4
140
+ Q3D = 5
141
+
142
+ def apply(self):
143
+ edb_setup = None
144
+ if self.type == self.SetupType.SIWAVE_DC:
145
+ if self.name not in self._pedb.setups:
146
+ edb_setup = self._pedb.create_siwave_dc_setup(self.name)
147
+ self._pedb.logger.info("Setup {} created.".format(self.name))
148
+ else:
149
+ self._pedb.logger.warning("Setup {} already existing. Editing it.".format(self.name))
150
+ edb_setup = self._pedb.setups[self.name]
151
+ edb_setup.set_dc_slider(self.dc_settings.dc_slider_position)
152
+ # TODO add DCIR settings in EDB setup
153
+ elif self.type == self.SetupType.HFSS:
154
+ if self.name not in self._pedb.setups:
155
+ edb_setup = self._pedb.create_hfss_setup(self.name)
156
+ self._pedb.logger.info("Setup {} created.".format(self.name))
157
+ else:
158
+ self._pedb.logger.warning("Setup {} already existing. Editing it.".format(self.name))
159
+ edb_setup = self._pedb.setups[self.name]
160
+ if not edb_setup.set_solution_single_frequency(self.f_adapt, self.max_num_passes, self.max_mag_delta_s):
161
+ self._pedb.logger.errur(f"Failed to create HFSS simulation setup {self.name}")
162
+ elif self.type == self.SetupType.SIWAVE_SYZ:
163
+ if self.name not in self._pedb.setups:
164
+ edb_setup = self._pedb.create_siwave_syz_setup(self.name)
165
+ self._pedb.logger.info("Setup {} created.".format(self.name))
166
+ else:
167
+ self._pedb.logger.warning("Setup {} already existing. Editing it.".format(self.name))
168
+ edb_setup = self._pedb.setups[self.name]
169
+ edb_setup.si_slider_position = self.si_slider_position
170
+ edb_setup.pi_slider_position = self.pi_slider_position
171
+ for sweep in self.sweeps:
172
+ for dist in sweep.distribution:
173
+ freqs = []
174
+ if dist.type == dist.DistributionType.LINEAR_STEP:
175
+ freqs.append(
176
+ [
177
+ "linear scale",
178
+ self._pedb.edb_value(dist.start).ToString(),
179
+ self._pedb.edb_value(dist.stop).ToString(),
180
+ self._pedb.edb_value(dist.step).ToString(),
181
+ ]
182
+ )
183
+ elif dist.type == dist.DistributionType.LINEAR_COUNT:
184
+ freqs.append(
185
+ [
186
+ "linear count",
187
+ self._pedb.edb_value(dist.start).ToString(),
188
+ self._pedb.edb_value(dist.stop).ToString(),
189
+ int(dist.count),
190
+ ]
191
+ )
192
+ elif dist.type == dist.DistributionType.LOG_SCALE:
193
+ freqs.append(
194
+ [
195
+ "log scale",
196
+ self._pedb.edb_value(dist.start).ToString(),
197
+ self._pedb.edb_value(dist.stop).ToString(),
198
+ int(dist.count),
199
+ ]
200
+ )
201
+ edb_setup.add_frequency_sweep(sweep.name, frequency_sweep=freqs)
@@ -0,0 +1,49 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ from pathlib import Path
24
+
25
+
26
+ class CfgSpiceModel:
27
+ def __init__(self, pdata, path_lib, spice_dict):
28
+ self._pedb = pdata.pedb
29
+ self.path_libraries = path_lib
30
+ self._spice_dict = spice_dict
31
+ self.name = self._spice_dict.get("name", "")
32
+ self.component_definition = self._spice_dict.get("component_definition", "")
33
+ self.file_path = self._spice_dict.get("file_path", "")
34
+ self.sub_circuit_name = self._spice_dict.get("sub_circuit_name", "")
35
+ self.apply_to_all = self._spice_dict.get("apply_to_all", True)
36
+ self.components = list(self._spice_dict.get("components", []))
37
+
38
+ def apply(self):
39
+ """Apply Spice model on layout."""
40
+ if not Path(self.file_path).anchor:
41
+ fpath = str(Path(self.path_libraries) / self.file_path)
42
+ comps = self._pedb.components.definitions[self.component_definition].components
43
+ if self.apply_to_all:
44
+ for ref_des, comp in comps.items():
45
+ comp.assign_spice_model(fpath, self.name, self.sub_circuit_name)
46
+ else:
47
+ for ref_des, comp in comps.items():
48
+ if ref_des in self.components:
49
+ comp.assign_spice_model(fpath, self.name, self.sub_circuit_name)