pyedb 0.38.0__py3-none-any.whl → 0.39.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 (205) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/common/nets.py +53 -139
  3. pyedb/configuration/cfg_components.py +1 -1
  4. pyedb/configuration/cfg_general.py +4 -2
  5. pyedb/configuration/cfg_modeler.py +1 -1
  6. pyedb/configuration/cfg_package_definition.py +1 -1
  7. pyedb/configuration/cfg_padstacks.py +1 -1
  8. pyedb/configuration/cfg_ports_sources.py +56 -23
  9. pyedb/configuration/configuration.py +18 -1
  10. pyedb/dotnet/{application → database}/Variables.py +21 -21
  11. pyedb/dotnet/{edb_core → database}/cell/connectable.py +5 -5
  12. pyedb/dotnet/{edb_core → database}/cell/hierarchy/component.py +11 -11
  13. pyedb/dotnet/{edb_core → database}/cell/hierarchy/hierarchy_obj.py +1 -1
  14. pyedb/dotnet/{edb_core → database}/cell/hierarchy/model.py +1 -1
  15. pyedb/dotnet/{edb_core → database}/cell/layout.py +17 -17
  16. pyedb/dotnet/{edb_core → database}/cell/layout_obj.py +3 -3
  17. pyedb/dotnet/{edb_core → database}/cell/primitive/bondwire.py +1 -1
  18. pyedb/dotnet/{edb_core → database}/cell/primitive/path.py +4 -4
  19. pyedb/dotnet/{edb_core → database}/cell/primitive/primitive.py +14 -14
  20. pyedb/dotnet/{edb_core → database}/cell/terminal/bundle_terminal.py +2 -2
  21. pyedb/dotnet/{edb_core → database}/cell/terminal/edge_terminal.py +4 -4
  22. pyedb/dotnet/{edb_core → database}/cell/terminal/padstack_instance_terminal.py +2 -2
  23. pyedb/dotnet/{edb_core → database}/cell/terminal/pingroup_terminal.py +2 -2
  24. pyedb/dotnet/{edb_core → database}/cell/terminal/point_terminal.py +2 -2
  25. pyedb/dotnet/{edb_core → database}/cell/terminal/terminal.py +11 -11
  26. pyedb/dotnet/{edb_core → database}/cell/voltage_regulator.py +2 -2
  27. pyedb/dotnet/{edb_core → database}/components.py +101 -124
  28. pyedb/dotnet/{edb_core → database}/definition/component_def.py +5 -5
  29. pyedb/dotnet/{edb_core → database}/definition/component_model.py +1 -1
  30. pyedb/dotnet/{edb_core → database}/definition/definition_obj.py +1 -1
  31. pyedb/dotnet/{edb_core → database}/definition/definitions.py +2 -2
  32. pyedb/dotnet/{edb_core → database}/definition/package_def.py +4 -4
  33. pyedb/dotnet/{edb_core → database}/dotnet/database.py +8 -8
  34. pyedb/dotnet/{edb_core → database}/dotnet/primitive.py +9 -9
  35. pyedb/dotnet/{edb_core → database}/edb_data/control_file.py +12 -12
  36. pyedb/dotnet/{edb_core → database}/edb_data/hfss_extent_info.py +7 -7
  37. pyedb/dotnet/{edb_core → database}/edb_data/nets_data.py +10 -13
  38. pyedb/dotnet/{edb_core → database}/edb_data/padstacks_data.py +16 -16
  39. pyedb/dotnet/{edb_core → database}/edb_data/ports.py +4 -4
  40. pyedb/dotnet/{edb_core → database}/edb_data/primitives_data.py +5 -5
  41. pyedb/dotnet/{edb_core → database}/edb_data/raptor_x_simulation_setup_data.py +4 -4
  42. pyedb/dotnet/{edb_core → database}/edb_data/simulation_configuration.py +10 -10
  43. pyedb/dotnet/{edb_core → database}/edb_data/sources.py +4 -4
  44. pyedb/dotnet/{edb_core → database}/edb_data/variables.py +1 -1
  45. pyedb/dotnet/{edb_core → database}/geometry/polygon_data.py +4 -4
  46. pyedb/dotnet/{edb_core → database}/hfss.py +8 -8
  47. pyedb/dotnet/{edb_core → database}/layout_obj_instance.py +1 -1
  48. pyedb/dotnet/{edb_core → database}/layout_validation.py +2 -2
  49. pyedb/dotnet/{edb_core → database}/materials.py +23 -8
  50. pyedb/dotnet/{edb_core → database}/modeler.py +27 -27
  51. pyedb/dotnet/{edb_core → database}/net_class.py +8 -8
  52. pyedb/dotnet/{edb_core → database}/nets.py +12 -12
  53. pyedb/dotnet/{edb_core → database}/padstack.py +15 -15
  54. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/mesh_operation.py +1 -1
  55. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/settings.py +3 -3
  56. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sim_setup_info.py +2 -2
  57. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/simulation_settings.py +1 -1
  58. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/siw_dc_ir_settings.py +1 -1
  59. pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sweep_data.py +1 -1
  60. pyedb/dotnet/{edb_core → database}/siwave.py +10 -10
  61. pyedb/dotnet/{edb_core → database}/stackup.py +12 -12
  62. pyedb/dotnet/{edb_core → database}/utilities/hfss_simulation_setup.py +15 -15
  63. pyedb/dotnet/{edb_core → database}/utilities/obj_base.py +1 -1
  64. pyedb/dotnet/{edb_core → database}/utilities/simulation_setup.py +3 -3
  65. pyedb/dotnet/{edb_core → database}/utilities/siwave_simulation_setup.py +6 -6
  66. pyedb/dotnet/edb.py +117 -112
  67. pyedb/generic/design_types.py +26 -19
  68. pyedb/generic/general_methods.py +1 -1
  69. pyedb/generic/plot.py +0 -2
  70. pyedb/grpc/database/__init__.py +1 -0
  71. pyedb/grpc/database/components.py +2354 -0
  72. pyedb/grpc/database/control_file.py +1277 -0
  73. pyedb/grpc/database/definition/component_def.py +218 -0
  74. pyedb/grpc/database/definition/component_model.py +39 -0
  75. pyedb/grpc/database/definition/component_pin.py +32 -0
  76. pyedb/grpc/database/definition/materials.py +1207 -0
  77. pyedb/grpc/database/definition/n_port_component_model.py +34 -0
  78. pyedb/grpc/database/definition/package_def.py +227 -0
  79. pyedb/grpc/database/definition/padstack_def.py +842 -0
  80. pyedb/grpc/database/definitions.py +70 -0
  81. pyedb/grpc/database/general.py +43 -0
  82. pyedb/grpc/database/geometry/__init__.py +0 -0
  83. pyedb/grpc/database/geometry/arc_data.py +93 -0
  84. pyedb/grpc/database/geometry/point_3d_data.py +79 -0
  85. pyedb/grpc/database/geometry/point_data.py +30 -0
  86. pyedb/grpc/database/geometry/polygon_data.py +133 -0
  87. pyedb/grpc/database/hfss.py +1279 -0
  88. pyedb/grpc/database/hierarchy/__init__.py +0 -0
  89. pyedb/grpc/database/hierarchy/component.py +1301 -0
  90. pyedb/grpc/database/hierarchy/model.py +31 -0
  91. pyedb/grpc/database/hierarchy/netlist_model.py +30 -0
  92. pyedb/grpc/database/hierarchy/pin_pair_model.py +128 -0
  93. pyedb/grpc/database/hierarchy/pingroup.py +245 -0
  94. pyedb/grpc/database/hierarchy/s_parameter_model.py +33 -0
  95. pyedb/grpc/database/hierarchy/spice_model.py +48 -0
  96. pyedb/grpc/database/layers/__init__.py +0 -0
  97. pyedb/grpc/database/layers/layer.py +57 -0
  98. pyedb/grpc/database/layers/stackup_layer.py +410 -0
  99. pyedb/grpc/database/layout/__init__.py +0 -0
  100. pyedb/grpc/database/layout/cell.py +30 -0
  101. pyedb/grpc/database/layout/layout.py +196 -0
  102. pyedb/grpc/database/layout/voltage_regulator.py +149 -0
  103. pyedb/grpc/database/layout_validation.py +319 -0
  104. pyedb/grpc/database/modeler.py +1468 -0
  105. pyedb/grpc/database/net/__init__.py +0 -0
  106. pyedb/grpc/database/net/differential_pair.py +138 -0
  107. pyedb/grpc/database/net/extended_net.py +340 -0
  108. pyedb/grpc/database/net/net.py +198 -0
  109. pyedb/grpc/database/net/net_class.py +93 -0
  110. pyedb/grpc/database/nets.py +633 -0
  111. pyedb/grpc/database/padstacks.py +1500 -0
  112. pyedb/grpc/database/ports/__init__.py +0 -0
  113. pyedb/grpc/database/ports/ports.py +396 -0
  114. pyedb/grpc/database/primitive/__init__.py +3 -0
  115. pyedb/grpc/database/primitive/bondwire.py +181 -0
  116. pyedb/grpc/database/primitive/circle.py +75 -0
  117. pyedb/grpc/database/primitive/padstack_instance.py +1116 -0
  118. pyedb/grpc/database/primitive/path.py +346 -0
  119. pyedb/grpc/database/primitive/polygon.py +276 -0
  120. pyedb/grpc/database/primitive/primitive.py +739 -0
  121. pyedb/grpc/database/primitive/rectangle.py +146 -0
  122. pyedb/grpc/database/simulation_setup/__init__.py +0 -0
  123. pyedb/grpc/database/simulation_setup/adaptive_frequency.py +33 -0
  124. pyedb/grpc/database/simulation_setup/hfss_advanced_meshing_settings.py +32 -0
  125. pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +59 -0
  126. pyedb/grpc/database/simulation_setup/hfss_dcr_settings.py +35 -0
  127. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +61 -0
  128. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +78 -0
  129. pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +118 -0
  130. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +355 -0
  131. pyedb/grpc/database/simulation_setup/hfss_solver_settings.py +34 -0
  132. pyedb/grpc/database/simulation_setup/mesh_operation.py +34 -0
  133. pyedb/grpc/database/simulation_setup/raptor_x_advanced_settings.py +34 -0
  134. pyedb/grpc/database/simulation_setup/raptor_x_general_settings.py +33 -0
  135. pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +64 -0
  136. pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +125 -0
  137. pyedb/grpc/database/simulation_setup/siwave_dcir_simulation_setup.py +34 -0
  138. pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +119 -0
  139. pyedb/grpc/database/simulation_setup/sweep_data.py +32 -0
  140. pyedb/grpc/database/siwave.py +1023 -0
  141. pyedb/grpc/database/source_excitations.py +2572 -0
  142. pyedb/grpc/database/stackup.py +2574 -0
  143. pyedb/grpc/database/terminal/__init__.py +0 -0
  144. pyedb/grpc/database/terminal/bundle_terminal.py +218 -0
  145. pyedb/grpc/database/terminal/edge_terminal.py +51 -0
  146. pyedb/grpc/database/terminal/padstack_instance_terminal.py +171 -0
  147. pyedb/grpc/database/terminal/pingroup_terminal.py +162 -0
  148. pyedb/grpc/database/terminal/point_terminal.py +99 -0
  149. pyedb/grpc/database/terminal/terminal.py +470 -0
  150. pyedb/grpc/database/utility/__init__.py +3 -0
  151. pyedb/grpc/database/utility/constants.py +25 -0
  152. pyedb/grpc/database/utility/heat_sink.py +124 -0
  153. pyedb/grpc/database/utility/hfss_extent_info.py +448 -0
  154. pyedb/grpc/database/utility/layout_statistics.py +277 -0
  155. pyedb/grpc/database/utility/rlc.py +80 -0
  156. pyedb/grpc/database/utility/simulation_configuration.py +3305 -0
  157. pyedb/grpc/database/utility/sources.py +388 -0
  158. pyedb/grpc/database/utility/sweep_data_distribution.py +83 -0
  159. pyedb/grpc/database/utility/xml_control_file.py +1277 -0
  160. pyedb/grpc/edb.py +4151 -0
  161. pyedb/grpc/edb_init.py +481 -0
  162. pyedb/grpc/rpc_session.py +177 -0
  163. pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +3 -2
  164. pyedb/ipc2581/ecad/cad_data/feature.py +4 -3
  165. pyedb/ipc2581/ecad/cad_data/layer_feature.py +32 -20
  166. pyedb/ipc2581/ecad/cad_data/outline.py +3 -2
  167. pyedb/ipc2581/ecad/cad_data/package.py +4 -3
  168. pyedb/ipc2581/ecad/cad_data/path.py +82 -31
  169. pyedb/ipc2581/ecad/cad_data/polygon.py +122 -60
  170. pyedb/ipc2581/ecad/cad_data/profile.py +13 -12
  171. pyedb/ipc2581/ecad/cad_data/step.py +53 -21
  172. pyedb/ipc2581/ipc2581.py +47 -49
  173. pyedb/modeler/geometry_operators.py +1 -1
  174. {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/METADATA +5 -2
  175. pyedb-0.39.0.dist-info/RECORD +288 -0
  176. pyedb-0.38.0.dist-info/RECORD +0 -195
  177. /pyedb/dotnet/{edb_core → database}/__init__.py +0 -0
  178. /pyedb/dotnet/{application → database/cell}/__init__.py +0 -0
  179. /pyedb/dotnet/{edb_core/cell → database/cell/hierarchy}/__init__.py +0 -0
  180. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/netlist_model.py +0 -0
  181. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/pin_pair_model.py +0 -0
  182. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/s_parameter_model.py +0 -0
  183. /pyedb/dotnet/{edb_core → database}/cell/hierarchy/spice_model.py +0 -0
  184. /pyedb/dotnet/{edb_core → database}/cell/primitive/__init__.py +0 -0
  185. /pyedb/dotnet/{edb_core/cell/hierarchy → database/cell/terminal}/__init__.py +0 -0
  186. /pyedb/dotnet/{edb_core/cell/terminal → database/definition}/__init__.py +0 -0
  187. /pyedb/dotnet/{edb_core/definition → database/dotnet}/__init__.py +0 -0
  188. /pyedb/dotnet/{edb_core/dotnet → database/edb_data}/__init__.py +0 -0
  189. /pyedb/dotnet/{edb_core → database}/edb_data/design_options.py +0 -0
  190. /pyedb/dotnet/{edb_core → database}/edb_data/edbvalue.py +0 -0
  191. /pyedb/dotnet/{edb_core → database}/edb_data/layer_data.py +0 -0
  192. /pyedb/dotnet/{edb_core → database}/edb_data/utilities.py +0 -0
  193. /pyedb/dotnet/{edb_core → database}/general.py +0 -0
  194. /pyedb/dotnet/{edb_core/edb_data → database/geometry}/__init__.py +0 -0
  195. /pyedb/dotnet/{edb_core → database}/geometry/point_data.py +0 -0
  196. /pyedb/dotnet/{edb_core → database}/sim_setup_data/__init__.py +0 -0
  197. /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/__init__.py +0 -0
  198. /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/adaptive_frequency_data.py +0 -0
  199. /pyedb/dotnet/{edb_core/geometry → database/sim_setup_data/io}/__init__.py +0 -0
  200. /pyedb/dotnet/{edb_core → database}/sim_setup_data/io/siwave.py +0 -0
  201. /pyedb/dotnet/{edb_core → database}/utilities/__init__.py +0 -0
  202. /pyedb/dotnet/{edb_core → database}/utilities/heatsink.py +0 -0
  203. /pyedb/{dotnet/edb_core/sim_setup_data/io → grpc/database/definition}/__init__.py +0 -0
  204. {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/LICENSE +0 -0
  205. {pyedb-0.38.0.dist-info → pyedb-0.39.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,1207 @@
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 __future__ import absolute_import # noreorder
24
+
25
+ import difflib
26
+ import logging
27
+ import os
28
+ import re
29
+ from typing import Optional
30
+ import warnings
31
+
32
+ from ansys.edb.core.definition.debye_model import DebyeModel as GrpcDebyeModel
33
+ from ansys.edb.core.definition.djordjecvic_sarkar_model import (
34
+ DjordjecvicSarkarModel as GrpcDjordjecvicSarkarModel,
35
+ )
36
+ from ansys.edb.core.definition.material_def import (
37
+ MaterialProperty as GrpcMaterialProperty,
38
+ )
39
+ from ansys.edb.core.definition.material_def import MaterialDef as GrpcMaterialDef
40
+ from ansys.edb.core.definition.multipole_debye_model import (
41
+ MultipoleDebyeModel as GrpcMultipoleDebyeModel,
42
+ )
43
+ from ansys.edb.core.utility.value import Value as GrpcValue
44
+ from pydantic import BaseModel, confloat
45
+
46
+ from pyedb import Edb
47
+ from pyedb.exceptions import MaterialModelException
48
+
49
+ logger = logging.getLogger(__name__)
50
+
51
+ # TODO: Once we are Python3.9+ change PositiveInt implementation like
52
+ # from annotated_types import Gt
53
+ # from typing_extensions import Annotated
54
+ # PositiveFloat = Annotated[float, Gt(0)]
55
+ try:
56
+ from annotated_types import Gt
57
+ from typing_extensions import Annotated
58
+
59
+ PositiveFloat = Annotated[float, Gt(0)]
60
+ except:
61
+ PositiveFloat = confloat(gt=0)
62
+
63
+ ATTRIBUTES = [
64
+ "conductivity",
65
+ "dielectric_loss_tangent",
66
+ "magnetic_loss_tangent",
67
+ "mass_density",
68
+ "permittivity",
69
+ "permeability",
70
+ "poisson_ratio",
71
+ "specific_heat",
72
+ "thermal_conductivity",
73
+ "youngs_modulus",
74
+ "thermal_expansion_coefficient",
75
+ ]
76
+ DC_ATTRIBUTES = [
77
+ "dielectric_model_frequency",
78
+ "loss_tangent_at_frequency",
79
+ "permittivity_at_frequency",
80
+ "dc_conductivity",
81
+ "dc_permittivity",
82
+ ]
83
+ PERMEABILITY_DEFAULT_VALUE = 1
84
+
85
+
86
+ def get_line_float_value(line):
87
+ """Retrieve the float value expected in the line of an AMAT file.
88
+
89
+ The associated string is expected to follow one of the following cases:
90
+ - simple('permittivity', 12.)
91
+ - permittivity='12'.
92
+ """
93
+ try:
94
+ return float(re.split(",|=", line)[-1].strip("'\n)"))
95
+ except ValueError:
96
+ return None
97
+
98
+
99
+ class MaterialProperties(BaseModel):
100
+ """Store material properties."""
101
+
102
+ conductivity: Optional[PositiveFloat] = None
103
+ dielectric_loss_tangent: Optional[PositiveFloat] = None
104
+ magnetic_loss_tangent: Optional[PositiveFloat] = None
105
+ mass_density: Optional[PositiveFloat] = None
106
+ permittivity: Optional[PositiveFloat] = None
107
+ permeability: Optional[PositiveFloat] = None
108
+ poisson_ratio: Optional[PositiveFloat] = None
109
+ specific_heat: Optional[PositiveFloat] = None
110
+ thermal_conductivity: Optional[PositiveFloat] = None
111
+ youngs_modulus: Optional[PositiveFloat] = None
112
+ thermal_expansion_coefficient: Optional[PositiveFloat] = None
113
+ dc_conductivity: Optional[PositiveFloat] = None
114
+ dc_permittivity: Optional[PositiveFloat] = None
115
+ dielectric_model_frequency: Optional[PositiveFloat] = None
116
+ loss_tangent_at_frequency: Optional[PositiveFloat] = None
117
+ permittivity_at_frequency: Optional[PositiveFloat] = None
118
+
119
+
120
+ class Material(GrpcMaterialDef):
121
+ """Manage EDB methods for material property management."""
122
+
123
+ def __init__(self, edb: Edb, edb_material_def):
124
+ super().__init__(edb_material_def.msg)
125
+ self.__edb: Edb = edb
126
+ self.__name: str = edb_material_def.name
127
+ self.__material_def = edb_material_def
128
+ self.__dielectric_model = None
129
+
130
+ @property
131
+ def name(self):
132
+ """Material name.
133
+
134
+ Returns
135
+ -------
136
+ str
137
+ Material name.
138
+ """
139
+ return self.__name
140
+
141
+ @property
142
+ def dc_model(self):
143
+ """Dielectric material model.
144
+
145
+ Returns
146
+ -------
147
+ :class:``
148
+
149
+ """
150
+ return self.dielectric_material_model
151
+
152
+ @property
153
+ def dielectric_material_model(self):
154
+ """Material dielectric model.
155
+
156
+ Returns
157
+ -------
158
+ :class:`DebyeModel <ansys.edb.core.definition.debye_model.DebyeModel>` or
159
+ :class:`DjordjecvicSarkarModel <ansys.edb.core.definition.djordjecvic_sarkar_model.DjordjecvicSarkarModel>` or
160
+ :class:`MultipoleDebyeModel <ansys.edb.core.definition.multipole_debye_model.MultipoleDebyeModel>`.
161
+ EDB dielectric model.
162
+ """
163
+ try:
164
+ if super().dielectric_material_model.type.name.lower() == "debye":
165
+ self.__dielectric_model = GrpcDebyeModel(super().dielectric_material_model.msg)
166
+ elif super().dielectric_material_model.type.name.lower() == "multipole_debye":
167
+ self.__dielectric_model = GrpcMultipoleDebyeModel(super().dielectric_material_model.msg)
168
+ elif super().dielectric_material_model.type.name.lower() == "djordjecvic_sarkar":
169
+ self.__dielectric_model = GrpcDjordjecvicSarkarModel(super().dielectric_material_model.msg)
170
+ return self.__dielectric_model
171
+ except:
172
+ return None
173
+
174
+ @property
175
+ def conductivity(self):
176
+ """Get material conductivity.
177
+
178
+ Returns
179
+ -------
180
+ float
181
+ Conductivity value.
182
+ """
183
+ try:
184
+ value = self.get_property(GrpcMaterialProperty.CONDUCTIVITY).value
185
+ return value
186
+ except:
187
+ return None
188
+
189
+ @conductivity.setter
190
+ def conductivity(self, value):
191
+ """Set material conductivity."""
192
+ if self.dielectric_material_model:
193
+ self.__edb.logger.error(
194
+ f"Dielectric model defined on material {self.name}. Conductivity can not be changed"
195
+ f"Changing conductivity is only allowed when no dielectric model is assigned."
196
+ )
197
+ else:
198
+ self.set_property(GrpcMaterialProperty.CONDUCTIVITY, GrpcValue(value))
199
+
200
+ @property
201
+ def dc_conductivity(self):
202
+ """Material DC conductivity.
203
+
204
+ Returns
205
+ -------
206
+ float
207
+ DC conductivity value.
208
+
209
+ """
210
+ try:
211
+ return self.dielectric_material_model.dc_conductivity
212
+ except:
213
+ return
214
+
215
+ @dc_conductivity.setter
216
+ def dc_conductivity(self, value):
217
+ if self.dielectric_material_model:
218
+ self.dielectric_material_model.dc_conductivity = float(value)
219
+
220
+ @property
221
+ def dc_permittivity(self):
222
+ """Material DC permittivity.
223
+
224
+ Returns
225
+ -------
226
+ float
227
+ DC permittivity value.
228
+
229
+ """
230
+ try:
231
+ return self.dielectric_material_model.dc_relative_permitivity
232
+ except:
233
+ return
234
+
235
+ @dc_permittivity.setter
236
+ def dc_permittivity(self, value):
237
+ if self.dielectric_material_model:
238
+ self.dielectric_material_model.dc_relative_permitivity = float(value)
239
+
240
+ @property
241
+ def loss_tangent_at_frequency(self):
242
+ """Material loss tangent at frequency if dielectric model is defined.
243
+
244
+ Returns
245
+ -------
246
+ float
247
+ Loss tangent value.
248
+
249
+ """
250
+ try:
251
+ return self.dielectric_material_model.loss_tangent_at_frequency
252
+ except:
253
+ return
254
+
255
+ @loss_tangent_at_frequency.setter
256
+ def loss_tangent_at_frequency(self, value):
257
+ if self.dielectric_material_model:
258
+ self.dielectric_material_model.loss_tangent_at_frequency = float(value)
259
+
260
+ @property
261
+ def dielectric_model_frequency(self):
262
+ """Dielectric model frequency if model is defined.
263
+
264
+ Returns
265
+ -------
266
+ float
267
+ Frequency value.
268
+
269
+ """
270
+ try:
271
+ return self.dielectric_material_model.frequency
272
+ except:
273
+ return
274
+
275
+ @dielectric_model_frequency.setter
276
+ def dielectric_model_frequency(self, value):
277
+ if self.dielectric_material_model:
278
+ self.dielectric_material_model.frequency = float(value)
279
+
280
+ @property
281
+ def permittivity_at_frequency(self):
282
+ """Material permittivity at frequency if model is defined.
283
+
284
+
285
+ Returns
286
+ -------
287
+ float
288
+ Permittivity value.
289
+
290
+ """
291
+ try:
292
+ return self.dielectric_material_model.relative_permitivity_at_frequency
293
+ except:
294
+ return
295
+
296
+ @permittivity_at_frequency.setter
297
+ def permittivity_at_frequency(self, value):
298
+ if self.dielectric_material_model:
299
+ self.dielectric_material_model.relative_permitivity_at_frequency = float(value)
300
+
301
+ @property
302
+ def permittivity(self):
303
+ """Material permittivity.
304
+
305
+
306
+ Returns
307
+ -------
308
+ float
309
+ Permittivity value.
310
+
311
+ """
312
+ try:
313
+ value = self.get_property(GrpcMaterialProperty.PERMITTIVITY).value
314
+ return value
315
+ except:
316
+ return None
317
+
318
+ @permittivity.setter
319
+ def permittivity(self, value):
320
+ """Set material permittivity."""
321
+ self.set_property(GrpcMaterialProperty.PERMITTIVITY, GrpcValue(value))
322
+
323
+ @property
324
+ def permeability(self):
325
+ """Material permeability.
326
+
327
+ Returns
328
+ -------
329
+ float
330
+ Permeability value.
331
+
332
+ """
333
+ try:
334
+ value = self.get_property(GrpcMaterialProperty.PERMEABILITY).value
335
+ return value
336
+ except:
337
+ return None
338
+
339
+ @permeability.setter
340
+ def permeability(self, value):
341
+ """Set material permeability."""
342
+ self.set_property(GrpcMaterialProperty.PERMEABILITY, GrpcValue(value))
343
+
344
+ @property
345
+ def loss_tangent(self):
346
+ """Material loss tangent.
347
+
348
+ Returns
349
+ -------
350
+ float
351
+ Loss tangent value.
352
+
353
+ """
354
+ warnings.warn(
355
+ "This method is deprecated in versions >0.7.0 and will soon be removed. "
356
+ "Use property dielectric_loss_tangent instead.",
357
+ DeprecationWarning,
358
+ )
359
+ return self.dielectric_loss_tangent
360
+
361
+ @property
362
+ def dielectric_loss_tangent(self):
363
+ """Material loss tangent.
364
+
365
+ Returns
366
+ -------
367
+ float
368
+ Loss tangent value.
369
+
370
+ """
371
+ try:
372
+ return self.get_property(GrpcMaterialProperty.DIELECTRIC_LOSS_TANGENT).value
373
+ except:
374
+ return None
375
+
376
+ @loss_tangent.setter
377
+ def loss_tangent(self, value):
378
+ """Set material loss tangent."""
379
+ warnings.warn(
380
+ "This method is deprecated in versions >0.7.0 and will soon be removed. "
381
+ "Use property dielectric_loss_tangent instead.",
382
+ DeprecationWarning,
383
+ )
384
+ self.dielectric_loss_tangent(value)
385
+
386
+ @dielectric_loss_tangent.setter
387
+ def dielectric_loss_tangent(self, value):
388
+ """Set material loss tangent."""
389
+ self.set_property(GrpcMaterialProperty.DIELECTRIC_LOSS_TANGENT, GrpcValue(value))
390
+
391
+ @property
392
+ def magnetic_loss_tangent(self):
393
+ """Material magnetic loss tangent.
394
+
395
+ Returns
396
+ -------
397
+ float
398
+ Magnetic loss tangent value.
399
+ """
400
+ try:
401
+ value = self.get_property(GrpcMaterialProperty.MAGNETIC_LOSS_TANGENT).value
402
+ return value
403
+ except:
404
+ return None
405
+
406
+ @magnetic_loss_tangent.setter
407
+ def magnetic_loss_tangent(self, value):
408
+ """Set material magnetic loss tangent."""
409
+ self.set_property(GrpcMaterialProperty.MAGNETIC_LOSS_TANGENT, GrpcValue(value))
410
+
411
+ @property
412
+ def thermal_conductivity(self):
413
+ """Material thermal conductivity.
414
+
415
+ Returns
416
+ -------
417
+ float
418
+ Thermal conductivity value.
419
+
420
+ """
421
+ try:
422
+ value = self.get_property(GrpcMaterialProperty.THERMAL_CONDUCTIVITY).value
423
+ return value
424
+ except:
425
+ return None
426
+
427
+ @thermal_conductivity.setter
428
+ def thermal_conductivity(self, value):
429
+ """Set material thermal conductivity."""
430
+ self.set_property(GrpcMaterialProperty.THERMAL_CONDUCTIVITY, GrpcValue(value))
431
+
432
+ @property
433
+ def mass_density(self):
434
+ """Material mass density.
435
+
436
+ Returns
437
+ -------
438
+ float
439
+ Mass density value.
440
+
441
+ """
442
+ try:
443
+ value = self.get_property(GrpcMaterialProperty.MASS_DENSITY).value
444
+ return value
445
+ except:
446
+ return None
447
+
448
+ @mass_density.setter
449
+ def mass_density(self, value):
450
+ """Set material mass density."""
451
+ self.set_property(GrpcMaterialProperty.MASS_DENSITY, GrpcValue(value))
452
+
453
+ @property
454
+ def youngs_modulus(self):
455
+ """Material young modulus.
456
+
457
+ Returns
458
+ -------
459
+ float
460
+ Material young modulus value.
461
+
462
+ """
463
+ try:
464
+ value = self.get_property(GrpcMaterialProperty.YOUNGS_MODULUS).value
465
+ return value
466
+ except:
467
+ return None
468
+
469
+ @youngs_modulus.setter
470
+ def youngs_modulus(self, value):
471
+ """Set material young modulus."""
472
+ self.set_property(GrpcMaterialProperty.YOUNGS_MODULUS, GrpcValue(value))
473
+
474
+ @property
475
+ def specific_heat(self):
476
+ """Material specific heat.
477
+
478
+ Returns
479
+ -------
480
+ float
481
+ Material specific heat value.
482
+ """
483
+ try:
484
+ return self.get_property(GrpcMaterialProperty.SPECIFIC_HEAT).value
485
+ except:
486
+ return None
487
+
488
+ @specific_heat.setter
489
+ def specific_heat(self, value):
490
+ """Set material specific heat."""
491
+ self.set_property(GrpcMaterialProperty.SPECIFIC_HEAT, GrpcValue(value))
492
+
493
+ @property
494
+ def poisson_ratio(self):
495
+ """Material poisson ratio.
496
+
497
+ Returns
498
+ -------
499
+ float
500
+ Material poisson ratio value.
501
+ """
502
+ try:
503
+ return self.get_property(GrpcMaterialProperty.POISSONS_RATIO).value
504
+ except:
505
+ return None
506
+
507
+ @poisson_ratio.setter
508
+ def poisson_ratio(self, value):
509
+ """Set material poisson ratio."""
510
+ self.set_property(GrpcMaterialProperty.POISSONS_RATIO, GrpcValue(value))
511
+
512
+ @property
513
+ def thermal_expansion_coefficient(self):
514
+ """Material thermal coefficient.
515
+
516
+ Returns
517
+ -------
518
+ float
519
+ Material thermal coefficient value.
520
+
521
+ """
522
+ try:
523
+ return self.get_property(GrpcMaterialProperty.THERMAL_EXPANSION_COEFFICIENT).value
524
+ except:
525
+ return None
526
+
527
+ @thermal_expansion_coefficient.setter
528
+ def thermal_expansion_coefficient(self, value):
529
+ """Set material thermal coefficient."""
530
+ self.set_property(GrpcMaterialProperty.THERMAL_EXPANSION_COEFFICIENT, GrpcValue(value))
531
+
532
+ def set_debye_model(self):
533
+ """Set Debye model on current material."""
534
+ super(Material, self.__class__).dielectric_material_model.__set__(self, GrpcDebyeModel.create())
535
+
536
+ def set_multipole_debye_model(self):
537
+ """Set multi-pole debeye model on current material."""
538
+ super(Material, self.__class__).dielectric_material_model.__set__(self, GrpcMultipoleDebyeModel.create())
539
+
540
+ def set_djordjecvic_sarkar_model(self):
541
+ """Set Djordjecvic-Sarkar model on current material."""
542
+ super(Material, self.__class__).dielectric_material_model.__set__(self, GrpcDjordjecvicSarkarModel.create())
543
+
544
+ def to_dict(self):
545
+ """Convert material into dictionary."""
546
+ properties = self.__load_all_properties()
547
+
548
+ res = {"name": self.name}
549
+ res.update(properties.model_dump())
550
+ return res
551
+
552
+ def update(self, input_dict: dict):
553
+ if input_dict:
554
+ # Update attributes
555
+ for attribute in ATTRIBUTES:
556
+ if attribute in input_dict:
557
+ setattr(self, attribute, input_dict[attribute])
558
+ if "loss_tangent" in input_dict: # pragma: no cover
559
+ setattr(self, "loss_tangent", input_dict["loss_tangent"])
560
+
561
+ # Update DS model
562
+ # NOTE: Contrary to before we don't test 'dielectric_model_frequency' only
563
+ if any(map(lambda attribute: input_dict.get(attribute, None) is not None, DC_ATTRIBUTES)):
564
+ if not self.__dielectric_model:
565
+ self.__dielectric_model = GrpcDjordjecvicSarkarModel.create()
566
+ for attribute in DC_ATTRIBUTES:
567
+ if attribute in input_dict:
568
+ if attribute == "use_dc_relative_conductivity" and input_dict[attribute] is not None:
569
+ self.__dielectric_model.use_dc_relative_conductivity = True
570
+ setattr(self, attribute, input_dict[attribute])
571
+ self.__material_def.dielectric_material_model = (
572
+ self.__dielectric_model
573
+ ) # Check material is properly assigned
574
+ # Unset DS model if it is already assigned to the material in the database
575
+ elif self.__dielectric_model:
576
+ self.__material_def.dielectric_material_model = None
577
+
578
+ def __load_all_properties(self):
579
+ """Load all properties of the material."""
580
+ res = MaterialProperties()
581
+ for property in res.model_dump().keys():
582
+ value = getattr(self, property)
583
+ setattr(res, property, value)
584
+ return res
585
+
586
+
587
+ class Materials(object):
588
+ """Manages EDB methods for material management accessible from `Edb.materials` property."""
589
+
590
+ def __init__(self, edb: Edb):
591
+ self.__edb = edb
592
+ self.__syslib = os.path.join(self.__edb.base_path, "syslib")
593
+
594
+ def __contains__(self, item):
595
+ if isinstance(item, Material):
596
+ return item.name in self.materials
597
+ else:
598
+ return item in self.materials
599
+
600
+ def __getitem__(self, item):
601
+ return self.materials[item]
602
+
603
+ @property
604
+ def syslib(self):
605
+ """Get the project sys library.
606
+
607
+ Returns
608
+ -------
609
+ str
610
+ Syslib path.
611
+ """
612
+ return self.__syslib
613
+
614
+ @property
615
+ def materials(self):
616
+ """Get materials.
617
+
618
+ Returns
619
+ -------
620
+ Dict[str, :class:`Material <pyedb.grpc.database.definition.materials.Material>`]
621
+ Materials dictionary.
622
+ """
623
+ materials = {
624
+ material_def.name: Material(self.__edb, material_def) for material_def in self.__edb.active_db.material_defs
625
+ }
626
+ return materials
627
+
628
+ def add_material(self, name: str, **kwargs):
629
+ """Add a new material.
630
+
631
+ Parameters
632
+ ----------
633
+ name : str
634
+ Material name.
635
+
636
+ Returns
637
+ -------
638
+ :class:`Material <pyedb.grpc.database.definition.materials.Material>`
639
+ Material object.
640
+ """
641
+ curr_materials = self.materials
642
+ if name in curr_materials:
643
+ raise ValueError(f"Material {name} already exists in material library.")
644
+ elif name.lower() in (material.lower() for material in curr_materials):
645
+ m = {material.lower(): material for material in curr_materials}[name.lower()]
646
+ raise ValueError(f"Material names are case-insensitive and '{name}' already exists as '{m}'.")
647
+
648
+ material_def = GrpcMaterialDef.create(self.__edb.active_db, name)
649
+ material = Material(self.__edb, material_def)
650
+ # Apply default values to the material
651
+ if "permeability" not in kwargs:
652
+ kwargs["permeability"] = PERMEABILITY_DEFAULT_VALUE
653
+ attributes_input_dict = {key: val for (key, val) in kwargs.items() if key in ATTRIBUTES + DC_ATTRIBUTES}
654
+ if "loss_tangent" in kwargs: # pragma: no cover
655
+ warnings.warn(
656
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
657
+ "Use key dielectric_loss_tangent instead.",
658
+ DeprecationWarning,
659
+ )
660
+ attributes_input_dict["dielectric_loss_tangent"] = kwargs["loss_tangent"]
661
+ if attributes_input_dict:
662
+ material.update(attributes_input_dict)
663
+
664
+ return material
665
+
666
+ def add_conductor_material(self, name, conductivity, **kwargs):
667
+ """Add a new conductor material.
668
+
669
+ Parameters
670
+ ----------
671
+ name : str
672
+ Name of the new material.
673
+ conductivity : str, float, int
674
+ Conductivity of the new material.
675
+
676
+ Returns
677
+ -------
678
+ :class:`Material <pyedb.grpc.database.definition.materials.Material>`
679
+ Material object.
680
+
681
+ """
682
+ extended_kwargs = {key: value for (key, value) in kwargs.items()}
683
+ extended_kwargs["conductivity"] = conductivity
684
+ material = self.add_material(name, **extended_kwargs)
685
+
686
+ return material
687
+
688
+ def add_dielectric_material(self, name, permittivity, dielectric_loss_tangent, **kwargs):
689
+ """Add a new dielectric material in library.
690
+
691
+ Parameters
692
+ ----------
693
+ name : str
694
+ Name of the new material.
695
+ permittivity : str, float, int
696
+ Permittivity of the new material.
697
+ dielectric_loss_tangent : str, float, int
698
+ Dielectric loss tangent of the new material.
699
+
700
+ Returns
701
+ -------
702
+ :class:`Material <pyedb.grpc.database.definition.materials.Material>`
703
+ Material object.
704
+ """
705
+ extended_kwargs = {key: value for (key, value) in kwargs.items()}
706
+ extended_kwargs["permittivity"] = permittivity
707
+ extended_kwargs["dielectric_loss_tangent"] = dielectric_loss_tangent
708
+ material = self.add_material(name, **extended_kwargs)
709
+
710
+ return material
711
+
712
+ def add_djordjevicsarkar_dielectric(
713
+ self,
714
+ name,
715
+ permittivity_at_frequency,
716
+ loss_tangent_at_frequency,
717
+ dielectric_model_frequency,
718
+ dc_conductivity=None,
719
+ dc_permittivity=None,
720
+ **kwargs,
721
+ ):
722
+ """Add a dielectric using the Djordjevic-Sarkar model.
723
+
724
+ Parameters
725
+ ----------
726
+ name : str
727
+ Name of the dielectric.
728
+ permittivity_at_frequency : str, float, int
729
+ Relative permittivity of the dielectric.
730
+ loss_tangent_at_frequency : str, float, int
731
+ Loss tangent for the material.
732
+ dielectric_model_frequency : str, float, int
733
+ Test frequency in GHz for the dielectric.
734
+
735
+ Returns
736
+ -------
737
+ :class:`Material <pyedb.grpc.database.definition.materials.Material>`
738
+ Material object.
739
+ """
740
+ curr_materials = self.materials
741
+ if name in curr_materials:
742
+ raise ValueError(f"Material {name} already exists in material library.")
743
+ elif name.lower() in (material.lower() for material in curr_materials):
744
+ raise ValueError(f"Material names are case-insensitive and {name.lower()} already exists.")
745
+
746
+ material_model = GrpcDjordjecvicSarkarModel.create()
747
+ material_model.relative_permitivity_at_frequency = permittivity_at_frequency
748
+ material_model.loss_tangent_at_frequency = loss_tangent_at_frequency
749
+ material_model.frequency = dielectric_model_frequency
750
+ if dc_conductivity is not None:
751
+ material_model.dc_conductivity = dc_conductivity
752
+ material_model.use_dc_relative_conductivity = True
753
+ if dc_permittivity is not None:
754
+ material_model.dc_relative_permitivity = dc_permittivity
755
+ try:
756
+ material = self.__add_dielectric_material_model(name, material_model)
757
+ for key, value in kwargs.items():
758
+ setattr(material, key, value)
759
+ if "loss_tangent" in kwargs: # pragma: no cover
760
+ warnings.warn(
761
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
762
+ "Use key dielectric_loss_tangent instead.",
763
+ DeprecationWarning,
764
+ )
765
+ setattr(material, "dielectric_loss_tangent", kwargs["loss_tangent"])
766
+ return material
767
+ except MaterialModelException:
768
+ raise ValueError("Use realistic values to define DS model.")
769
+
770
+ def add_debye_material(
771
+ self,
772
+ name,
773
+ permittivity_low,
774
+ permittivity_high,
775
+ loss_tangent_low,
776
+ loss_tangent_high,
777
+ lower_freqency,
778
+ higher_frequency,
779
+ **kwargs,
780
+ ):
781
+ """Add a dielectric with the Debye model.
782
+
783
+ Parameters
784
+ ----------
785
+ name : str
786
+ Name of the dielectric.
787
+ permittivity_low : float, int
788
+ Relative permittivity of the dielectric at the frequency specified
789
+ for ``lower_frequency``.
790
+ permittivity_high : float, int
791
+ Relative permittivity of the dielectric at the frequency specified
792
+ for ``higher_frequency``.
793
+ loss_tangent_low : float, int
794
+ Loss tangent for the material at the frequency specified
795
+ for ``lower_frequency``.
796
+ loss_tangent_high : float, int
797
+ Loss tangent for the material at the frequency specified
798
+ for ``higher_frequency``.
799
+ lower_freqency : str, float, int
800
+ Value for the lower frequency.
801
+ higher_frequency : str, float, int
802
+ Value for the higher frequency.
803
+
804
+ Returns
805
+ -------
806
+ :class:`Material <pyedb.grpc.database.definition.materials.Material>`
807
+ Material object.
808
+ """
809
+ curr_materials = self.materials
810
+ if name in curr_materials:
811
+ raise ValueError(f"Material {name} already exists in material library.")
812
+ elif name.lower() in (material.lower() for material in curr_materials):
813
+ raise ValueError(f"Material names are case-insensitive and {name.lower()} already exists.")
814
+ material_model = GrpcDebyeModel.create()
815
+ material_model.frequency_range = (lower_freqency, higher_frequency)
816
+ material_model.loss_tangent_at_high_low_frequency = (loss_tangent_low, loss_tangent_high)
817
+ material_model.relative_permitivity_at_high_low_frequency = (permittivity_low, permittivity_high)
818
+ try:
819
+ material = self.__add_dielectric_material_model(name, material_model)
820
+ for key, value in kwargs.items():
821
+ setattr(material, key, value)
822
+ if "loss_tangent" in kwargs: # pragma: no cover
823
+ warnings.warn(
824
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
825
+ "Use key dielectric_loss_tangent instead.",
826
+ DeprecationWarning,
827
+ )
828
+ setattr(material, "dielectric_loss_tangent", kwargs["loss_tangent"])
829
+ return material
830
+ except MaterialModelException:
831
+ raise ValueError("Use realistic values to define Debye model.")
832
+
833
+ def add_multipole_debye_material(
834
+ self,
835
+ name,
836
+ frequencies,
837
+ permittivities,
838
+ loss_tangents,
839
+ **kwargs,
840
+ ):
841
+ """Add a dielectric with the Multipole Debye model.
842
+
843
+ Parameters
844
+ ----------
845
+ name : str
846
+ Name of the dielectric.
847
+ frequencies : list
848
+ Frequencies in GHz.
849
+ permittivities : list
850
+ Relative permittivities at each frequency.
851
+ loss_tangents : list
852
+ Loss tangents at each frequency.
853
+
854
+ Returns
855
+ -------
856
+ :class:`Material <pyedb.grpc.database.definition.materials.Material>`
857
+ Material object.
858
+
859
+ Examples
860
+ --------
861
+ >>> from pyedb import Edb
862
+ >>> edb = Edb()
863
+ >>> freq = [0, 2, 3, 4, 5, 6]
864
+ >>> rel_perm = [1e9, 1.1e9, 1.2e9, 1.3e9, 1.5e9, 1.6e9]
865
+ >>> loss_tan = [0.025, 0.026, 0.027, 0.028, 0.029, 0.030]
866
+ >>> diel = edb.materials.add_multipole_debye_material("My_MP_Debye", freq, rel_perm, loss_tan)
867
+ """
868
+ curr_materials = self.materials
869
+ if name in curr_materials:
870
+ raise ValueError(f"Material {name} already exists in material library.")
871
+ elif name.lower() in (material.lower() for material in curr_materials):
872
+ raise ValueError(f"Material names are case-insensitive and {name.lower()} already exists.")
873
+
874
+ frequencies = [float(i) for i in frequencies]
875
+ permittivities = [float(i) for i in permittivities]
876
+ loss_tangents = [float(i) for i in loss_tangents]
877
+ material_model = GrpcMultipoleDebyeModel.create()
878
+ material_model.set_parameters(frequencies, permittivities, loss_tangents)
879
+ try:
880
+ material = self.__add_dielectric_material_model(name, material_model)
881
+ for key, value in kwargs.items():
882
+ setattr(material, key, value)
883
+ if "loss_tangent" in kwargs: # pragma: no cover
884
+ warnings.warn(
885
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
886
+ "Use key dielectric_loss_tangent instead.",
887
+ DeprecationWarning,
888
+ )
889
+ setattr(material, "dielectric_loss_tangent", kwargs["loss_tangent"])
890
+ return material
891
+ except MaterialModelException:
892
+ raise ValueError("Use realistic values to define Multipole Debye model.")
893
+
894
+ def __add_dielectric_material_model(self, name, material_model):
895
+ """Add a dielectric material model.
896
+
897
+ Parameters
898
+ ----------
899
+ name : str
900
+ Name of the dielectric.
901
+ material_model : Any
902
+ Dielectric material model.
903
+ """
904
+ if GrpcMaterialDef.find_by_name(self.__edb.active_db, name).is_null:
905
+ if name.lower() in (material.lower() for material in self.materials):
906
+ raise ValueError(f"Material names are case-insensitive and {name.lower()} already exists.")
907
+ GrpcMaterialDef.create(self.__edb.active_db, name)
908
+
909
+ material_def = GrpcMaterialDef.find_by_name(self.__edb.active_db, name)
910
+ material_def.dielectric_material_model = material_model
911
+ material = Material(self.__edb, material_def)
912
+ return material
913
+
914
+ def duplicate(self, material_name, new_material_name):
915
+ """Duplicate a material from the database.
916
+
917
+ Parameters
918
+ ----------
919
+ material_name : str
920
+ Name of the existing material.
921
+ new_material_name : str
922
+ Name of the new duplicated material.
923
+
924
+ Returns
925
+ -------
926
+ :class:`Material <pyedb.grpc.database.definition.materials.Material>`
927
+ Material object.
928
+ """
929
+ curr_materials = self.materials
930
+ if new_material_name in curr_materials:
931
+ raise ValueError(f"Material {new_material_name} already exists in material library.")
932
+ elif new_material_name.lower() in (material.lower() for material in curr_materials):
933
+ raise ValueError(f"Material names are case-insensitive and {new_material_name.lower()} already exists.")
934
+
935
+ material = self.materials[material_name]
936
+ material_def = GrpcMaterialDef.create(self.__edb.active_db, new_material_name)
937
+ material_dict = material.to_dict()
938
+ new_material = Material(self.__edb, material_def)
939
+ new_material.update(material_dict)
940
+ return new_material
941
+
942
+ def delete_material(self, material_name):
943
+ """
944
+
945
+ .deprecated: pyedb 0.32.0 use `delete` instead.
946
+
947
+ Parameters
948
+ ----------
949
+ material_name : str
950
+ Name of the material to delete.
951
+
952
+ """
953
+ warnings.warn(
954
+ "`delete_material` is deprecated use `delete` instead.",
955
+ DeprecationWarning,
956
+ )
957
+ self.delete(material_name)
958
+
959
+ def delete(self, material_name):
960
+ """Remove a material from the database.
961
+
962
+ Returns
963
+ -------
964
+ bool
965
+
966
+ """
967
+ material_def = GrpcMaterialDef.find_by_name(self.__edb.active_db, material_name)
968
+ if material_def.is_null:
969
+ raise ValueError(f"Cannot find material {material_name}.")
970
+ return False
971
+ material_def.delete()
972
+ return True
973
+
974
+ def update_material(self, material_name, input_dict):
975
+ """Update material attributes."""
976
+ if material_name not in self.materials:
977
+ raise ValueError(f"Material {material_name} does not exist in material library.")
978
+
979
+ material = self[material_name]
980
+ attributes_input_dict = {key: val for (key, val) in input_dict.items() if key in ATTRIBUTES + DC_ATTRIBUTES}
981
+ if "loss_tangent" in input_dict: # pragma: no cover
982
+ warnings.warn(
983
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
984
+ "Use key dielectric_loss_tangent instead.",
985
+ DeprecationWarning,
986
+ )
987
+ attributes_input_dict["dielectric_loss_tangent"] = input_dict["loss_tangent"]
988
+ if attributes_input_dict:
989
+ material.update(attributes_input_dict)
990
+ return material
991
+
992
+ def load_material(self, material: dict):
993
+ """Load material."""
994
+ if material:
995
+ material_name = material["name"]
996
+ material_conductivity = material.get("conductivity", None)
997
+ if material_conductivity and material_conductivity > 1e4:
998
+ self.add_conductor_material(material_name, material_conductivity)
999
+ else:
1000
+ material_permittivity = material["permittivity"]
1001
+ if "loss_tangent" in material: # pragma: no cover
1002
+ warnings.warn(
1003
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
1004
+ "Use key dielectric_loss_tangent instead.",
1005
+ DeprecationWarning,
1006
+ )
1007
+ material_dlt = material["loss_tangent"]
1008
+ else:
1009
+ material_dlt = material["dielectric_loss_tangent"]
1010
+ self.add_dielectric_material(material_name, material_permittivity, material_dlt)
1011
+
1012
+ def material_property_to_id(self, property_name):
1013
+ """Convert a material property name to a material property ID.
1014
+
1015
+ Parameters
1016
+ ----------
1017
+ property_name : str
1018
+ Name of the material property.
1019
+
1020
+ Returns
1021
+ -------
1022
+ Any
1023
+ """
1024
+ # material_property_id = GrpcMaterialProperty.CONDUCTIVITY self.__edb_definition.MaterialPropertyId
1025
+ property_name_to_id = {
1026
+ "Permittivity": GrpcMaterialProperty.PERMITTIVITY,
1027
+ "Permeability": GrpcMaterialProperty.PERMEABILITY,
1028
+ "Conductivity": GrpcMaterialProperty.CONDUCTIVITY,
1029
+ "DielectricLossTangent": GrpcMaterialProperty.DIELECTRIC_LOSS_TANGENT,
1030
+ "MagneticLossTangent": GrpcMaterialProperty.MAGNETIC_LOSS_TANGENT,
1031
+ "ThermalConductivity": GrpcMaterialProperty.THERMAL_CONDUCTIVITY,
1032
+ "MassDensity": GrpcMaterialProperty.MASS_DENSITY,
1033
+ "SpecificHeat": GrpcMaterialProperty.SPECIFIC_HEAT,
1034
+ "YoungsModulus": GrpcMaterialProperty.YOUNGS_MODULUS,
1035
+ "PoissonsRatio": GrpcMaterialProperty.POISSONS_RATIO,
1036
+ "ThermalExpansionCoefficient": GrpcMaterialProperty.THERMAL_EXPANSION_COEFFICIENT,
1037
+ "InvalidProperty": GrpcMaterialProperty.INVALID_PROPERTY,
1038
+ }
1039
+
1040
+ if property_name == "loss_tangent":
1041
+ warnings.warn(
1042
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
1043
+ "Use key dielectric_loss_tangent instead.",
1044
+ DeprecationWarning,
1045
+ )
1046
+ property_name = "dielectric_loss_tangent"
1047
+ match = difflib.get_close_matches(property_name, property_name_to_id, 1, 0.7)
1048
+ if match:
1049
+ return property_name_to_id[match[0]]
1050
+ else:
1051
+ return property_name_to_id["InvalidProperty"]
1052
+
1053
+ def load_amat(self, amat_file):
1054
+ """Load materials from an AMAT file.
1055
+
1056
+ Parameters
1057
+ ----------
1058
+ amat_file : str
1059
+ Full path to the AMAT file to read and add to the Edb.
1060
+
1061
+ Returns
1062
+ -------
1063
+ bool
1064
+ """
1065
+ if not os.path.exists(amat_file):
1066
+ raise FileNotFoundError(f"File path {amat_file} does not exist.")
1067
+ materials_dict = self.read_materials(amat_file)
1068
+ for material_name, material_properties in materials_dict.items():
1069
+ if not material_name in self:
1070
+ if "tangent_delta" in material_properties:
1071
+ material_properties["dielectric_loss_tangent"] = material_properties["tangent_delta"]
1072
+ del material_properties["tangent_delta"]
1073
+ elif "loss_tangent" in material_properties: # pragma: no cover
1074
+ warnings.warn(
1075
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
1076
+ "Use key dielectric_loss_tangent instead.",
1077
+ DeprecationWarning,
1078
+ )
1079
+ material_properties["dielectric_loss_tangent"] = material_properties["loss_tangent"]
1080
+ del material_properties["loss_tangent"]
1081
+ self.add_material(material_name, **material_properties)
1082
+ else:
1083
+ self.__edb.logger.warning(f"Material {material_name} already exist and was not loaded from AMAT file.")
1084
+ return True
1085
+
1086
+ def iterate_materials_in_amat(self, amat_file=None):
1087
+ """Iterate over material description in an AMAT file.
1088
+
1089
+ Parameters
1090
+ ----------
1091
+ amat_file : str
1092
+ Full path to the AMAT file to read.
1093
+
1094
+ Yields
1095
+ ------
1096
+ dict
1097
+ """
1098
+ if amat_file is None:
1099
+ amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
1100
+
1101
+ begin_regex = re.compile(r"^\$begin '(.+)'")
1102
+ end_regex = re.compile(r"^\$end '(.+)'")
1103
+ material_properties = ATTRIBUTES.copy()
1104
+ # Remove cases manually handled
1105
+ material_properties.remove("conductivity")
1106
+
1107
+ with open(amat_file, "r") as amat_fh:
1108
+ in_material_def = False
1109
+ material_description = {}
1110
+ for line in amat_fh:
1111
+ if in_material_def:
1112
+ # Yield material definition
1113
+ if end_regex.search(line):
1114
+ in_material_def = False
1115
+ yield material_description
1116
+ material_description = {}
1117
+ # Extend material definition if possible
1118
+ else:
1119
+ for material_property in material_properties:
1120
+ if material_property in line:
1121
+ value = get_line_float_value(line)
1122
+ if value is not None:
1123
+ material_description[material_property] = value
1124
+ break
1125
+ # Extra case to cover bug in syslib AMAT file (see #364)
1126
+ if "thermal_expansion_coeffcient" in line:
1127
+ value = get_line_float_value(line)
1128
+ if value is not None:
1129
+ material_description["thermal_expansion_coefficient"] = value
1130
+ # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1131
+ if "conductivity" in line and "thermal_conductivity" not in line:
1132
+ value = get_line_float_value(line)
1133
+ if value is not None:
1134
+ material_description["conductivity"] = value
1135
+ # Extra case to avoid confusion ("conductivity" is included in "thermal_conductivity")
1136
+ if (
1137
+ "loss_tangent" in line
1138
+ and "dielectric_loss_tangent" not in line
1139
+ and "magnetic_loss_tangent" not in line
1140
+ ):
1141
+ warnings.warn(
1142
+ "This key is deprecated in versions >0.7.0 and will soon be removed. "
1143
+ "Use key dielectric_loss_tangent instead.",
1144
+ DeprecationWarning,
1145
+ )
1146
+ value = get_line_float_value(line)
1147
+ if value is not None:
1148
+ material_description["dielectric_loss_tangent"] = value
1149
+ # Check if we reach the beginning of a material description
1150
+ else:
1151
+ match = begin_regex.search(line)
1152
+ if match:
1153
+ material_name = match.group(1)
1154
+ # Skip unwanted data
1155
+ if material_name in ("$index$", "$base_index$"):
1156
+ continue
1157
+ material_description["name"] = match.group(1)
1158
+ in_material_def = True
1159
+
1160
+ def read_materials(self, amat_file):
1161
+ """Read materials from an AMAT file.
1162
+
1163
+ Parameters
1164
+ ----------
1165
+ amat_file : str
1166
+ Full path to the AMAT file to read.
1167
+
1168
+ Returns
1169
+ -------
1170
+ dict
1171
+ {material name: dict of material properties}.
1172
+ """
1173
+ res = {}
1174
+ for material in self.iterate_materials_in_amat(amat_file):
1175
+ material_name = material["name"]
1176
+ res[material_name] = {}
1177
+ for material_property, value in material.items():
1178
+ if material_property != "name":
1179
+ res[material_name][material_property] = value
1180
+
1181
+ return res
1182
+
1183
+ def read_syslib_material(self, material_name):
1184
+ """Read a specific material from syslib AMAT file.
1185
+
1186
+ Parameters
1187
+ ----------
1188
+ material_name : str
1189
+ Name of the material.
1190
+
1191
+ Returns
1192
+ -------
1193
+ dict
1194
+ {material name: dict of material properties}.
1195
+ """
1196
+ res = {}
1197
+ amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
1198
+ for material in self.iterate_materials_in_amat(amat_file):
1199
+ iter_material_name = material["name"]
1200
+ if iter_material_name == material_name or iter_material_name.lower() == material_name.lower():
1201
+ for material_property, value in material.items():
1202
+ if material_property != "name":
1203
+ res[material_property] = value
1204
+ return res
1205
+
1206
+ self.__edb.logger.error(f"Material {material_name} does not exist in syslib AMAT file.")
1207
+ return res