pyedb 0.38.0__py3-none-any.whl → 0.39.1__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/common/nets.py +53 -139
- pyedb/configuration/cfg_components.py +1 -1
- pyedb/configuration/cfg_general.py +4 -2
- pyedb/configuration/cfg_modeler.py +1 -1
- pyedb/configuration/cfg_package_definition.py +1 -1
- pyedb/configuration/cfg_padstacks.py +1 -1
- pyedb/configuration/cfg_ports_sources.py +56 -23
- pyedb/configuration/configuration.py +18 -1
- pyedb/dotnet/{application → database}/Variables.py +21 -21
- pyedb/dotnet/{edb_core → database}/cell/connectable.py +5 -5
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/component.py +11 -11
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/hierarchy_obj.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/layout.py +17 -17
- pyedb/dotnet/{edb_core → database}/cell/layout_obj.py +3 -3
- pyedb/dotnet/{edb_core → database}/cell/primitive/bondwire.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/primitive/path.py +4 -4
- pyedb/dotnet/{edb_core → database}/cell/primitive/primitive.py +14 -14
- pyedb/dotnet/{edb_core → database}/cell/terminal/bundle_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/edge_terminal.py +4 -4
- pyedb/dotnet/{edb_core → database}/cell/terminal/padstack_instance_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/pingroup_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/point_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/terminal.py +11 -11
- pyedb/dotnet/{edb_core → database}/cell/voltage_regulator.py +2 -2
- pyedb/dotnet/{edb_core → database}/components.py +101 -124
- pyedb/dotnet/{edb_core → database}/definition/component_def.py +5 -5
- pyedb/dotnet/{edb_core → database}/definition/component_model.py +1 -1
- pyedb/dotnet/{edb_core → database}/definition/definition_obj.py +1 -1
- pyedb/dotnet/{edb_core → database}/definition/definitions.py +2 -2
- pyedb/dotnet/{edb_core → database}/definition/package_def.py +4 -4
- pyedb/dotnet/{edb_core → database}/dotnet/database.py +8 -8
- pyedb/dotnet/{edb_core → database}/dotnet/primitive.py +9 -9
- pyedb/dotnet/{edb_core → database}/edb_data/control_file.py +12 -12
- pyedb/dotnet/{edb_core → database}/edb_data/hfss_extent_info.py +7 -7
- pyedb/dotnet/{edb_core → database}/edb_data/nets_data.py +10 -13
- pyedb/dotnet/{edb_core → database}/edb_data/padstacks_data.py +16 -16
- pyedb/dotnet/{edb_core → database}/edb_data/ports.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/primitives_data.py +5 -5
- pyedb/dotnet/{edb_core → database}/edb_data/raptor_x_simulation_setup_data.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/simulation_configuration.py +10 -10
- pyedb/dotnet/{edb_core → database}/edb_data/sources.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/variables.py +1 -1
- pyedb/dotnet/{edb_core → database}/geometry/polygon_data.py +4 -4
- pyedb/dotnet/{edb_core → database}/hfss.py +8 -8
- pyedb/dotnet/{edb_core → database}/layout_obj_instance.py +1 -1
- pyedb/dotnet/{edb_core → database}/layout_validation.py +2 -2
- pyedb/dotnet/{edb_core → database}/materials.py +23 -8
- pyedb/dotnet/{edb_core → database}/modeler.py +27 -27
- pyedb/dotnet/{edb_core → database}/net_class.py +8 -8
- pyedb/dotnet/{edb_core → database}/nets.py +12 -12
- pyedb/dotnet/{edb_core → database}/padstack.py +15 -15
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/mesh_operation.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/settings.py +3 -3
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sim_setup_info.py +2 -2
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/simulation_settings.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/siw_dc_ir_settings.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sweep_data.py +1 -1
- pyedb/dotnet/{edb_core → database}/siwave.py +10 -10
- pyedb/dotnet/{edb_core → database}/stackup.py +12 -12
- pyedb/dotnet/{edb_core → database}/utilities/hfss_simulation_setup.py +15 -15
- pyedb/dotnet/{edb_core → database}/utilities/obj_base.py +1 -1
- pyedb/dotnet/{edb_core → database}/utilities/simulation_setup.py +3 -3
- pyedb/dotnet/{edb_core → database}/utilities/siwave_simulation_setup.py +6 -6
- pyedb/dotnet/edb.py +117 -112
- pyedb/generic/design_types.py +26 -19
- pyedb/generic/general_methods.py +1 -1
- pyedb/generic/plot.py +0 -2
- pyedb/grpc/database/__init__.py +1 -0
- pyedb/grpc/database/components.py +2354 -0
- pyedb/grpc/database/control_file.py +1277 -0
- pyedb/grpc/database/definition/component_def.py +218 -0
- pyedb/grpc/database/definition/component_model.py +39 -0
- pyedb/grpc/database/definition/component_pin.py +32 -0
- pyedb/grpc/database/definition/materials.py +1207 -0
- pyedb/grpc/database/definition/n_port_component_model.py +34 -0
- pyedb/grpc/database/definition/package_def.py +227 -0
- pyedb/grpc/database/definition/padstack_def.py +842 -0
- pyedb/grpc/database/definitions.py +70 -0
- pyedb/grpc/database/general.py +43 -0
- pyedb/grpc/database/geometry/__init__.py +0 -0
- pyedb/grpc/database/geometry/arc_data.py +93 -0
- pyedb/grpc/database/geometry/point_3d_data.py +79 -0
- pyedb/grpc/database/geometry/point_data.py +30 -0
- pyedb/grpc/database/geometry/polygon_data.py +133 -0
- pyedb/grpc/database/hfss.py +1279 -0
- pyedb/grpc/database/hierarchy/__init__.py +0 -0
- pyedb/grpc/database/hierarchy/component.py +1301 -0
- pyedb/grpc/database/hierarchy/model.py +31 -0
- pyedb/grpc/database/hierarchy/netlist_model.py +30 -0
- pyedb/grpc/database/hierarchy/pin_pair_model.py +128 -0
- pyedb/grpc/database/hierarchy/pingroup.py +245 -0
- pyedb/grpc/database/hierarchy/s_parameter_model.py +33 -0
- pyedb/grpc/database/hierarchy/spice_model.py +48 -0
- pyedb/grpc/database/layers/__init__.py +0 -0
- pyedb/grpc/database/layers/layer.py +57 -0
- pyedb/grpc/database/layers/stackup_layer.py +410 -0
- pyedb/grpc/database/layout/__init__.py +0 -0
- pyedb/grpc/database/layout/cell.py +30 -0
- pyedb/grpc/database/layout/layout.py +196 -0
- pyedb/grpc/database/layout/voltage_regulator.py +149 -0
- pyedb/grpc/database/layout_validation.py +319 -0
- pyedb/grpc/database/modeler.py +1468 -0
- pyedb/grpc/database/net/__init__.py +0 -0
- pyedb/grpc/database/net/differential_pair.py +138 -0
- pyedb/grpc/database/net/extended_net.py +340 -0
- pyedb/grpc/database/net/net.py +198 -0
- pyedb/grpc/database/net/net_class.py +93 -0
- pyedb/grpc/database/nets.py +633 -0
- pyedb/grpc/database/padstacks.py +1500 -0
- pyedb/grpc/database/ports/__init__.py +0 -0
- pyedb/grpc/database/ports/ports.py +396 -0
- pyedb/grpc/database/primitive/__init__.py +3 -0
- pyedb/grpc/database/primitive/bondwire.py +181 -0
- pyedb/grpc/database/primitive/circle.py +75 -0
- pyedb/grpc/database/primitive/padstack_instance.py +1116 -0
- pyedb/grpc/database/primitive/path.py +346 -0
- pyedb/grpc/database/primitive/polygon.py +276 -0
- pyedb/grpc/database/primitive/primitive.py +739 -0
- pyedb/grpc/database/primitive/rectangle.py +146 -0
- pyedb/grpc/database/simulation_setup/__init__.py +0 -0
- pyedb/grpc/database/simulation_setup/adaptive_frequency.py +33 -0
- pyedb/grpc/database/simulation_setup/hfss_advanced_meshing_settings.py +32 -0
- pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +59 -0
- pyedb/grpc/database/simulation_setup/hfss_dcr_settings.py +35 -0
- pyedb/grpc/database/simulation_setup/hfss_general_settings.py +61 -0
- pyedb/grpc/database/simulation_setup/hfss_settings_options.py +78 -0
- pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +118 -0
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +355 -0
- pyedb/grpc/database/simulation_setup/hfss_solver_settings.py +34 -0
- pyedb/grpc/database/simulation_setup/mesh_operation.py +34 -0
- pyedb/grpc/database/simulation_setup/raptor_x_advanced_settings.py +34 -0
- pyedb/grpc/database/simulation_setup/raptor_x_general_settings.py +33 -0
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +64 -0
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +125 -0
- pyedb/grpc/database/simulation_setup/siwave_dcir_simulation_setup.py +34 -0
- pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +119 -0
- pyedb/grpc/database/simulation_setup/sweep_data.py +32 -0
- pyedb/grpc/database/siwave.py +1023 -0
- pyedb/grpc/database/source_excitations.py +2572 -0
- pyedb/grpc/database/stackup.py +2574 -0
- pyedb/grpc/database/terminal/__init__.py +0 -0
- pyedb/grpc/database/terminal/bundle_terminal.py +218 -0
- pyedb/grpc/database/terminal/edge_terminal.py +51 -0
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +171 -0
- pyedb/grpc/database/terminal/pingroup_terminal.py +162 -0
- pyedb/grpc/database/terminal/point_terminal.py +99 -0
- pyedb/grpc/database/terminal/terminal.py +470 -0
- pyedb/grpc/database/utility/__init__.py +3 -0
- pyedb/grpc/database/utility/constants.py +25 -0
- pyedb/grpc/database/utility/heat_sink.py +124 -0
- pyedb/grpc/database/utility/hfss_extent_info.py +448 -0
- pyedb/grpc/database/utility/layout_statistics.py +277 -0
- pyedb/grpc/database/utility/rlc.py +80 -0
- pyedb/grpc/database/utility/simulation_configuration.py +3305 -0
- pyedb/grpc/database/utility/sources.py +388 -0
- pyedb/grpc/database/utility/sweep_data_distribution.py +83 -0
- pyedb/grpc/database/utility/xml_control_file.py +1277 -0
- pyedb/grpc/edb.py +4152 -0
- pyedb/grpc/edb_init.py +481 -0
- pyedb/grpc/rpc_session.py +177 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +3 -2
- pyedb/ipc2581/ecad/cad_data/feature.py +4 -3
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +32 -20
- pyedb/ipc2581/ecad/cad_data/outline.py +3 -2
- pyedb/ipc2581/ecad/cad_data/package.py +4 -3
- pyedb/ipc2581/ecad/cad_data/path.py +82 -31
- pyedb/ipc2581/ecad/cad_data/polygon.py +122 -60
- pyedb/ipc2581/ecad/cad_data/profile.py +13 -12
- pyedb/ipc2581/ecad/cad_data/step.py +53 -21
- pyedb/ipc2581/ipc2581.py +47 -49
- pyedb/modeler/geometry_operators.py +1 -1
- {pyedb-0.38.0.dist-info → pyedb-0.39.1.dist-info}/METADATA +5 -2
- pyedb-0.39.1.dist-info/RECORD +288 -0
- pyedb-0.38.0.dist-info/RECORD +0 -195
- /pyedb/dotnet/{edb_core → database}/__init__.py +0 -0
- /pyedb/dotnet/{application → database/cell}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell → database/cell/hierarchy}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/netlist_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/pin_pair_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/s_parameter_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/spice_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/primitive/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell/hierarchy → database/cell/terminal}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell/terminal → database/definition}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/definition → database/dotnet}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/dotnet → database/edb_data}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/design_options.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/edbvalue.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/layer_data.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/utilities.py +0 -0
- /pyedb/dotnet/{edb_core → database}/general.py +0 -0
- /pyedb/dotnet/{edb_core/edb_data → database/geometry}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/geometry/point_data.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/adaptive_frequency_data.py +0 -0
- /pyedb/dotnet/{edb_core/geometry → database/sim_setup_data/io}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/io/siwave.py +0 -0
- /pyedb/dotnet/{edb_core → database}/utilities/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/utilities/heatsink.py +0 -0
- /pyedb/{dotnet/edb_core/sim_setup_data/io → grpc/database/definition}/__init__.py +0 -0
- {pyedb-0.38.0.dist-info → pyedb-0.39.1.dist-info}/LICENSE +0 -0
- {pyedb-0.38.0.dist-info → pyedb-0.39.1.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
|