pyedb 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +17 -0
- pyedb/dotnet/__init__.py +0 -0
- pyedb/dotnet/application/Variables.py +2261 -0
- pyedb/dotnet/application/__init__.py +0 -0
- pyedb/dotnet/clr_module.py +103 -0
- pyedb/dotnet/edb.py +4237 -0
- pyedb/dotnet/edb_core/__init__.py +1 -0
- pyedb/dotnet/edb_core/cell/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
- pyedb/dotnet/edb_core/components.py +2669 -0
- pyedb/dotnet/edb_core/configuration.py +423 -0
- pyedb/dotnet/edb_core/definition/__init__.py +0 -0
- pyedb/dotnet/edb_core/definition/component_def.py +166 -0
- pyedb/dotnet/edb_core/definition/component_model.py +30 -0
- pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
- pyedb/dotnet/edb_core/definition/definitions.py +12 -0
- pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
- pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
- pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
- pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
- pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
- pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
- pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
- pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
- pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
- pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
- pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
- pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
- pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
- pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
- pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
- pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
- pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
- pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
- pyedb/dotnet/edb_core/general.py +181 -0
- pyedb/dotnet/edb_core/hfss.py +1646 -0
- pyedb/dotnet/edb_core/layout.py +1244 -0
- pyedb/dotnet/edb_core/layout_validation.py +272 -0
- pyedb/dotnet/edb_core/materials.py +939 -0
- pyedb/dotnet/edb_core/net_class.py +335 -0
- pyedb/dotnet/edb_core/nets.py +1215 -0
- pyedb/dotnet/edb_core/padstack.py +1389 -0
- pyedb/dotnet/edb_core/siwave.py +1427 -0
- pyedb/dotnet/edb_core/stackup.py +2703 -0
- pyedb/edb_logger.py +396 -0
- pyedb/generic/__init__.py +0 -0
- pyedb/generic/constants.py +1063 -0
- pyedb/generic/data_handlers.py +320 -0
- pyedb/generic/design_types.py +104 -0
- pyedb/generic/filesystem.py +150 -0
- pyedb/generic/general_methods.py +1535 -0
- pyedb/generic/plot.py +1840 -0
- pyedb/generic/process.py +285 -0
- pyedb/generic/settings.py +224 -0
- pyedb/ipc2581/__init__.py +0 -0
- pyedb/ipc2581/bom/__init__.py +0 -0
- pyedb/ipc2581/bom/bom.py +21 -0
- pyedb/ipc2581/bom/bom_item.py +32 -0
- pyedb/ipc2581/bom/characteristics.py +37 -0
- pyedb/ipc2581/bom/refdes.py +16 -0
- pyedb/ipc2581/content/__init__.py +0 -0
- pyedb/ipc2581/content/color.py +38 -0
- pyedb/ipc2581/content/content.py +55 -0
- pyedb/ipc2581/content/dictionary_color.py +29 -0
- pyedb/ipc2581/content/dictionary_fill.py +28 -0
- pyedb/ipc2581/content/dictionary_line.py +30 -0
- pyedb/ipc2581/content/entry_color.py +13 -0
- pyedb/ipc2581/content/entry_line.py +14 -0
- pyedb/ipc2581/content/fill.py +15 -0
- pyedb/ipc2581/content/layer_ref.py +10 -0
- pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
- pyedb/ipc2581/ecad/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
- pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
- pyedb/ipc2581/ecad/cad_data/component.py +41 -0
- pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
- pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
- pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
- pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
- pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
- pyedb/ipc2581/ecad/cad_data/package.py +104 -0
- pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
- pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
- pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
- pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
- pyedb/ipc2581/ecad/cad_data/path.py +89 -0
- pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
- pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
- pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
- pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
- pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
- pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
- pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
- pyedb/ipc2581/ecad/cad_data/step.py +275 -0
- pyedb/ipc2581/ecad/cad_header.py +33 -0
- pyedb/ipc2581/ecad/ecad.py +19 -0
- pyedb/ipc2581/ecad/spec.py +46 -0
- pyedb/ipc2581/history_record.py +37 -0
- pyedb/ipc2581/ipc2581.py +387 -0
- pyedb/ipc2581/logistic_header.py +25 -0
- pyedb/misc/__init__.py +0 -0
- pyedb/misc/aedtlib_personalib_install.py +14 -0
- pyedb/misc/downloads.py +322 -0
- pyedb/misc/misc.py +67 -0
- pyedb/misc/pyedb.runtimeconfig.json +13 -0
- pyedb/misc/siw_feature_config/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
- pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
- pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
- pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
- pyedb/misc/utilities.py +27 -0
- pyedb/modeler/geometry_operators.py +2082 -0
- pyedb-0.2.0.dist-info/LICENSE +21 -0
- pyedb-0.2.0.dist-info/METADATA +208 -0
- pyedb-0.2.0.dist-info/RECORD +128 -0
- pyedb-0.2.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,2261 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains these classes: `CSVDataset`, `DataSet`, `Expression`, `Variable`, and `VariableManager`.
|
|
3
|
+
|
|
4
|
+
This module is used to create and edit design and project variables in the 3D tools.
|
|
5
|
+
|
|
6
|
+
Examples
|
|
7
|
+
--------
|
|
8
|
+
>>> from pyaedt import Hfss
|
|
9
|
+
>>> hfss = Hfss()
|
|
10
|
+
>>> hfss["$d"] = "5mm"
|
|
11
|
+
>>> hfss["d"] = "5mm"
|
|
12
|
+
>>> hfss["postd"] = "1W"
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import absolute_import # noreorder
|
|
17
|
+
from __future__ import division
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import re
|
|
21
|
+
import types
|
|
22
|
+
|
|
23
|
+
from pyedb.generic.constants import (
|
|
24
|
+
AEDT_UNITS,
|
|
25
|
+
SI_UNITS,
|
|
26
|
+
_resolve_unit_system,
|
|
27
|
+
unit_system,
|
|
28
|
+
)
|
|
29
|
+
from pyedb.generic.general_methods import (
|
|
30
|
+
GrpcApiError,
|
|
31
|
+
check_numeric_equivalence,
|
|
32
|
+
is_array,
|
|
33
|
+
is_number,
|
|
34
|
+
open_file,
|
|
35
|
+
pyedb_function_handler,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class CSVDataset:
|
|
40
|
+
"""Reads in a CSV file and extracts data, which can be augmented with constant values.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
csv_file : str, optional
|
|
45
|
+
Input file consisting of delimited data with the first line as the header.
|
|
46
|
+
The CSV value includes the header and data, which supports AEDT units information
|
|
47
|
+
such as ``"1.23Wb"``. You can also augment the data with constant values.
|
|
48
|
+
separator : str, optional
|
|
49
|
+
Value to use for the delimiter. The default is``None`` in which case a comma is
|
|
50
|
+
assumed.
|
|
51
|
+
units_dict : dict, optional
|
|
52
|
+
Dictionary consisting of ``{Variable Name: unit}`` to rescale the data
|
|
53
|
+
if it is not in the desired unit system.
|
|
54
|
+
append_dict : dict, optional
|
|
55
|
+
Dictionary consisting of ``{New Variable Name: value}`` to add variables
|
|
56
|
+
with constant values to all data points. This dictionary is used to add
|
|
57
|
+
multiple sweeps to one result file.
|
|
58
|
+
valid_solutions : bool, optional
|
|
59
|
+
The default is ``True``.
|
|
60
|
+
invalid_solutions : bool, optional
|
|
61
|
+
The default is ``False``.
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def number_of_rows(self): # pragma: no cover
|
|
67
|
+
"""Number of rows."""
|
|
68
|
+
if self._data:
|
|
69
|
+
for variable, data_list in self._data.items():
|
|
70
|
+
return len(data_list)
|
|
71
|
+
else:
|
|
72
|
+
return 0
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def number_of_columns(self): # pragma: no cover
|
|
76
|
+
"""Number of columns."""
|
|
77
|
+
return len(self._header)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def header(self): # pragma: no cover
|
|
81
|
+
"""Header."""
|
|
82
|
+
return self._header
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def data(self): # pragma: no cover
|
|
86
|
+
"""Data."""
|
|
87
|
+
return self._data
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def path(self): # pragma: no cover
|
|
91
|
+
"""Path."""
|
|
92
|
+
return os.path.dirname(os.path.realpath(self._csv_file))
|
|
93
|
+
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
csv_file=None,
|
|
97
|
+
separator=None,
|
|
98
|
+
units_dict=None,
|
|
99
|
+
append_dict=None,
|
|
100
|
+
valid_solutions=True,
|
|
101
|
+
invalid_solutions=False,
|
|
102
|
+
): # pragma: no cover
|
|
103
|
+
self._header = []
|
|
104
|
+
self._data = {}
|
|
105
|
+
self._unit_dict = {}
|
|
106
|
+
self._append_dict = {}
|
|
107
|
+
|
|
108
|
+
# Set the index counter explicitly to zero
|
|
109
|
+
self._index = 0
|
|
110
|
+
|
|
111
|
+
if separator:
|
|
112
|
+
self._separator = separator
|
|
113
|
+
else:
|
|
114
|
+
self._separator = ","
|
|
115
|
+
|
|
116
|
+
if units_dict:
|
|
117
|
+
self._unit_dict = units_dict
|
|
118
|
+
|
|
119
|
+
if append_dict:
|
|
120
|
+
self._append_dict = append_dict
|
|
121
|
+
|
|
122
|
+
self._csv_file = csv_file
|
|
123
|
+
if csv_file:
|
|
124
|
+
with open_file(csv_file, "r") as fi:
|
|
125
|
+
file_data = fi.readlines()
|
|
126
|
+
for line in file_data:
|
|
127
|
+
if self._header:
|
|
128
|
+
line_data = line.strip().split(self._separator)
|
|
129
|
+
# Check for invalid data in the line (fields with 'nan')
|
|
130
|
+
if "nan" not in line_data:
|
|
131
|
+
for j, value in enumerate(line_data):
|
|
132
|
+
var_name = self._header[j]
|
|
133
|
+
if var_name in self._unit_dict:
|
|
134
|
+
var_value = Variable(value).rescale_to(self._unit_dict[var_name]).numeric_value
|
|
135
|
+
else:
|
|
136
|
+
var_value = Variable(value).value
|
|
137
|
+
self._data[var_name].append(var_value)
|
|
138
|
+
|
|
139
|
+
# Add augmented quantities
|
|
140
|
+
for entry in self._append_dict:
|
|
141
|
+
var_value_str = self._append_dict[entry]
|
|
142
|
+
numeric_value = Variable(var_value_str).numeric_value
|
|
143
|
+
self._data[entry].append(numeric_value)
|
|
144
|
+
|
|
145
|
+
else:
|
|
146
|
+
self._header = line.strip().split(",")
|
|
147
|
+
for additional_quantity_name in self._append_dict:
|
|
148
|
+
self._header.append(additional_quantity_name)
|
|
149
|
+
for quantity_name in self._header:
|
|
150
|
+
self._data[quantity_name] = []
|
|
151
|
+
|
|
152
|
+
pass
|
|
153
|
+
|
|
154
|
+
@pyedb_function_handler()
|
|
155
|
+
def __getitem__(self, item): # pragma: no cover
|
|
156
|
+
variable_list = item.split(",")
|
|
157
|
+
data_out = CSVDataset()
|
|
158
|
+
for variable in variable_list:
|
|
159
|
+
found_variable = False
|
|
160
|
+
for key_string in self._data:
|
|
161
|
+
if variable in key_string:
|
|
162
|
+
found_variable = True
|
|
163
|
+
break
|
|
164
|
+
assert found_variable, "Input string {} is not a key of the data dictionary.".format(variable)
|
|
165
|
+
data_out._data[variable] = self._data[key_string]
|
|
166
|
+
data_out._header.append(variable)
|
|
167
|
+
return data_out
|
|
168
|
+
|
|
169
|
+
@pyedb_function_handler()
|
|
170
|
+
def __add__(self, other): # pragma: no cover
|
|
171
|
+
assert self.number_of_columns == other.number_of_columns, "Inconsistent number of columns"
|
|
172
|
+
# Create a new object to return, avoiding changing the original inputs
|
|
173
|
+
new_dataset = CSVDataset()
|
|
174
|
+
# Add empty columns to new_dataset
|
|
175
|
+
for column in self._data:
|
|
176
|
+
new_dataset._data[column] = []
|
|
177
|
+
|
|
178
|
+
# Add the data from 'self' to a the new dataset
|
|
179
|
+
for column, row_data in self.data.items():
|
|
180
|
+
for value in row_data:
|
|
181
|
+
new_dataset._data[column].append(value)
|
|
182
|
+
|
|
183
|
+
# Add the data from 'other' to a the new dataset
|
|
184
|
+
for column, row_data in other.data.items():
|
|
185
|
+
for value in row_data:
|
|
186
|
+
new_dataset._data[column].append(value)
|
|
187
|
+
|
|
188
|
+
return new_dataset
|
|
189
|
+
|
|
190
|
+
def __iadd__(self, other): # pragma: no cover
|
|
191
|
+
"""Incrementally add the dataset in one CSV file to a dataset in another CSV file.
|
|
192
|
+
|
|
193
|
+
.. note:
|
|
194
|
+
This assumes that the number of columns in both datasets are the same,
|
|
195
|
+
or that one of the datasets is empty. No checking is done for
|
|
196
|
+
equivalency of units or variable names.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
# Handle the case of an empty data set and create empty lists for the column data
|
|
201
|
+
if self.number_of_columns == 0:
|
|
202
|
+
self._header = other.header
|
|
203
|
+
for column in other.data:
|
|
204
|
+
self._data[column] = []
|
|
205
|
+
|
|
206
|
+
assert self.number_of_columns == other.number_of_columns, "Inconsistent number of columns"
|
|
207
|
+
|
|
208
|
+
# Append the data from 'other'
|
|
209
|
+
for column, row_data in other.data.items():
|
|
210
|
+
for value in row_data:
|
|
211
|
+
self._data[column].append(value)
|
|
212
|
+
|
|
213
|
+
return self
|
|
214
|
+
|
|
215
|
+
# Called when iteration is initialized
|
|
216
|
+
def __iter__(self): # pragma: no cover
|
|
217
|
+
self._index = 0
|
|
218
|
+
return self
|
|
219
|
+
|
|
220
|
+
# Create an iterator to yield the row data as a string as we loop through the object
|
|
221
|
+
def __next__(self): # pragma: no cover
|
|
222
|
+
if self._index < (self.number_of_rows - 1):
|
|
223
|
+
output = []
|
|
224
|
+
for column in self._header:
|
|
225
|
+
evaluated_value = str(self._data[column][self._index])
|
|
226
|
+
output.append(evaluated_value)
|
|
227
|
+
output_string = " ".join(output)
|
|
228
|
+
self._index += 1
|
|
229
|
+
else:
|
|
230
|
+
raise StopIteration
|
|
231
|
+
|
|
232
|
+
return output_string
|
|
233
|
+
|
|
234
|
+
def next(self): # pragma: no cover
|
|
235
|
+
"""Yield the next row."""
|
|
236
|
+
return self.__next__()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@pyedb_function_handler()
|
|
240
|
+
def _find_units_in_dependent_variables(variable_value, full_variables={}): # pragma: no cover
|
|
241
|
+
m2 = re.findall(r"[0-9.]+ *([a-z_A-Z]+)", variable_value)
|
|
242
|
+
if len(m2) > 0:
|
|
243
|
+
if len(set(m2)) <= 1:
|
|
244
|
+
return m2[0]
|
|
245
|
+
else:
|
|
246
|
+
if unit_system(m2[0]):
|
|
247
|
+
return SI_UNITS[unit_system(m2[0])]
|
|
248
|
+
else:
|
|
249
|
+
m1 = re.findall(r"(?<=[/+-/*//^/(/[])([a-z_A-Z/$]\w*)", variable_value.replace(" ", ""))
|
|
250
|
+
m2 = re.findall(r"^([a-z_A-Z/$]\w*)", variable_value.replace(" ", ""))
|
|
251
|
+
m = list(set(m1).union(m2))
|
|
252
|
+
for i, v in full_variables.items():
|
|
253
|
+
if i in m and _find_units_in_dependent_variables(v):
|
|
254
|
+
return _find_units_in_dependent_variables(v)
|
|
255
|
+
return ""
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@pyedb_function_handler()
|
|
259
|
+
def decompose_variable_value(variable_value, full_variables={}): # pragma: no cover
|
|
260
|
+
"""Decompose a variable value.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
variable_value : str
|
|
265
|
+
full_variables : dict
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
tuples
|
|
270
|
+
Tuples made of the float value of the variable and the units exposed as a string.
|
|
271
|
+
"""
|
|
272
|
+
# set default return values - then check for valid units
|
|
273
|
+
float_value = variable_value
|
|
274
|
+
units = ""
|
|
275
|
+
|
|
276
|
+
if is_number(variable_value):
|
|
277
|
+
float_value = float(variable_value)
|
|
278
|
+
elif isinstance(variable_value, str) and variable_value != "nan":
|
|
279
|
+
try:
|
|
280
|
+
# Handle a numerical value in string form
|
|
281
|
+
float_value = float(variable_value)
|
|
282
|
+
except ValueError:
|
|
283
|
+
# search for a valid units string at the end of the variable_value
|
|
284
|
+
loc = re.search("[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?", variable_value)
|
|
285
|
+
units = _find_units_in_dependent_variables(variable_value, full_variables)
|
|
286
|
+
if loc:
|
|
287
|
+
loc_units = loc.span()[1]
|
|
288
|
+
extract_units = variable_value[loc_units:]
|
|
289
|
+
chars = set("+*/()[]")
|
|
290
|
+
if any((c in chars) for c in extract_units):
|
|
291
|
+
return variable_value, units
|
|
292
|
+
try:
|
|
293
|
+
float_value = float(variable_value[0:loc_units])
|
|
294
|
+
units = extract_units
|
|
295
|
+
except ValueError:
|
|
296
|
+
float_value = variable_value
|
|
297
|
+
|
|
298
|
+
return float_value, units
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@pyedb_function_handler()
|
|
302
|
+
def _generate_property_validation_errors(property_name, expected, actual): # pragma: no cover
|
|
303
|
+
expected_value, expected_unit = decompose_variable_value(expected)
|
|
304
|
+
actual_value, actual_unit = decompose_variable_value(actual)
|
|
305
|
+
|
|
306
|
+
if isinstance(expected_value, (float, int)) and isinstance(actual_value, (float, int)):
|
|
307
|
+
if not check_numeric_equivalence(expected_value, actual_value, 1e-9):
|
|
308
|
+
yield "Value Error {0}: Expected {1}, got {2}".format(property_name, expected, actual)
|
|
309
|
+
if expected_unit != actual_unit:
|
|
310
|
+
yield "Unit Error {0}: Expected {1}, got {2}".format(property_name, expected_unit, actual_unit)
|
|
311
|
+
else:
|
|
312
|
+
if expected != actual:
|
|
313
|
+
yield "Error {0}: Expected {1}, got {2}".format(property_name, expected, actual)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@pyedb_function_handler()
|
|
317
|
+
def generate_validation_errors(property_names, expected_settings, actual_settings): # pragma: no cover
|
|
318
|
+
"""From the given property names, expected settings and actual settings, return a list of validation errors.
|
|
319
|
+
If no errors are found, an empty list is returned. The validation of values such as "10mm"
|
|
320
|
+
ensures that they are close to within a relative tolerance.
|
|
321
|
+
For example an expected setting of "10mm", and actual of "10.000000001mm" will not yield a validation error.
|
|
322
|
+
For values with no numerical value, an equivalence check is made.
|
|
323
|
+
|
|
324
|
+
Parameters
|
|
325
|
+
----------
|
|
326
|
+
property_names : List[str]
|
|
327
|
+
List of property names.
|
|
328
|
+
expected_settings : List[str]
|
|
329
|
+
List of the expected settings.
|
|
330
|
+
actual_settings : List[str]
|
|
331
|
+
List of actual settings.
|
|
332
|
+
|
|
333
|
+
Returns
|
|
334
|
+
-------
|
|
335
|
+
List[str]
|
|
336
|
+
A list of validation errors for the given settings.
|
|
337
|
+
"""
|
|
338
|
+
validation_errors = [
|
|
339
|
+
error
|
|
340
|
+
for property_name, expected, actual in zip(property_names, expected_settings, actual_settings)
|
|
341
|
+
for error in _generate_property_validation_errors(property_name, expected, actual)
|
|
342
|
+
]
|
|
343
|
+
return validation_errors
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
# TODO: See how we handle this (totally removed / reworked ) ?
|
|
347
|
+
class VariableManager(object):
|
|
348
|
+
"""Manages design properties and project variables.
|
|
349
|
+
|
|
350
|
+
Design properties are the local variables in a design. Project
|
|
351
|
+
variables are defined at the project level and start with ``$``.
|
|
352
|
+
|
|
353
|
+
This class provides access to all variables or a subset of the
|
|
354
|
+
variables. Manipulation of the numerical or string definitions of
|
|
355
|
+
variable values is provided in the
|
|
356
|
+
:class:`pyedb.dotnet.application.Variables.Variable` class.
|
|
357
|
+
|
|
358
|
+
Parameters
|
|
359
|
+
----------
|
|
360
|
+
variables : dict
|
|
361
|
+
Dictionary of all design properties and project variables in
|
|
362
|
+
the active design.
|
|
363
|
+
design_variables : dict
|
|
364
|
+
Dictionary of all design properties in the active design.
|
|
365
|
+
project_variables : dict
|
|
366
|
+
Dictionary of all project variables available to the active
|
|
367
|
+
design (key by variable name).
|
|
368
|
+
dependent_variables : dict
|
|
369
|
+
Dictionary of all dependent variables available to the active
|
|
370
|
+
design (key by variable name).
|
|
371
|
+
independent_variables : dict
|
|
372
|
+
Dictionary of all independent variables (constant numeric
|
|
373
|
+
values) available to the active design (key by variable name).
|
|
374
|
+
independent_design_variables : dict
|
|
375
|
+
|
|
376
|
+
independent_project_variables : dict
|
|
377
|
+
|
|
378
|
+
variable_names : str or list
|
|
379
|
+
One or more variable names.
|
|
380
|
+
project_variable_names : str or list
|
|
381
|
+
One or more project variable names.
|
|
382
|
+
design_variable_names : str or list
|
|
383
|
+
One or more design variable names.
|
|
384
|
+
dependent_variable_names : str or list
|
|
385
|
+
All dependent variable names within the project.
|
|
386
|
+
independent_variable_names : list of str
|
|
387
|
+
All independent variable names within the project. These can
|
|
388
|
+
be sweep variables for optimetrics.
|
|
389
|
+
independent_project_variable_names : str or list
|
|
390
|
+
All independent project variable names within the
|
|
391
|
+
project. These can be sweep variables for optimetrics.
|
|
392
|
+
independent_design_variable_names : str or list
|
|
393
|
+
All independent design properties (local variables) within the
|
|
394
|
+
project. These can be sweep variables for optimetrics.
|
|
395
|
+
|
|
396
|
+
See Also
|
|
397
|
+
--------
|
|
398
|
+
pyedb.dotnet.application.Variables.Variable
|
|
399
|
+
|
|
400
|
+
Examples
|
|
401
|
+
--------
|
|
402
|
+
|
|
403
|
+
>>> from pyaedt.maxwell import Maxwell3d
|
|
404
|
+
>>> from pyaedt.desktop import Desktop
|
|
405
|
+
>>> d = Desktop()
|
|
406
|
+
>>> aedtapp = Maxwell3d()
|
|
407
|
+
|
|
408
|
+
Define some test variables.
|
|
409
|
+
|
|
410
|
+
>>> aedtapp["Var1"] = 3
|
|
411
|
+
>>> aedtapp["Var2"] = "12deg"
|
|
412
|
+
>>> aedtapp["Var3"] = "Var1 * Var2"
|
|
413
|
+
>>> aedtapp["$PrjVar1"] = "pi"
|
|
414
|
+
|
|
415
|
+
Get the variable manager for the active design.
|
|
416
|
+
|
|
417
|
+
>>> v = aedtapp.variable_manager
|
|
418
|
+
|
|
419
|
+
Get a dictionary of all project and design variables.
|
|
420
|
+
|
|
421
|
+
>>> v.variables
|
|
422
|
+
{'Var1': <pyedb.dotnet.application.Variables.Variable at 0x2661f34c448>,
|
|
423
|
+
'Var2': <pyedb.dotnet.application.Variables.Variable at 0x2661f34c308>,
|
|
424
|
+
'Var3': <pyedb.dotnet.application.Variables.Expression at 0x2661f34cb48>,
|
|
425
|
+
'$PrjVar1': <pyedb.dotnet.application.Variables.Expression at 0x2661f34cc48>}
|
|
426
|
+
|
|
427
|
+
Get a dictionary of only the design variables.
|
|
428
|
+
|
|
429
|
+
>>> v.design_variables
|
|
430
|
+
{'Var1': <pyedb.dotnet.application.Variables.Variable at 0x2661f339508>,
|
|
431
|
+
'Var2': <pyedb.dotnet.application.Variables.Variable at 0x2661f3415c8>,
|
|
432
|
+
'Var3': <pyedb.dotnet.application.Variables.Expression at 0x2661f341808>}
|
|
433
|
+
|
|
434
|
+
Get a dictionary of only the independent design variables.
|
|
435
|
+
|
|
436
|
+
>>> v.independent_design_variables
|
|
437
|
+
{'Var1': <pyedb.dotnet.application.Variables.Variable at 0x2661f335d08>,
|
|
438
|
+
'Var2': <pyedb.dotnet.application.Variables.Variable at 0x2661f3557c8>}
|
|
439
|
+
|
|
440
|
+
"""
|
|
441
|
+
|
|
442
|
+
@property
|
|
443
|
+
def variables(self): # pragma: no cover
|
|
444
|
+
"""Variables.
|
|
445
|
+
|
|
446
|
+
Returns
|
|
447
|
+
-------
|
|
448
|
+
dict
|
|
449
|
+
Dictionary of the `Variable` objects for each project variable and each
|
|
450
|
+
design property in the active design.
|
|
451
|
+
|
|
452
|
+
References
|
|
453
|
+
----------
|
|
454
|
+
|
|
455
|
+
>>> oProject.GetVariables
|
|
456
|
+
>>> oDesign.GetVariables
|
|
457
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
458
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames
|
|
459
|
+
"""
|
|
460
|
+
return self._variable_dict([self._odesign, self._oproject])
|
|
461
|
+
|
|
462
|
+
@pyedb_function_handler()
|
|
463
|
+
def decompose(self, variable_value): # pragma: no cover
|
|
464
|
+
"""Decompose a variable string to a floating with its unit.
|
|
465
|
+
|
|
466
|
+
Parameters
|
|
467
|
+
----------
|
|
468
|
+
variable_value : str
|
|
469
|
+
|
|
470
|
+
Returns
|
|
471
|
+
-------
|
|
472
|
+
tuple
|
|
473
|
+
The float value of the variable and the units exposed as a string.
|
|
474
|
+
|
|
475
|
+
Examples
|
|
476
|
+
--------
|
|
477
|
+
>>> hfss = Hfss()
|
|
478
|
+
>>> print(hfss.variable_manager.decompose("5mm"))
|
|
479
|
+
>>> (5.0, 'mm')
|
|
480
|
+
>>> hfss["v1"] = "3N"
|
|
481
|
+
>>> print(hfss.variable_manager.decompose("v1"))
|
|
482
|
+
>>> (3.0, 'N')
|
|
483
|
+
>>> hfss["v2"] = "2*v1"
|
|
484
|
+
>>> print(hfss.variable_manager.decompose("v2"))
|
|
485
|
+
>>> (6.0, 'N')
|
|
486
|
+
"""
|
|
487
|
+
if variable_value in self.independent_variable_names:
|
|
488
|
+
val, unit = decompose_variable_value(self[variable_value].expression)
|
|
489
|
+
elif variable_value in self.dependent_variable_names:
|
|
490
|
+
val, unit = decompose_variable_value(self[variable_value].evaluated_value)
|
|
491
|
+
else:
|
|
492
|
+
val, unit = decompose_variable_value(variable_value)
|
|
493
|
+
return val, unit
|
|
494
|
+
|
|
495
|
+
@property
|
|
496
|
+
def design_variables(self): # pragma: no cover
|
|
497
|
+
"""Design variables.
|
|
498
|
+
|
|
499
|
+
Returns
|
|
500
|
+
-------
|
|
501
|
+
dict
|
|
502
|
+
Dictionary of the design properties (local properties) in the design.
|
|
503
|
+
|
|
504
|
+
References
|
|
505
|
+
----------
|
|
506
|
+
|
|
507
|
+
>>> oDesign.GetVariables
|
|
508
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames
|
|
509
|
+
"""
|
|
510
|
+
return self._variable_dict([self._odesign])
|
|
511
|
+
|
|
512
|
+
@property
|
|
513
|
+
def project_variables(self): # pragma: no cover
|
|
514
|
+
"""Project variables.
|
|
515
|
+
|
|
516
|
+
Returns
|
|
517
|
+
-------
|
|
518
|
+
dict
|
|
519
|
+
Dictionary of the project properties.
|
|
520
|
+
|
|
521
|
+
References
|
|
522
|
+
----------
|
|
523
|
+
|
|
524
|
+
>>> oProject.GetVariables
|
|
525
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
526
|
+
"""
|
|
527
|
+
return self._variable_dict([self._oproject])
|
|
528
|
+
|
|
529
|
+
@property
|
|
530
|
+
def post_processing_variables(self): # pragma: no cover
|
|
531
|
+
"""Post Processing variables.
|
|
532
|
+
|
|
533
|
+
Returns
|
|
534
|
+
-------
|
|
535
|
+
dict
|
|
536
|
+
Dictionary of the post processing variables (constant numeric
|
|
537
|
+
values) available to the design.
|
|
538
|
+
|
|
539
|
+
References
|
|
540
|
+
----------
|
|
541
|
+
|
|
542
|
+
>>> oProject.GetVariables
|
|
543
|
+
>>> oDesign.GetVariables
|
|
544
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
545
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames
|
|
546
|
+
"""
|
|
547
|
+
try:
|
|
548
|
+
all_post_vars = list(self._odesign.GetPostProcessingVariables())
|
|
549
|
+
except:
|
|
550
|
+
all_post_vars = []
|
|
551
|
+
out = self.design_variables
|
|
552
|
+
post_vars = {}
|
|
553
|
+
for k, v in out.items():
|
|
554
|
+
if k in all_post_vars:
|
|
555
|
+
post_vars[k] = v
|
|
556
|
+
return post_vars
|
|
557
|
+
|
|
558
|
+
@property
|
|
559
|
+
def independent_variables(self): # pragma: no cover
|
|
560
|
+
"""Independent variables.
|
|
561
|
+
|
|
562
|
+
Returns
|
|
563
|
+
-------
|
|
564
|
+
dict
|
|
565
|
+
Dictionary of the independent variables (constant numeric
|
|
566
|
+
values) available to the design.
|
|
567
|
+
|
|
568
|
+
References
|
|
569
|
+
----------
|
|
570
|
+
|
|
571
|
+
>>> oProject.GetVariables
|
|
572
|
+
>>> oDesign.GetVariables
|
|
573
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
574
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames
|
|
575
|
+
"""
|
|
576
|
+
return self._variable_dict([self._odesign, self._oproject], dependent=False)
|
|
577
|
+
|
|
578
|
+
@property
|
|
579
|
+
def independent_project_variables(self): # pragma: no cover
|
|
580
|
+
"""Independent project variables.
|
|
581
|
+
|
|
582
|
+
Returns
|
|
583
|
+
-------
|
|
584
|
+
dict
|
|
585
|
+
Dictionary of the independent project variables available to the design.
|
|
586
|
+
|
|
587
|
+
References
|
|
588
|
+
----------
|
|
589
|
+
|
|
590
|
+
>>> oProject.GetVariables
|
|
591
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
592
|
+
"""
|
|
593
|
+
return self._variable_dict([self._oproject], dependent=False)
|
|
594
|
+
|
|
595
|
+
@property
|
|
596
|
+
def independent_design_variables(self): # pragma: no cover
|
|
597
|
+
"""Independent design variables.
|
|
598
|
+
|
|
599
|
+
Returns
|
|
600
|
+
-------
|
|
601
|
+
dict
|
|
602
|
+
Dictionary of the independent design properties (local
|
|
603
|
+
variables) available to the design.
|
|
604
|
+
|
|
605
|
+
References
|
|
606
|
+
----------
|
|
607
|
+
|
|
608
|
+
>>> oDesign.GetVariables
|
|
609
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames
|
|
610
|
+
"""
|
|
611
|
+
return self._variable_dict([self._odesign], dependent=False)
|
|
612
|
+
|
|
613
|
+
@property
|
|
614
|
+
def dependent_variables(self): # pragma: no cover
|
|
615
|
+
"""Dependent variables.
|
|
616
|
+
|
|
617
|
+
Returns
|
|
618
|
+
-------
|
|
619
|
+
dict
|
|
620
|
+
Dictionary of the dependent design properties (local
|
|
621
|
+
variables) and project variables available to the design.
|
|
622
|
+
|
|
623
|
+
References
|
|
624
|
+
----------
|
|
625
|
+
|
|
626
|
+
>>> oProject.GetVariables
|
|
627
|
+
>>> oDesign.GetVariables
|
|
628
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
629
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames
|
|
630
|
+
"""
|
|
631
|
+
return self._variable_dict([self._odesign, self._oproject], independent=False)
|
|
632
|
+
|
|
633
|
+
@property
|
|
634
|
+
def dependent_project_variables(self): # pragma: no cover
|
|
635
|
+
"""Dependent project variables.
|
|
636
|
+
|
|
637
|
+
Returns
|
|
638
|
+
-------
|
|
639
|
+
dict
|
|
640
|
+
Dictionary of the dependent project variables available to the design.
|
|
641
|
+
|
|
642
|
+
References
|
|
643
|
+
----------
|
|
644
|
+
|
|
645
|
+
>>> oProject.GetVariables
|
|
646
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
647
|
+
"""
|
|
648
|
+
return self._variable_dict([self._oproject], independent=False)
|
|
649
|
+
|
|
650
|
+
@property
|
|
651
|
+
def dependent_design_variables(self): # pragma: no cover
|
|
652
|
+
"""Dependent design variables.
|
|
653
|
+
|
|
654
|
+
Returns
|
|
655
|
+
-------
|
|
656
|
+
dict
|
|
657
|
+
Dictionary of the dependent design properties (local
|
|
658
|
+
variables) available to the design.
|
|
659
|
+
|
|
660
|
+
References
|
|
661
|
+
----------
|
|
662
|
+
|
|
663
|
+
>>> oDesign.GetVariables
|
|
664
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames
|
|
665
|
+
"""
|
|
666
|
+
return self._variable_dict([self._odesign], independent=False)
|
|
667
|
+
|
|
668
|
+
@property
|
|
669
|
+
def variable_names(self): # pragma: no cover
|
|
670
|
+
"""List of variables."""
|
|
671
|
+
return [var_name for var_name in self.variables]
|
|
672
|
+
|
|
673
|
+
@property
|
|
674
|
+
def project_variable_names(self): # pragma: no cover
|
|
675
|
+
"""List of project variables.
|
|
676
|
+
|
|
677
|
+
References
|
|
678
|
+
----------
|
|
679
|
+
|
|
680
|
+
>>> oProject.GetVariables
|
|
681
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
682
|
+
"""
|
|
683
|
+
return [var_name for var_name in self.project_variables]
|
|
684
|
+
|
|
685
|
+
@property
|
|
686
|
+
def design_variable_names(self): # pragma: no cover
|
|
687
|
+
"""List of design variables.
|
|
688
|
+
|
|
689
|
+
References
|
|
690
|
+
----------
|
|
691
|
+
|
|
692
|
+
>>> oDesign.GetVariables
|
|
693
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames"""
|
|
694
|
+
return [var_name for var_name in self.design_variables]
|
|
695
|
+
|
|
696
|
+
@property
|
|
697
|
+
def independent_project_variable_names(self): # pragma: no cover
|
|
698
|
+
"""List of independent project variables.
|
|
699
|
+
|
|
700
|
+
References
|
|
701
|
+
----------
|
|
702
|
+
|
|
703
|
+
>>> oProject.GetVariables
|
|
704
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
705
|
+
"""
|
|
706
|
+
return [var_name for var_name in self.independent_project_variables]
|
|
707
|
+
|
|
708
|
+
@property
|
|
709
|
+
def independent_design_variable_names(self): # pragma: no cover
|
|
710
|
+
"""List of independent design variables.
|
|
711
|
+
|
|
712
|
+
References
|
|
713
|
+
----------
|
|
714
|
+
|
|
715
|
+
>>> oDesign.GetVariables
|
|
716
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames"""
|
|
717
|
+
return [var_name for var_name in self.independent_design_variables]
|
|
718
|
+
|
|
719
|
+
@property
|
|
720
|
+
def independent_variable_names(self): # pragma: no cover
|
|
721
|
+
"""List of independent variables.
|
|
722
|
+
|
|
723
|
+
References
|
|
724
|
+
----------
|
|
725
|
+
|
|
726
|
+
>>> oProject.GetVariables
|
|
727
|
+
>>> oDesign.GetVariables
|
|
728
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
729
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames"""
|
|
730
|
+
return [var_name for var_name in self.independent_variables]
|
|
731
|
+
|
|
732
|
+
@property
|
|
733
|
+
def dependent_project_variable_names(self): # pragma: no cover
|
|
734
|
+
"""List of dependent project variables.
|
|
735
|
+
|
|
736
|
+
References
|
|
737
|
+
----------
|
|
738
|
+
|
|
739
|
+
>>> oProject.GetVariables
|
|
740
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
741
|
+
"""
|
|
742
|
+
return [var_name for var_name in self.dependent_project_variables]
|
|
743
|
+
|
|
744
|
+
@property
|
|
745
|
+
def dependent_design_variable_names(self): # pragma: no cover
|
|
746
|
+
"""List of dependent design variables.
|
|
747
|
+
|
|
748
|
+
References
|
|
749
|
+
----------
|
|
750
|
+
|
|
751
|
+
>>> oDesign.GetVariables
|
|
752
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames"""
|
|
753
|
+
return [var_name for var_name in self.dependent_design_variables]
|
|
754
|
+
|
|
755
|
+
@property
|
|
756
|
+
def dependent_variable_names(self): # pragma: no cover
|
|
757
|
+
"""List of dependent variables.
|
|
758
|
+
|
|
759
|
+
References
|
|
760
|
+
----------
|
|
761
|
+
|
|
762
|
+
>>> oProject.GetVariables
|
|
763
|
+
>>> oDesign.GetVariables
|
|
764
|
+
>>> oProject.GetChildObject("Variables").GetChildNames
|
|
765
|
+
>>> oDesign.GetChildObject("Variables").GetChildNames"""
|
|
766
|
+
return [var_name for var_name in self.dependent_variables]
|
|
767
|
+
|
|
768
|
+
@property
|
|
769
|
+
def _oproject(self): # pragma: no cover
|
|
770
|
+
"""Project."""
|
|
771
|
+
return self._app._oproject
|
|
772
|
+
|
|
773
|
+
@property
|
|
774
|
+
def _odesign(self): # pragma: no cover
|
|
775
|
+
"""Design."""
|
|
776
|
+
return self._app._odesign
|
|
777
|
+
|
|
778
|
+
@property
|
|
779
|
+
def _logger(self): # pragma: no cover
|
|
780
|
+
"""Logger."""
|
|
781
|
+
return self._app.logger
|
|
782
|
+
|
|
783
|
+
def __init__(self, app):
|
|
784
|
+
# Global Desktop Environment
|
|
785
|
+
self._app = app
|
|
786
|
+
self._independent_design_variables = {}
|
|
787
|
+
self._independent_project_variables = {}
|
|
788
|
+
self._dependent_design_variables = {}
|
|
789
|
+
self._dependent_project_variables = {}
|
|
790
|
+
|
|
791
|
+
@property
|
|
792
|
+
def _independent_variables(self): # pragma: no cover
|
|
793
|
+
all = {}
|
|
794
|
+
all.update(self._independent_project_variables)
|
|
795
|
+
all.update(self._independent_design_variables)
|
|
796
|
+
return all
|
|
797
|
+
|
|
798
|
+
@property
|
|
799
|
+
def _dependent_variables(self): # pragma: no cover
|
|
800
|
+
all = {}
|
|
801
|
+
for k, v in self._dependent_project_variables.items():
|
|
802
|
+
all[k] = v
|
|
803
|
+
for k, v in self._dependent_design_variables.items():
|
|
804
|
+
all[k] = v
|
|
805
|
+
return all
|
|
806
|
+
|
|
807
|
+
@property
|
|
808
|
+
def _all_variables(self): # pragma: no cover
|
|
809
|
+
all = {}
|
|
810
|
+
all.update(self._independent_variables)
|
|
811
|
+
all.update(self._dependent_variables)
|
|
812
|
+
return all
|
|
813
|
+
|
|
814
|
+
@pyedb_function_handler()
|
|
815
|
+
def __delitem__(self, key): # pragma: no cover
|
|
816
|
+
"""Implement del with array name or index."""
|
|
817
|
+
self.delete_variable(key)
|
|
818
|
+
|
|
819
|
+
@pyedb_function_handler()
|
|
820
|
+
def __getitem__(self, variable_name): # pragma: no cover
|
|
821
|
+
return self.variables[variable_name]
|
|
822
|
+
|
|
823
|
+
@pyedb_function_handler()
|
|
824
|
+
def __setitem__(self, variable, value): # pragma: no cover
|
|
825
|
+
self.set_variable(variable, value)
|
|
826
|
+
return True
|
|
827
|
+
|
|
828
|
+
@pyedb_function_handler()
|
|
829
|
+
def _cleanup_variables(self): # pragma: no cover
|
|
830
|
+
variables = self._get_var_list_from_aedt(self._app.odesign) + self._get_var_list_from_aedt(self._app.oproject)
|
|
831
|
+
all_dicts = [
|
|
832
|
+
self._independent_project_variables,
|
|
833
|
+
self._independent_design_variables,
|
|
834
|
+
self._dependent_project_variables,
|
|
835
|
+
self._dependent_design_variables,
|
|
836
|
+
]
|
|
837
|
+
for dict_var in all_dicts:
|
|
838
|
+
for var_name in list(dict_var.keys()):
|
|
839
|
+
if var_name not in variables:
|
|
840
|
+
del dict_var[var_name]
|
|
841
|
+
|
|
842
|
+
@pyedb_function_handler()
|
|
843
|
+
def _variable_dict(self, object_list, dependent=True, independent=True): # pragma: no cover
|
|
844
|
+
"""Retrieve the variable dictionary.
|
|
845
|
+
|
|
846
|
+
Parameters
|
|
847
|
+
----------
|
|
848
|
+
object_list : list
|
|
849
|
+
List of objects.
|
|
850
|
+
dependent : bool, optional
|
|
851
|
+
Whether to include dependent variables. The default is ``True``.
|
|
852
|
+
independent : bool, optional
|
|
853
|
+
Whether to include independent variables. The default is ``True``.
|
|
854
|
+
|
|
855
|
+
Returns
|
|
856
|
+
-------
|
|
857
|
+
dict
|
|
858
|
+
Dictionary of the specified variables.
|
|
859
|
+
|
|
860
|
+
"""
|
|
861
|
+
all_names = {}
|
|
862
|
+
for obj in object_list:
|
|
863
|
+
variables = [i for i in self._get_var_list_from_aedt(obj) if i not in list(self._all_variables.keys())]
|
|
864
|
+
for variable_name in variables:
|
|
865
|
+
variable_expression = self.get_expression(variable_name)
|
|
866
|
+
if variable_expression:
|
|
867
|
+
all_names[variable_name] = variable_expression
|
|
868
|
+
si_value = self._app.get_evaluated_value(variable_name)
|
|
869
|
+
value = Variable(variable_expression, None, si_value, all_names, name=variable_name, app=self._app)
|
|
870
|
+
is_number_flag = is_number(value._calculated_value)
|
|
871
|
+
if variable_name.startswith("$") and is_number_flag:
|
|
872
|
+
self._independent_project_variables[variable_name] = value
|
|
873
|
+
elif variable_name.startswith("$"):
|
|
874
|
+
self._dependent_project_variables[variable_name] = value
|
|
875
|
+
elif is_number_flag:
|
|
876
|
+
self._independent_design_variables[variable_name] = value
|
|
877
|
+
else:
|
|
878
|
+
self._dependent_design_variables[variable_name] = value
|
|
879
|
+
self._cleanup_variables()
|
|
880
|
+
vars_to_output = {}
|
|
881
|
+
dicts_to_add = []
|
|
882
|
+
if independent:
|
|
883
|
+
if self._app.odesign in object_list:
|
|
884
|
+
dicts_to_add.append(self._independent_design_variables)
|
|
885
|
+
if self._app.oproject in object_list:
|
|
886
|
+
dicts_to_add.append(self._independent_project_variables)
|
|
887
|
+
if dependent:
|
|
888
|
+
if self._app.odesign in object_list:
|
|
889
|
+
dicts_to_add.append(self._dependent_design_variables)
|
|
890
|
+
if self._app.oproject in object_list:
|
|
891
|
+
dicts_to_add.append(self._dependent_project_variables)
|
|
892
|
+
for dict_var in dicts_to_add:
|
|
893
|
+
for k, v in dict_var.items():
|
|
894
|
+
vars_to_output[k] = v
|
|
895
|
+
return vars_to_output
|
|
896
|
+
|
|
897
|
+
# TODO: Should be renamed to "evaluate"
|
|
898
|
+
@pyedb_function_handler()
|
|
899
|
+
def get_expression(self, variable_name): # pragma: no cover
|
|
900
|
+
"""Retrieve the variable value of a project or design variable as a string.
|
|
901
|
+
|
|
902
|
+
References
|
|
903
|
+
----------
|
|
904
|
+
|
|
905
|
+
>>> oProject.GetVariableValue
|
|
906
|
+
>>> oDesign.GetVariableValue
|
|
907
|
+
"""
|
|
908
|
+
invalid_names = ["CosimDefinition", "CoSimulator", "CoSimulator/Choices", "InstanceName", "ModelName"]
|
|
909
|
+
if variable_name not in invalid_names:
|
|
910
|
+
try:
|
|
911
|
+
return self.aedt_object(variable_name).GetVariableValue(variable_name)
|
|
912
|
+
except:
|
|
913
|
+
return False
|
|
914
|
+
else:
|
|
915
|
+
return False
|
|
916
|
+
|
|
917
|
+
@pyedb_function_handler()
|
|
918
|
+
def aedt_object(self, variable): # pragma: no cover
|
|
919
|
+
"""Retrieve an AEDT object.
|
|
920
|
+
|
|
921
|
+
Parameters
|
|
922
|
+
----------
|
|
923
|
+
variable : str
|
|
924
|
+
Name of the variable.
|
|
925
|
+
|
|
926
|
+
"""
|
|
927
|
+
if variable[0] == "$":
|
|
928
|
+
return self._oproject
|
|
929
|
+
else:
|
|
930
|
+
return self._odesign
|
|
931
|
+
|
|
932
|
+
@pyedb_function_handler()
|
|
933
|
+
def set_variable(
|
|
934
|
+
self,
|
|
935
|
+
variable_name,
|
|
936
|
+
expression=None,
|
|
937
|
+
readonly=False,
|
|
938
|
+
hidden=False,
|
|
939
|
+
description=None,
|
|
940
|
+
overwrite=True,
|
|
941
|
+
postprocessing=False,
|
|
942
|
+
circuit_parameter=True,
|
|
943
|
+
): # pragma: no cover
|
|
944
|
+
"""Set the value of a design property or project variable.
|
|
945
|
+
|
|
946
|
+
Parameters
|
|
947
|
+
----------
|
|
948
|
+
variable_name : str
|
|
949
|
+
Name of the design property or project variable
|
|
950
|
+
(``$var``). If this variable does not exist, a new one is
|
|
951
|
+
created and a value is set.
|
|
952
|
+
expression : str
|
|
953
|
+
Valid string expression within the AEDT design and project
|
|
954
|
+
structure. For example, ``"3*cos(34deg)"``.
|
|
955
|
+
readonly : bool, optional
|
|
956
|
+
Whether to set the design property or project variable to
|
|
957
|
+
read-only. The default is ``False``.
|
|
958
|
+
hidden : bool, optional
|
|
959
|
+
Whether to hide the design property or project variable. The
|
|
960
|
+
default is ``False``.
|
|
961
|
+
description : str, optional
|
|
962
|
+
Text to display for the design property or project variable in the
|
|
963
|
+
``Properties`` window. The default is ``None``.
|
|
964
|
+
overwrite : bool, optional
|
|
965
|
+
Whether to overwrite an existing value for the design
|
|
966
|
+
property or project variable. The default is ``False``, in
|
|
967
|
+
which case this method is ignored.
|
|
968
|
+
postprocessing : bool, optional
|
|
969
|
+
Whether to define a postprocessing variable.
|
|
970
|
+
The default is ``False``, in which case the variable is not used in postprocessing.
|
|
971
|
+
circuit_parameter : bool, optional
|
|
972
|
+
Whether to define a parameter in a circuit design or a local parameter.
|
|
973
|
+
The default is ``True``, in which case a circuit variable is created as a parameter default.
|
|
974
|
+
|
|
975
|
+
Returns
|
|
976
|
+
-------
|
|
977
|
+
bool
|
|
978
|
+
``True`` when successful, ``False`` when failed.
|
|
979
|
+
|
|
980
|
+
References
|
|
981
|
+
----------
|
|
982
|
+
|
|
983
|
+
>>> oProject.ChangeProperty
|
|
984
|
+
>>> oDesign.ChangeProperty
|
|
985
|
+
|
|
986
|
+
Examples
|
|
987
|
+
--------
|
|
988
|
+
Set the value of design property ``p1`` to ``"10mm"``,
|
|
989
|
+
creating the property if it does not already eixst.
|
|
990
|
+
|
|
991
|
+
>>> aedtapp.variable_manager.set_variable("p1", expression="10mm")
|
|
992
|
+
|
|
993
|
+
Set the value of design property ``p1`` to ``"20mm"`` only if
|
|
994
|
+
the property does not already exist.
|
|
995
|
+
|
|
996
|
+
>>> aedtapp.variable_manager.set_variable("p1", expression="20mm", overwrite=False)
|
|
997
|
+
|
|
998
|
+
Set the value of design property ``p2`` to ``"10mm"``,
|
|
999
|
+
creating the property if it does not already exist. Also make
|
|
1000
|
+
it read-only and hidden and add a description.
|
|
1001
|
+
|
|
1002
|
+
>>> aedtapp.variable_manager.set_variable(variable_name="p2", expression="10mm", readonly=True, hidden=True,
|
|
1003
|
+
... description="This is the description of this variable.")
|
|
1004
|
+
|
|
1005
|
+
Set the value of the project variable ``$p1`` to ``"30mm"``,
|
|
1006
|
+
creating the variable if it does not exist.
|
|
1007
|
+
|
|
1008
|
+
>>> aedtapp.variable_manager.set_variable["$p1"] == "30mm"
|
|
1009
|
+
|
|
1010
|
+
"""
|
|
1011
|
+
if variable_name in self._independent_variables:
|
|
1012
|
+
del self._independent_variables[variable_name]
|
|
1013
|
+
if variable_name in self._independent_design_variables:
|
|
1014
|
+
del self._independent_design_variables[variable_name]
|
|
1015
|
+
elif variable_name in self._independent_project_variables:
|
|
1016
|
+
del self._independent_project_variables[variable_name]
|
|
1017
|
+
elif variable_name in self._dependent_variables:
|
|
1018
|
+
del self._dependent_variables[variable_name]
|
|
1019
|
+
if variable_name in self._dependent_design_variables:
|
|
1020
|
+
del self._dependent_design_variables[variable_name]
|
|
1021
|
+
elif variable_name in self._dependent_project_variables:
|
|
1022
|
+
del self._dependent_project_variables[variable_name]
|
|
1023
|
+
if not description:
|
|
1024
|
+
description = ""
|
|
1025
|
+
|
|
1026
|
+
desktop_object = self.aedt_object(variable_name)
|
|
1027
|
+
if variable_name.startswith("$"):
|
|
1028
|
+
tab_name = "ProjectVariableTab"
|
|
1029
|
+
prop_server = "ProjectVariables"
|
|
1030
|
+
else:
|
|
1031
|
+
tab_name = "LocalVariableTab"
|
|
1032
|
+
prop_server = "LocalVariables"
|
|
1033
|
+
if circuit_parameter and self._app.design_type in [
|
|
1034
|
+
"HFSS 3D Layout Design",
|
|
1035
|
+
"Circuit Design",
|
|
1036
|
+
"Maxwell Circuit",
|
|
1037
|
+
"Twin Builder",
|
|
1038
|
+
]:
|
|
1039
|
+
tab_name = "DefinitionParameterTab"
|
|
1040
|
+
if self._app.design_type in ["HFSS 3D Layout Design", "Circuit Design", "Maxwell Circuit", "Twin Builder"]:
|
|
1041
|
+
prop_server = "Instance:{}".format(desktop_object.GetName())
|
|
1042
|
+
|
|
1043
|
+
prop_type = "VariableProp"
|
|
1044
|
+
if postprocessing or "post" in variable_name.lower()[0:5]:
|
|
1045
|
+
prop_type = "PostProcessingVariableProp"
|
|
1046
|
+
if isinstance(expression, str):
|
|
1047
|
+
# Handle string type variable (including arbitrary expression)# Handle input type variable
|
|
1048
|
+
variable = expression
|
|
1049
|
+
elif isinstance(expression, Variable):
|
|
1050
|
+
# Handle input type variable
|
|
1051
|
+
variable = expression.evaluated_value
|
|
1052
|
+
elif is_number(expression):
|
|
1053
|
+
# Handle input type int/float, etc (including numeric 0)
|
|
1054
|
+
variable = str(expression)
|
|
1055
|
+
# Handle None, "" as Separator
|
|
1056
|
+
elif isinstance(expression, list):
|
|
1057
|
+
variable = str(expression)
|
|
1058
|
+
elif not expression:
|
|
1059
|
+
prop_type = "SeparatorProp"
|
|
1060
|
+
variable = ""
|
|
1061
|
+
try:
|
|
1062
|
+
if self.delete_separator(variable_name):
|
|
1063
|
+
desktop_object.Undo()
|
|
1064
|
+
self._logger.clear_messages()
|
|
1065
|
+
return
|
|
1066
|
+
except:
|
|
1067
|
+
pass
|
|
1068
|
+
else:
|
|
1069
|
+
raise Exception("Unhandled input type to the design property or project variable.") # pragma: no cover
|
|
1070
|
+
|
|
1071
|
+
# Get all design and project variables in lower case for a case-sensitive comparison
|
|
1072
|
+
var_list = self._get_var_list_from_aedt(desktop_object)
|
|
1073
|
+
lower_case_vars = [var_name.lower() for var_name in var_list]
|
|
1074
|
+
|
|
1075
|
+
if variable_name.lower() not in lower_case_vars:
|
|
1076
|
+
try:
|
|
1077
|
+
desktop_object.ChangeProperty(
|
|
1078
|
+
[
|
|
1079
|
+
"NAME:AllTabs",
|
|
1080
|
+
[
|
|
1081
|
+
"NAME:{0}".format(tab_name),
|
|
1082
|
+
["NAME:PropServers", prop_server],
|
|
1083
|
+
[
|
|
1084
|
+
"NAME:NewProps",
|
|
1085
|
+
[
|
|
1086
|
+
"NAME:" + variable_name,
|
|
1087
|
+
"PropType:=",
|
|
1088
|
+
prop_type,
|
|
1089
|
+
"UserDef:=",
|
|
1090
|
+
True,
|
|
1091
|
+
"Value:=",
|
|
1092
|
+
variable,
|
|
1093
|
+
"Description:=",
|
|
1094
|
+
description,
|
|
1095
|
+
"ReadOnly:=",
|
|
1096
|
+
readonly,
|
|
1097
|
+
"Hidden:=",
|
|
1098
|
+
hidden,
|
|
1099
|
+
],
|
|
1100
|
+
],
|
|
1101
|
+
],
|
|
1102
|
+
]
|
|
1103
|
+
)
|
|
1104
|
+
except:
|
|
1105
|
+
if ";" in desktop_object.GetName() and prop_type == "PostProcessingVariableProp":
|
|
1106
|
+
self._logger.info("PostProcessing Variable exists already. Changing value.")
|
|
1107
|
+
desktop_object.ChangeProperty(
|
|
1108
|
+
[
|
|
1109
|
+
"NAME:AllTabs",
|
|
1110
|
+
[
|
|
1111
|
+
"NAME:{}".format(tab_name),
|
|
1112
|
+
["NAME:PropServers", prop_server],
|
|
1113
|
+
[
|
|
1114
|
+
"NAME:ChangedProps",
|
|
1115
|
+
[
|
|
1116
|
+
"NAME:" + variable_name,
|
|
1117
|
+
"Value:=",
|
|
1118
|
+
variable,
|
|
1119
|
+
"Description:=",
|
|
1120
|
+
description,
|
|
1121
|
+
"ReadOnly:=",
|
|
1122
|
+
readonly,
|
|
1123
|
+
"Hidden:=",
|
|
1124
|
+
hidden,
|
|
1125
|
+
],
|
|
1126
|
+
],
|
|
1127
|
+
],
|
|
1128
|
+
]
|
|
1129
|
+
)
|
|
1130
|
+
elif overwrite:
|
|
1131
|
+
desktop_object.ChangeProperty(
|
|
1132
|
+
[
|
|
1133
|
+
"NAME:AllTabs",
|
|
1134
|
+
[
|
|
1135
|
+
"NAME:{}".format(tab_name),
|
|
1136
|
+
["NAME:PropServers", prop_server],
|
|
1137
|
+
[
|
|
1138
|
+
"NAME:ChangedProps",
|
|
1139
|
+
[
|
|
1140
|
+
"NAME:" + variable_name,
|
|
1141
|
+
"Value:=",
|
|
1142
|
+
variable,
|
|
1143
|
+
"Description:=",
|
|
1144
|
+
description,
|
|
1145
|
+
"ReadOnly:=",
|
|
1146
|
+
readonly,
|
|
1147
|
+
"Hidden:=",
|
|
1148
|
+
hidden,
|
|
1149
|
+
],
|
|
1150
|
+
],
|
|
1151
|
+
],
|
|
1152
|
+
]
|
|
1153
|
+
)
|
|
1154
|
+
self._cleanup_variables()
|
|
1155
|
+
var_list = self._get_var_list_from_aedt(desktop_object)
|
|
1156
|
+
lower_case_vars = [var_name.lower() for var_name in var_list]
|
|
1157
|
+
if variable_name.lower() not in lower_case_vars:
|
|
1158
|
+
return False
|
|
1159
|
+
return True
|
|
1160
|
+
|
|
1161
|
+
@pyedb_function_handler()
|
|
1162
|
+
def delete_separator(self, separator_name): # pragma: no cover
|
|
1163
|
+
"""Delete a separator from either the active project or design.
|
|
1164
|
+
|
|
1165
|
+
Parameters
|
|
1166
|
+
----------
|
|
1167
|
+
separator_name : str
|
|
1168
|
+
Value to use for the delimiter.
|
|
1169
|
+
|
|
1170
|
+
Returns
|
|
1171
|
+
-------
|
|
1172
|
+
bool
|
|
1173
|
+
``True`` when the separator exists and can be deleted, ``False`` otherwise.
|
|
1174
|
+
|
|
1175
|
+
References
|
|
1176
|
+
----------
|
|
1177
|
+
|
|
1178
|
+
>>> oProject.ChangeProperty
|
|
1179
|
+
>>> oDesign.ChangeProperty
|
|
1180
|
+
"""
|
|
1181
|
+
object_list = [(self._odesign, "Local"), (self._oproject, "Project")]
|
|
1182
|
+
|
|
1183
|
+
for object_tuple in object_list:
|
|
1184
|
+
desktop_object = object_tuple[0]
|
|
1185
|
+
var_type = object_tuple[1]
|
|
1186
|
+
try:
|
|
1187
|
+
desktop_object.ChangeProperty(
|
|
1188
|
+
[
|
|
1189
|
+
"NAME:AllTabs",
|
|
1190
|
+
[
|
|
1191
|
+
"NAME:{0}VariableTab".format(var_type),
|
|
1192
|
+
["NAME:PropServers", "{0}Variables".format(var_type)],
|
|
1193
|
+
["NAME:DeletedProps", separator_name],
|
|
1194
|
+
],
|
|
1195
|
+
]
|
|
1196
|
+
)
|
|
1197
|
+
return True
|
|
1198
|
+
except:
|
|
1199
|
+
pass
|
|
1200
|
+
return False
|
|
1201
|
+
|
|
1202
|
+
@pyedb_function_handler()
|
|
1203
|
+
def delete_variable(self, var_name): # pragma: no cover
|
|
1204
|
+
"""Delete a variable.
|
|
1205
|
+
|
|
1206
|
+
Parameters
|
|
1207
|
+
----------
|
|
1208
|
+
var_name : str
|
|
1209
|
+
Name of the variable.
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
Returns
|
|
1213
|
+
-------
|
|
1214
|
+
bool
|
|
1215
|
+
``True`` when successful, ``False`` when failed.
|
|
1216
|
+
|
|
1217
|
+
References
|
|
1218
|
+
----------
|
|
1219
|
+
|
|
1220
|
+
>>> oProject.ChangeProperty
|
|
1221
|
+
>>> oDesign.ChangeProperty
|
|
1222
|
+
"""
|
|
1223
|
+
desktop_object = self.aedt_object(var_name)
|
|
1224
|
+
var_type = "Project" if desktop_object == self._oproject else "Local"
|
|
1225
|
+
var_list = self._get_var_list_from_aedt(desktop_object)
|
|
1226
|
+
lower_case_vars = [var_name.lower() for var_name in var_list]
|
|
1227
|
+
if var_name.lower() in lower_case_vars:
|
|
1228
|
+
try:
|
|
1229
|
+
desktop_object.ChangeProperty(
|
|
1230
|
+
[
|
|
1231
|
+
"NAME:AllTabs",
|
|
1232
|
+
[
|
|
1233
|
+
"NAME:{0}VariableTab".format(var_type),
|
|
1234
|
+
["NAME:PropServers", "{0}Variables".format(var_type)],
|
|
1235
|
+
["NAME:DeletedProps", var_name],
|
|
1236
|
+
],
|
|
1237
|
+
]
|
|
1238
|
+
)
|
|
1239
|
+
except: # pragma: no cover
|
|
1240
|
+
pass
|
|
1241
|
+
else:
|
|
1242
|
+
self._cleanup_variables()
|
|
1243
|
+
return True
|
|
1244
|
+
return False
|
|
1245
|
+
|
|
1246
|
+
@pyedb_function_handler()
|
|
1247
|
+
def _get_var_list_from_aedt(self, desktop_object): # pragma: no cover
|
|
1248
|
+
var_list = []
|
|
1249
|
+
if self._app._is_object_oriented_enabled() and self._app.design_type != "Maxwell Circuit":
|
|
1250
|
+
# To retrieve local variables
|
|
1251
|
+
try:
|
|
1252
|
+
v = list(self._app.get_oo_object(self._app.odesign, "LocalVariables").GetPropNames())
|
|
1253
|
+
except AttributeError:
|
|
1254
|
+
v = []
|
|
1255
|
+
var_list += v
|
|
1256
|
+
if self._app._is_object_oriented_enabled() and self._app.design_type in [
|
|
1257
|
+
"Circuit Design",
|
|
1258
|
+
"Twin Builder",
|
|
1259
|
+
"HFSS 3D Layout Design",
|
|
1260
|
+
]:
|
|
1261
|
+
# To retrieve Parameter Default Variables
|
|
1262
|
+
try:
|
|
1263
|
+
v = list(self._app.get_oo_object(self._app.odesign, "DefinitionParameters").GetPropNames())
|
|
1264
|
+
except AttributeError:
|
|
1265
|
+
v = []
|
|
1266
|
+
var_list += v
|
|
1267
|
+
var_list += [i for i in list(desktop_object.GetVariables()) if i not in var_list]
|
|
1268
|
+
var_list += [i for i in list(self._app.oproject.GetArrayVariables()) if i not in var_list]
|
|
1269
|
+
return var_list
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
# TODO: See how we handle this (totally removed / reworked ) ?
|
|
1273
|
+
class Variable(object):
|
|
1274
|
+
"""Stores design properties and project variables and provides operations to perform on them.
|
|
1275
|
+
|
|
1276
|
+
Parameters
|
|
1277
|
+
----------
|
|
1278
|
+
value : float, str
|
|
1279
|
+
Numerical value of the variable in SI units.
|
|
1280
|
+
units : str
|
|
1281
|
+
Units for the value.
|
|
1282
|
+
|
|
1283
|
+
Examples
|
|
1284
|
+
--------
|
|
1285
|
+
|
|
1286
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1287
|
+
|
|
1288
|
+
Define a variable using a string value consistent with the AEDT properties.
|
|
1289
|
+
|
|
1290
|
+
>>> v = Variable("45mm")
|
|
1291
|
+
|
|
1292
|
+
Define an unitless variable with a value of 3.0.
|
|
1293
|
+
|
|
1294
|
+
>>> v = Variable(3.0)
|
|
1295
|
+
|
|
1296
|
+
Define a variable defined by a numeric result and a unit string.
|
|
1297
|
+
|
|
1298
|
+
>>> v = Variable(3.0 * 4.5, units="mm")
|
|
1299
|
+
>>> assert v.numeric_value = 13.5
|
|
1300
|
+
>>> assert v.units = "mm"
|
|
1301
|
+
|
|
1302
|
+
"""
|
|
1303
|
+
|
|
1304
|
+
def __init__(
|
|
1305
|
+
self,
|
|
1306
|
+
expression,
|
|
1307
|
+
units=None,
|
|
1308
|
+
si_value=None,
|
|
1309
|
+
full_variables=None,
|
|
1310
|
+
name=None,
|
|
1311
|
+
app=None,
|
|
1312
|
+
readonly=False,
|
|
1313
|
+
hidden=False,
|
|
1314
|
+
description=None,
|
|
1315
|
+
postprocessing=False,
|
|
1316
|
+
circuit_parameter=True,
|
|
1317
|
+
): # pragma: no cover
|
|
1318
|
+
if not full_variables:
|
|
1319
|
+
full_variables = {}
|
|
1320
|
+
self._variable_name = name
|
|
1321
|
+
self._app = app
|
|
1322
|
+
self._readonly = readonly
|
|
1323
|
+
self._hidden = hidden
|
|
1324
|
+
self._postprocessing = postprocessing
|
|
1325
|
+
self._circuit_parameter = circuit_parameter
|
|
1326
|
+
self._description = description
|
|
1327
|
+
self._is_optimization_included = None
|
|
1328
|
+
if units:
|
|
1329
|
+
if unit_system(units):
|
|
1330
|
+
specified_units = units
|
|
1331
|
+
self._units = None
|
|
1332
|
+
self._expression = expression
|
|
1333
|
+
self._calculated_value, self._units = decompose_variable_value(expression, full_variables)
|
|
1334
|
+
if si_value:
|
|
1335
|
+
self._value = si_value
|
|
1336
|
+
else:
|
|
1337
|
+
self._value = self._calculated_value
|
|
1338
|
+
# If units have been specified, check for a conflict and otherwise use the specified unit system
|
|
1339
|
+
if units:
|
|
1340
|
+
assert not self._units, "The unit specification {} is inconsistent with the identified units {}.".format(
|
|
1341
|
+
specified_units, self._units
|
|
1342
|
+
)
|
|
1343
|
+
self._units = specified_units
|
|
1344
|
+
|
|
1345
|
+
if not si_value and is_number(self._value):
|
|
1346
|
+
try:
|
|
1347
|
+
scale = AEDT_UNITS[self.unit_system][self._units]
|
|
1348
|
+
except KeyError:
|
|
1349
|
+
scale = 1
|
|
1350
|
+
if isinstance(scale, tuple):
|
|
1351
|
+
self._value = scale[0](self._value, inverse=False)
|
|
1352
|
+
elif isinstance(scale, types.FunctionType):
|
|
1353
|
+
self._value = scale(self._value, False)
|
|
1354
|
+
else:
|
|
1355
|
+
self._value = self._value * scale
|
|
1356
|
+
|
|
1357
|
+
@property
|
|
1358
|
+
def _aedt_obj(self): # pragma: no cover
|
|
1359
|
+
if "$" in self._variable_name and self._app:
|
|
1360
|
+
return self._app._oproject
|
|
1361
|
+
elif self._app:
|
|
1362
|
+
return self._app._odesign
|
|
1363
|
+
return None
|
|
1364
|
+
|
|
1365
|
+
@pyedb_function_handler()
|
|
1366
|
+
def _update_var(self): # pragma: no cover
|
|
1367
|
+
if self._app:
|
|
1368
|
+
return self._app.variable_manager.set_variable(
|
|
1369
|
+
self._variable_name,
|
|
1370
|
+
self._expression,
|
|
1371
|
+
readonly=self._readonly,
|
|
1372
|
+
postprocessing=self._postprocessing,
|
|
1373
|
+
circuit_parameter=self._circuit_parameter,
|
|
1374
|
+
description=self._description,
|
|
1375
|
+
hidden=self._hidden,
|
|
1376
|
+
)
|
|
1377
|
+
return False
|
|
1378
|
+
|
|
1379
|
+
@pyedb_function_handler()
|
|
1380
|
+
def _set_prop_val(self, prop, val, n_times=10): # pragma: no cover
|
|
1381
|
+
if self._app.design_type == "Maxwell Circuit":
|
|
1382
|
+
return
|
|
1383
|
+
try:
|
|
1384
|
+
name = "Variables"
|
|
1385
|
+
|
|
1386
|
+
if self._app.design_type in [
|
|
1387
|
+
"Circuit Design",
|
|
1388
|
+
"Twin Builder",
|
|
1389
|
+
"HFSS 3D Layout Design",
|
|
1390
|
+
]:
|
|
1391
|
+
if self._variable_name in list(
|
|
1392
|
+
self._app.get_oo_object(self._app.odesign, "DefinitionParameters").GetPropNames()
|
|
1393
|
+
):
|
|
1394
|
+
name = "DefinitionParameters"
|
|
1395
|
+
else:
|
|
1396
|
+
name = "LocalVariables"
|
|
1397
|
+
i = 0
|
|
1398
|
+
while i < n_times:
|
|
1399
|
+
if name == "DefinitionParameters":
|
|
1400
|
+
result = self._app.get_oo_object(self._aedt_obj, name).SetPropValue(prop, val)
|
|
1401
|
+
else:
|
|
1402
|
+
result = self._app.get_oo_object(
|
|
1403
|
+
self._aedt_obj, "{}/{}".format(name, self._variable_name)
|
|
1404
|
+
).SetPropValue(prop, val)
|
|
1405
|
+
if result:
|
|
1406
|
+
break
|
|
1407
|
+
i += 1
|
|
1408
|
+
except:
|
|
1409
|
+
pass
|
|
1410
|
+
|
|
1411
|
+
@pyedb_function_handler()
|
|
1412
|
+
def _get_prop_val(self, prop): # pragma: no cover
|
|
1413
|
+
if self._app.design_type == "Maxwell Circuit":
|
|
1414
|
+
return
|
|
1415
|
+
try:
|
|
1416
|
+
name = "Variables"
|
|
1417
|
+
|
|
1418
|
+
if self._app.design_type in [
|
|
1419
|
+
"Circuit Design",
|
|
1420
|
+
"Twin Builder",
|
|
1421
|
+
"HFSS 3D Layout Design",
|
|
1422
|
+
]:
|
|
1423
|
+
if self._variable_name in list(
|
|
1424
|
+
self._app.get_oo_object(self._app.odesign, "DefinitionParameters").GetPropNames()
|
|
1425
|
+
):
|
|
1426
|
+
return self._app.get_oo_object(self._aedt_obj, "DefinitionParameters").GetPropValue(prop)
|
|
1427
|
+
else:
|
|
1428
|
+
name = "LocalVariables"
|
|
1429
|
+
return self._app.get_oo_object(self._aedt_obj, "{}/{}".format(name, self._variable_name)).GetPropValue(prop)
|
|
1430
|
+
except:
|
|
1431
|
+
pass
|
|
1432
|
+
|
|
1433
|
+
@property
|
|
1434
|
+
def name(self): # pragma: no cover
|
|
1435
|
+
"""Variable name."""
|
|
1436
|
+
return self._variable_name
|
|
1437
|
+
|
|
1438
|
+
@name.setter
|
|
1439
|
+
def name(self, value): # pragma: no cover
|
|
1440
|
+
fallback_val = self._variable_name
|
|
1441
|
+
self._variable_name = value
|
|
1442
|
+
if not self._update_var():
|
|
1443
|
+
self._variable_name = fallback_val
|
|
1444
|
+
if self._app:
|
|
1445
|
+
self._app.logger.error('"Failed to update property "name".')
|
|
1446
|
+
|
|
1447
|
+
@property
|
|
1448
|
+
def is_optimization_enabled(self): # pragma: no cover
|
|
1449
|
+
""" "Check if optimization is enabled."""
|
|
1450
|
+
return self._get_prop_val("Optimization/Included")
|
|
1451
|
+
|
|
1452
|
+
@is_optimization_enabled.setter
|
|
1453
|
+
def is_optimization_enabled(self, value): # pragma: no cover
|
|
1454
|
+
self._set_prop_val("Optimization/Included", value, 10)
|
|
1455
|
+
|
|
1456
|
+
@property
|
|
1457
|
+
def optimization_min_value(self): # pragma: no cover
|
|
1458
|
+
""" "Optimization min value."""
|
|
1459
|
+
return self._get_prop_val("Optimization/Min")
|
|
1460
|
+
|
|
1461
|
+
@optimization_min_value.setter
|
|
1462
|
+
def optimization_min_value(self, value): # pragma: no cover
|
|
1463
|
+
self._set_prop_val("Optimization/Min", value, 10)
|
|
1464
|
+
|
|
1465
|
+
@property
|
|
1466
|
+
def optimization_max_value(self): # pragma: no cover
|
|
1467
|
+
""" "Optimization max value."""
|
|
1468
|
+
return self._get_prop_val("Optimization/Max")
|
|
1469
|
+
|
|
1470
|
+
@optimization_max_value.setter
|
|
1471
|
+
def optimization_max_value(self, value): # pragma: no cover
|
|
1472
|
+
self._set_prop_val("Optimization/Max", value, 10)
|
|
1473
|
+
|
|
1474
|
+
@property
|
|
1475
|
+
def is_sensitivity_enabled(self): # pragma: no cover
|
|
1476
|
+
"""Check if Sensitivity is enabled."""
|
|
1477
|
+
return self._get_prop_val("Sensitivity/Included")
|
|
1478
|
+
|
|
1479
|
+
@is_sensitivity_enabled.setter
|
|
1480
|
+
def is_sensitivity_enabled(self, value): # pragma: no cover
|
|
1481
|
+
self._set_prop_val("Sensitivity/Included", value, 10)
|
|
1482
|
+
|
|
1483
|
+
@property
|
|
1484
|
+
def sensitivity_min_value(self): # pragma: no cover
|
|
1485
|
+
""" "Sensitivity min value."""
|
|
1486
|
+
return self._get_prop_val("Sensitivity/Min")
|
|
1487
|
+
|
|
1488
|
+
@sensitivity_min_value.setter
|
|
1489
|
+
def sensitivity_min_value(self, value): # pragma: no cover
|
|
1490
|
+
self._set_prop_val("Sensitivity/Min", value, 10)
|
|
1491
|
+
|
|
1492
|
+
@property
|
|
1493
|
+
def sensitivity_max_value(self): # pragma: no cover
|
|
1494
|
+
""" "Sensitivity max value."""
|
|
1495
|
+
return self._get_prop_val("Sensitivity/Max")
|
|
1496
|
+
|
|
1497
|
+
@sensitivity_max_value.setter
|
|
1498
|
+
def sensitivity_max_value(self, value): # pragma: no cover
|
|
1499
|
+
self._set_prop_val("Sensitivity/Max", value, 10)
|
|
1500
|
+
|
|
1501
|
+
@property
|
|
1502
|
+
def sensitivity_initial_disp(self): # pragma: no cover
|
|
1503
|
+
""" "Sensitivity initial value."""
|
|
1504
|
+
return self._get_prop_val("Sensitivity/IDisp")
|
|
1505
|
+
|
|
1506
|
+
@sensitivity_initial_disp.setter
|
|
1507
|
+
def sensitivity_initial_disp(self, value): # pragma: no cover
|
|
1508
|
+
self._set_prop_val("Sensitivity/IDisp", value, 10)
|
|
1509
|
+
|
|
1510
|
+
@property
|
|
1511
|
+
def is_tuning_enabled(self): # pragma: no cover
|
|
1512
|
+
"""Check if tuning is enabled."""
|
|
1513
|
+
return self._get_prop_val("Tuning/Included")
|
|
1514
|
+
|
|
1515
|
+
@is_tuning_enabled.setter
|
|
1516
|
+
def is_tuning_enabled(self, value): # pragma: no cover
|
|
1517
|
+
self._set_prop_val("Tuning/Included", value, 10)
|
|
1518
|
+
|
|
1519
|
+
@property
|
|
1520
|
+
def tuning_min_value(self): # pragma: no cover
|
|
1521
|
+
""" "Tuning min value."""
|
|
1522
|
+
return self._get_prop_val("Tuning/Min")
|
|
1523
|
+
|
|
1524
|
+
@tuning_min_value.setter
|
|
1525
|
+
def tuning_min_value(self, value): # pragma: no cover
|
|
1526
|
+
self._set_prop_val("Tuning/Min", value, 10)
|
|
1527
|
+
|
|
1528
|
+
@property
|
|
1529
|
+
def tuning_max_value(self): # pragma: no cover
|
|
1530
|
+
""" "Tuning max value."""
|
|
1531
|
+
return self._get_prop_val("Tuning/Max")
|
|
1532
|
+
|
|
1533
|
+
@tuning_max_value.setter
|
|
1534
|
+
def tuning_max_value(self, value): # pragma: no cover
|
|
1535
|
+
self._set_prop_val("Tuning/Max", value, 10)
|
|
1536
|
+
|
|
1537
|
+
@property
|
|
1538
|
+
def tuning_step_value(self): # pragma: no cover
|
|
1539
|
+
""" "Tuning Step value."""
|
|
1540
|
+
return self._get_prop_val("Tuning/Step")
|
|
1541
|
+
|
|
1542
|
+
@tuning_step_value.setter
|
|
1543
|
+
def tuning_step_value(self, value): # pragma: no cover
|
|
1544
|
+
self._set_prop_val("Tuning/Step", value, 10)
|
|
1545
|
+
|
|
1546
|
+
@property
|
|
1547
|
+
def is_statistical_enabled(self): # pragma: no cover
|
|
1548
|
+
"""Check if statistical is enabled."""
|
|
1549
|
+
return self._get_prop_val("Statistical/Included")
|
|
1550
|
+
|
|
1551
|
+
@is_statistical_enabled.setter
|
|
1552
|
+
def is_statistical_enabled(self, value): # pragma: no cover
|
|
1553
|
+
self._set_prop_val("Statistical/Included", value, 10)
|
|
1554
|
+
|
|
1555
|
+
@property
|
|
1556
|
+
def read_only(self): # pragma: no cover
|
|
1557
|
+
"""Read-only flag value."""
|
|
1558
|
+
self._readonly = self._get_prop_val("ReadOnly")
|
|
1559
|
+
return self._readonly
|
|
1560
|
+
|
|
1561
|
+
@read_only.setter
|
|
1562
|
+
def read_only(self, value): # pragma: no cover
|
|
1563
|
+
fallback_val = self._readonly
|
|
1564
|
+
self._readonly = value
|
|
1565
|
+
if not self._update_var():
|
|
1566
|
+
self._readonly = fallback_val
|
|
1567
|
+
if self._app:
|
|
1568
|
+
self._app.logger.error('Failed to update property "read_only".')
|
|
1569
|
+
|
|
1570
|
+
@property
|
|
1571
|
+
def hidden(self): # pragma: no cover
|
|
1572
|
+
"""Hidden flag value."""
|
|
1573
|
+
self._hidden = self._get_prop_val("Hidden")
|
|
1574
|
+
return self._hidden
|
|
1575
|
+
|
|
1576
|
+
@hidden.setter
|
|
1577
|
+
def hidden(self, value): # pragma: no cover
|
|
1578
|
+
fallback_val = self._hidden
|
|
1579
|
+
self._hidden = value
|
|
1580
|
+
if not self._update_var():
|
|
1581
|
+
self._hidden = fallback_val
|
|
1582
|
+
if self._app:
|
|
1583
|
+
self._app.logger.error('Failed to update property "hidden".')
|
|
1584
|
+
|
|
1585
|
+
@property
|
|
1586
|
+
def description(self): # pragma: no cover
|
|
1587
|
+
"""Description value."""
|
|
1588
|
+
self._description = self._get_prop_val("Description")
|
|
1589
|
+
return self._description
|
|
1590
|
+
|
|
1591
|
+
@description.setter
|
|
1592
|
+
def description(self, value): # pragma: no cover
|
|
1593
|
+
fallback_val = self._description
|
|
1594
|
+
self._description = value
|
|
1595
|
+
if not self._update_var():
|
|
1596
|
+
self._description = fallback_val
|
|
1597
|
+
if self._app:
|
|
1598
|
+
self._app.logger.error('Failed to update property "description".')
|
|
1599
|
+
|
|
1600
|
+
@property
|
|
1601
|
+
def post_processing(self): # pragma: no cover
|
|
1602
|
+
"""Postprocessing flag value."""
|
|
1603
|
+
if self._app:
|
|
1604
|
+
return True if self._variable_name in self._app.variable_manager.post_processing_variables else False
|
|
1605
|
+
|
|
1606
|
+
@property
|
|
1607
|
+
def circuit_parameter(self): # pragma: no cover
|
|
1608
|
+
"""Circuit parameter flag value."""
|
|
1609
|
+
if "$" in self._variable_name:
|
|
1610
|
+
return False
|
|
1611
|
+
if self._app.design_type in ["HFSS 3D Layout Design", "Circuit Design", "Maxwell Circuit", "Twin Builder"]:
|
|
1612
|
+
prop_server = "Instance:{}".format(self._aedt_obj.GetName())
|
|
1613
|
+
return (
|
|
1614
|
+
True
|
|
1615
|
+
if self._variable_name in self._aedt_obj.GetProperties("DefinitionParameterTab", prop_server)
|
|
1616
|
+
else False
|
|
1617
|
+
)
|
|
1618
|
+
return False
|
|
1619
|
+
|
|
1620
|
+
@property
|
|
1621
|
+
def expression(self): # pragma: no cover
|
|
1622
|
+
"""Expression."""
|
|
1623
|
+
if self._aedt_obj:
|
|
1624
|
+
return self._aedt_obj.GetVariableValue(self._variable_name)
|
|
1625
|
+
return
|
|
1626
|
+
|
|
1627
|
+
@expression.setter
|
|
1628
|
+
def expression(self, value): # pragma: no cover
|
|
1629
|
+
fallback_val = self._expression
|
|
1630
|
+
self._expression = value
|
|
1631
|
+
if not self._update_var():
|
|
1632
|
+
self._expression = fallback_val
|
|
1633
|
+
if self._app:
|
|
1634
|
+
self._app.logger.error("Failed to update property Expression.")
|
|
1635
|
+
|
|
1636
|
+
@property
|
|
1637
|
+
def numeric_value(self): # pragma: no cover
|
|
1638
|
+
"""Numeric part of the expression as a float value."""
|
|
1639
|
+
if is_array(self._value):
|
|
1640
|
+
return list(eval(self._value))
|
|
1641
|
+
try:
|
|
1642
|
+
var_obj = self._aedt_obj.GetChildObject("Variables").GetChildObject(self._variable_name)
|
|
1643
|
+
val, _ = decompose_variable_value(var_obj.GetPropEvaluatedValue("EvaluatedValue"))
|
|
1644
|
+
return val
|
|
1645
|
+
except (TypeError, AttributeError):
|
|
1646
|
+
if is_number(self._value):
|
|
1647
|
+
try:
|
|
1648
|
+
scale = AEDT_UNITS[self.unit_system][self._units]
|
|
1649
|
+
except KeyError:
|
|
1650
|
+
scale = 1
|
|
1651
|
+
if isinstance(scale, tuple):
|
|
1652
|
+
return scale[0](self._value, True)
|
|
1653
|
+
elif isinstance(scale, types.FunctionType):
|
|
1654
|
+
return scale(self._value, True)
|
|
1655
|
+
else:
|
|
1656
|
+
return self._value / scale
|
|
1657
|
+
else: # pragma: no cover
|
|
1658
|
+
return self._value
|
|
1659
|
+
|
|
1660
|
+
@property
|
|
1661
|
+
def unit_system(self): # pragma: no cover
|
|
1662
|
+
"""Unit system of the expression as a string."""
|
|
1663
|
+
return unit_system(self._units)
|
|
1664
|
+
|
|
1665
|
+
@property
|
|
1666
|
+
def units(self): # pragma: no cover
|
|
1667
|
+
"""Units."""
|
|
1668
|
+
try:
|
|
1669
|
+
var_obj = self._aedt_obj.GetChildObject("Variables").GetChildObject(self._variable_name)
|
|
1670
|
+
_, self._units = decompose_variable_value(var_obj.GetPropEvaluatedValue("EvaluatedValue"))
|
|
1671
|
+
return self._units
|
|
1672
|
+
except (TypeError, AttributeError, GrpcApiError):
|
|
1673
|
+
pass
|
|
1674
|
+
return self._units
|
|
1675
|
+
|
|
1676
|
+
@property
|
|
1677
|
+
def value(self): # pragma: no cover
|
|
1678
|
+
"""Value."""
|
|
1679
|
+
|
|
1680
|
+
return self._value
|
|
1681
|
+
|
|
1682
|
+
@property
|
|
1683
|
+
def evaluated_value(self): # pragma: no cover
|
|
1684
|
+
"""String value.
|
|
1685
|
+
|
|
1686
|
+
The numeric value with the unit is concatenated and returned as a string. The numeric display
|
|
1687
|
+
in the modeler and the string value can differ. For example, you might see ``10mm`` in the
|
|
1688
|
+
modeler and see ``10.0mm`` returned as the string value.
|
|
1689
|
+
|
|
1690
|
+
"""
|
|
1691
|
+
return ("{}{}").format(self.numeric_value, self._units)
|
|
1692
|
+
|
|
1693
|
+
@pyedb_function_handler()
|
|
1694
|
+
def decompose(self): # pragma: no cover
|
|
1695
|
+
"""Decompose a variable value to a floating with its unit.
|
|
1696
|
+
|
|
1697
|
+
Returns
|
|
1698
|
+
-------
|
|
1699
|
+
tuple
|
|
1700
|
+
The float value of the variable and the units exposed as a string.
|
|
1701
|
+
|
|
1702
|
+
Examples
|
|
1703
|
+
--------
|
|
1704
|
+
>>> hfss = Hfss()
|
|
1705
|
+
>>> hfss["v1"] = "3N"
|
|
1706
|
+
>>> print(hfss.variable_manager["v1"].decompose("v1"))
|
|
1707
|
+
>>> (3.0, 'N')
|
|
1708
|
+
|
|
1709
|
+
"""
|
|
1710
|
+
return decompose_variable_value(self.evaluated_value)
|
|
1711
|
+
|
|
1712
|
+
@pyedb_function_handler()
|
|
1713
|
+
def rescale_to(self, units): # pragma: no cover
|
|
1714
|
+
"""Rescale the expression to a new unit within the current unit system.
|
|
1715
|
+
|
|
1716
|
+
Parameters
|
|
1717
|
+
----------
|
|
1718
|
+
units : str
|
|
1719
|
+
Units to rescale to.
|
|
1720
|
+
|
|
1721
|
+
Examples
|
|
1722
|
+
--------
|
|
1723
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1724
|
+
|
|
1725
|
+
>>> v = Variable("10W")
|
|
1726
|
+
>>> assert v.numeric_value == 10
|
|
1727
|
+
>>> assert v.units == "W"
|
|
1728
|
+
>>> v.rescale_to("kW")
|
|
1729
|
+
>>> assert v.numeric_value == 0.01
|
|
1730
|
+
>>> assert v.units == "kW"
|
|
1731
|
+
|
|
1732
|
+
"""
|
|
1733
|
+
new_unit_system = unit_system(units)
|
|
1734
|
+
assert (
|
|
1735
|
+
new_unit_system == self.unit_system
|
|
1736
|
+
), "New unit system {0} is inconsistent with the current unit system {1}."
|
|
1737
|
+
self._units = units
|
|
1738
|
+
return self
|
|
1739
|
+
|
|
1740
|
+
@pyedb_function_handler()
|
|
1741
|
+
def format(self, format): # pragma: no cover
|
|
1742
|
+
"""Retrieve the string value with the specified numerical formatting.
|
|
1743
|
+
|
|
1744
|
+
Parameters
|
|
1745
|
+
----------
|
|
1746
|
+
format : str
|
|
1747
|
+
Format for the numeric value of the string. For example, ``'06.2f'``. For
|
|
1748
|
+
more information, see the `PyFormat documentation <https://pyformat.info/>`_.
|
|
1749
|
+
|
|
1750
|
+
Returns
|
|
1751
|
+
-------
|
|
1752
|
+
str
|
|
1753
|
+
String value with the specified numerical formatting.
|
|
1754
|
+
|
|
1755
|
+
Examples
|
|
1756
|
+
--------
|
|
1757
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1758
|
+
|
|
1759
|
+
>>> v = Variable("10W")
|
|
1760
|
+
>>> assert v.format("f") == '10.000000W'
|
|
1761
|
+
>>> assert v.format("06.2f") == '010.00W'
|
|
1762
|
+
>>> assert v.format("6.2f") == ' 10.00W'
|
|
1763
|
+
|
|
1764
|
+
"""
|
|
1765
|
+
return ("{0:" + format + "}{1}").format(self.numeric_value, self._units)
|
|
1766
|
+
|
|
1767
|
+
@pyedb_function_handler()
|
|
1768
|
+
def __mul__(self, other): # pragma: no cover
|
|
1769
|
+
"""Multiply the variable with a number or another variable and return a new object.
|
|
1770
|
+
|
|
1771
|
+
Parameters
|
|
1772
|
+
----------
|
|
1773
|
+
other : numbers.Number or variable
|
|
1774
|
+
Object to be multiplied.
|
|
1775
|
+
|
|
1776
|
+
Returns
|
|
1777
|
+
-------
|
|
1778
|
+
type
|
|
1779
|
+
Variable.
|
|
1780
|
+
|
|
1781
|
+
Examples
|
|
1782
|
+
--------
|
|
1783
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1784
|
+
|
|
1785
|
+
Multiply ``'Length1'`` by unitless ``'None'``` to obtain ``'Length'``.
|
|
1786
|
+
A numerical value is also considered to be unitless.
|
|
1787
|
+
|
|
1788
|
+
import pyaedt.generic.constants >>> v1 = Variable("10mm")
|
|
1789
|
+
>>> v2 = Variable(3)
|
|
1790
|
+
>>> result_1 = v1 * v2
|
|
1791
|
+
>>> result_2 = v1 * 3
|
|
1792
|
+
>>> assert result_1.numeric_value == 30.0
|
|
1793
|
+
>>> assert result_1.unit_system == "Length"
|
|
1794
|
+
>>> assert result_2.numeric_value == result_1.numeric_value
|
|
1795
|
+
>>> assert result_2.unit_system == "Length"
|
|
1796
|
+
|
|
1797
|
+
Multiply voltage times current to obtain power.
|
|
1798
|
+
|
|
1799
|
+
import pyaedt.generic.constants >>> v3 = Variable("3mA")
|
|
1800
|
+
>>> v4 = Variable("40V")
|
|
1801
|
+
>>> result_3 = v3 * v4
|
|
1802
|
+
>>> assert result_3.numeric_value == 0.12
|
|
1803
|
+
>>> assert result_3.units == "W"
|
|
1804
|
+
>>> assert result_3.unit_system == "Power"
|
|
1805
|
+
|
|
1806
|
+
"""
|
|
1807
|
+
assert is_number(other) or isinstance(other, Variable), "Multiplier must be a scalar quantity or a variable."
|
|
1808
|
+
if is_number(other):
|
|
1809
|
+
result_value = self.numeric_value * other
|
|
1810
|
+
result_units = self.units
|
|
1811
|
+
else:
|
|
1812
|
+
if self.unit_system == "None":
|
|
1813
|
+
return self.numeric_value * other
|
|
1814
|
+
elif other.unit_system == "None":
|
|
1815
|
+
return other.numeric_value * self
|
|
1816
|
+
else:
|
|
1817
|
+
result_value = self.value * other.value
|
|
1818
|
+
result_units = _resolve_unit_system(self.unit_system, other.unit_system, "multiply")
|
|
1819
|
+
if not result_units:
|
|
1820
|
+
result_units = _resolve_unit_system(other.unit_system, self.unit_system, "multiply")
|
|
1821
|
+
|
|
1822
|
+
return Variable("{}{}".format(result_value, result_units))
|
|
1823
|
+
|
|
1824
|
+
__rmul__ = __mul__
|
|
1825
|
+
|
|
1826
|
+
@pyedb_function_handler()
|
|
1827
|
+
def __add__(self, other): # pragma: no cover
|
|
1828
|
+
"""Add the variable to another variable to return a new object.
|
|
1829
|
+
|
|
1830
|
+
Parameters
|
|
1831
|
+
----------
|
|
1832
|
+
other : class:`pyedb.dotnet.application.Variables.Variable`
|
|
1833
|
+
Object to be multiplied.
|
|
1834
|
+
|
|
1835
|
+
Returns
|
|
1836
|
+
-------
|
|
1837
|
+
type
|
|
1838
|
+
Variable.
|
|
1839
|
+
|
|
1840
|
+
Examples
|
|
1841
|
+
--------
|
|
1842
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1843
|
+
>>> import pyaedt.generic.constants
|
|
1844
|
+
>>> v1 = Variable("3mA")
|
|
1845
|
+
>>> v2 = Variable("10A")
|
|
1846
|
+
>>> result = v1 + v2
|
|
1847
|
+
>>> assert result.numeric_value == 10.003
|
|
1848
|
+
>>> assert result.units == "A"
|
|
1849
|
+
>>> assert result.unit_system == "Current"
|
|
1850
|
+
|
|
1851
|
+
"""
|
|
1852
|
+
assert isinstance(other, Variable), "You can only add a variable with another variable."
|
|
1853
|
+
assert (
|
|
1854
|
+
self.unit_system == other.unit_system
|
|
1855
|
+
), "Only ``Variable`` objects with the same unit system can be added."
|
|
1856
|
+
result_value = self.value + other.value
|
|
1857
|
+
result_units = SI_UNITS[self.unit_system]
|
|
1858
|
+
# If the units of the two operands are different, return SI-Units
|
|
1859
|
+
result_variable = Variable("{}{}".format(result_value, result_units))
|
|
1860
|
+
|
|
1861
|
+
# If the units of both operands are the same, return those units
|
|
1862
|
+
if self.units == other.units:
|
|
1863
|
+
result_variable.rescale_to(self.units)
|
|
1864
|
+
|
|
1865
|
+
return result_variable
|
|
1866
|
+
|
|
1867
|
+
@pyedb_function_handler()
|
|
1868
|
+
def __sub__(self, other): # pragma: no cover
|
|
1869
|
+
"""Subtract another variable from the variable to return a new object.
|
|
1870
|
+
|
|
1871
|
+
Parameters
|
|
1872
|
+
----------
|
|
1873
|
+
other : class:`pyedb.dotnet.application.Variables.Variable`
|
|
1874
|
+
Object to be subtracted.
|
|
1875
|
+
|
|
1876
|
+
Returns
|
|
1877
|
+
-------
|
|
1878
|
+
type
|
|
1879
|
+
Variable.
|
|
1880
|
+
|
|
1881
|
+
Examples
|
|
1882
|
+
--------
|
|
1883
|
+
|
|
1884
|
+
>>> import pyaedt.generic.constants
|
|
1885
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1886
|
+
>>> v3 = Variable("3mA")
|
|
1887
|
+
>>> v4 = Variable("10A")
|
|
1888
|
+
>>> result_2 = v3 - v4
|
|
1889
|
+
>>> assert result_2.numeric_value == -9.997
|
|
1890
|
+
>>> assert result_2.units == "A"
|
|
1891
|
+
>>> assert result_2.unit_system == "Current"
|
|
1892
|
+
|
|
1893
|
+
"""
|
|
1894
|
+
assert isinstance(other, Variable), "You can only subtract a variable from another variable."
|
|
1895
|
+
assert (
|
|
1896
|
+
self.unit_system == other.unit_system
|
|
1897
|
+
), "Only ``Variable`` objects with the same unit system can be subtracted."
|
|
1898
|
+
result_value = self.value - other.value
|
|
1899
|
+
result_units = SI_UNITS[self.unit_system]
|
|
1900
|
+
# If the units of the two operands are different, return SI-Units
|
|
1901
|
+
result_variable = Variable("{}{}".format(result_value, result_units))
|
|
1902
|
+
|
|
1903
|
+
# If the units of both operands are the same, return those units
|
|
1904
|
+
if self.units == other.units:
|
|
1905
|
+
result_variable.rescale_to(self.units)
|
|
1906
|
+
|
|
1907
|
+
return result_variable
|
|
1908
|
+
|
|
1909
|
+
# Python 3.x version
|
|
1910
|
+
@pyedb_function_handler()
|
|
1911
|
+
def __truediv__(self, other): # pragma: no cover
|
|
1912
|
+
"""Divide the variable by a number or another variable to return a new object.
|
|
1913
|
+
|
|
1914
|
+
Parameters
|
|
1915
|
+
----------
|
|
1916
|
+
other : numbers.Number or variable
|
|
1917
|
+
Object by which to divide.
|
|
1918
|
+
|
|
1919
|
+
Returns
|
|
1920
|
+
-------
|
|
1921
|
+
type
|
|
1922
|
+
Variable.
|
|
1923
|
+
|
|
1924
|
+
Examples
|
|
1925
|
+
--------
|
|
1926
|
+
Divide a variable with units ``"W"`` by a variable with units ``"V"`` and automatically
|
|
1927
|
+
resolve the new units to ``"A"``.
|
|
1928
|
+
|
|
1929
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1930
|
+
>>> import pyaedt.generic.constants
|
|
1931
|
+
>>> v1 = Variable("10W")
|
|
1932
|
+
>>> v2 = Variable("40V")
|
|
1933
|
+
>>> result = v1 / v2
|
|
1934
|
+
>>> assert result_1.numeric_value == 0.25
|
|
1935
|
+
>>> assert result_1.units == "A"
|
|
1936
|
+
>>> assert result_1.unit_system == "Current"
|
|
1937
|
+
|
|
1938
|
+
"""
|
|
1939
|
+
assert is_number(other) or isinstance(other, Variable), "Divisor must be a scalar quantity or a variable."
|
|
1940
|
+
if is_number(other):
|
|
1941
|
+
result_value = self.numeric_value / other
|
|
1942
|
+
result_units = self.units
|
|
1943
|
+
else:
|
|
1944
|
+
result_value = self.value / other.value
|
|
1945
|
+
result_units = _resolve_unit_system(self.unit_system, other.unit_system, "divide")
|
|
1946
|
+
|
|
1947
|
+
return Variable("{}{}".format(result_value, result_units))
|
|
1948
|
+
|
|
1949
|
+
# Python 2.7 version
|
|
1950
|
+
@pyedb_function_handler()
|
|
1951
|
+
def __div__(self, other): # pragma: no cover
|
|
1952
|
+
return self.__truediv__(other)
|
|
1953
|
+
|
|
1954
|
+
@pyedb_function_handler()
|
|
1955
|
+
def __rtruediv__(self, other): # pragma: no cover
|
|
1956
|
+
"""Divide another object by this object.
|
|
1957
|
+
|
|
1958
|
+
Parameters
|
|
1959
|
+
----------
|
|
1960
|
+
other : numbers.Number or variable
|
|
1961
|
+
Object to divide by.
|
|
1962
|
+
|
|
1963
|
+
Returns
|
|
1964
|
+
-------
|
|
1965
|
+
type
|
|
1966
|
+
Variable.
|
|
1967
|
+
|
|
1968
|
+
Examples
|
|
1969
|
+
--------
|
|
1970
|
+
Divide a number by a variable with units ``"s"`` and automatically determine that
|
|
1971
|
+
the result is in ``"Hz"``.
|
|
1972
|
+
|
|
1973
|
+
>>> import pyaedt.generic.constants
|
|
1974
|
+
>>> from pyedb.dotnet.application.Variables import Variable
|
|
1975
|
+
>>> v = Variable("1s")
|
|
1976
|
+
>>> result = 3.0 / v
|
|
1977
|
+
>>> assert result.numeric_value == 3.0
|
|
1978
|
+
>>> assert result.units == "Hz"
|
|
1979
|
+
>>> assert result.unit_system == "Freq"
|
|
1980
|
+
|
|
1981
|
+
"""
|
|
1982
|
+
if is_number(other):
|
|
1983
|
+
result_value = other / self.numeric_value
|
|
1984
|
+
result_units = _resolve_unit_system("None", self.unit_system, "divide")
|
|
1985
|
+
|
|
1986
|
+
else:
|
|
1987
|
+
result_value = other.numeric_value / self.numeric_value
|
|
1988
|
+
result_units = _resolve_unit_system(other.unit_system, self.unit_system, "divide")
|
|
1989
|
+
|
|
1990
|
+
return Variable("{}{}".format(result_value, result_units))
|
|
1991
|
+
|
|
1992
|
+
# # Python 2.7 version
|
|
1993
|
+
# @pyedb_function_handler()
|
|
1994
|
+
# def __div__(self, other):
|
|
1995
|
+
# return self.__rtruediv__(other)
|
|
1996
|
+
|
|
1997
|
+
|
|
1998
|
+
class DataSet(object):
|
|
1999
|
+
"""Manages datasets.
|
|
2000
|
+
|
|
2001
|
+
Parameters
|
|
2002
|
+
----------
|
|
2003
|
+
app :
|
|
2004
|
+
name : str
|
|
2005
|
+
Name of the app.
|
|
2006
|
+
x : list
|
|
2007
|
+
List of X-axis values for the dataset.
|
|
2008
|
+
y : list
|
|
2009
|
+
List of Y-axis values for the dataset.
|
|
2010
|
+
z : list, optional
|
|
2011
|
+
List of Z-axis values for a 3D dataset only. The default is ``None``.
|
|
2012
|
+
v : list, optional
|
|
2013
|
+
List of V-axis values for a 3D dataset only. The default is ``None``.
|
|
2014
|
+
xunit : str, optional
|
|
2015
|
+
Units for the X axis. The default is ``""``.
|
|
2016
|
+
yunit : str, optional
|
|
2017
|
+
Units for the Y axis. The default is ``""``.
|
|
2018
|
+
zunit : str, optional
|
|
2019
|
+
Units for the Z axis for a 3D dataset only. The default is ``""``.
|
|
2020
|
+
vunit : str, optional
|
|
2021
|
+
Units for the V axis for a 3D dataset only. The default is ``""``.
|
|
2022
|
+
|
|
2023
|
+
"""
|
|
2024
|
+
|
|
2025
|
+
def __init__(self, app, name, x, y, z=None, v=None, xunit="", yunit="", zunit="", vunit=""):
|
|
2026
|
+
self._app = app
|
|
2027
|
+
self.name = name
|
|
2028
|
+
self.x = x
|
|
2029
|
+
self.y = y
|
|
2030
|
+
self.z = z
|
|
2031
|
+
self.v = v
|
|
2032
|
+
self.xunit = xunit
|
|
2033
|
+
self.yunit = yunit
|
|
2034
|
+
self.zunit = zunit
|
|
2035
|
+
self.vunit = vunit
|
|
2036
|
+
|
|
2037
|
+
@pyedb_function_handler()
|
|
2038
|
+
def _args(self): # pragma: no cover
|
|
2039
|
+
"""Retrieve arguments."""
|
|
2040
|
+
arg = []
|
|
2041
|
+
arg.append("Name:" + self.name)
|
|
2042
|
+
arg2 = ["Name:Coordinates"]
|
|
2043
|
+
if self.z is None:
|
|
2044
|
+
arg2.append(["NAME:DimUnits", self.xunit, self.yunit])
|
|
2045
|
+
elif self.v is not None:
|
|
2046
|
+
arg2.append(["NAME:DimUnits", self.xunit, self.yunit, self.zunit, self.vunit])
|
|
2047
|
+
else:
|
|
2048
|
+
return False
|
|
2049
|
+
if self.z:
|
|
2050
|
+
x, y, z, v = (list(t) for t in zip(*sorted(zip(self.x, self.y, self.z, self.v), key=lambda e: float(e[0]))))
|
|
2051
|
+
else:
|
|
2052
|
+
x, y = (list(t) for t in zip(*sorted(zip(self.x, self.y), key=lambda e: float(e[0]))))
|
|
2053
|
+
ver = self._app._aedt_version
|
|
2054
|
+
for i in range(len(x)):
|
|
2055
|
+
if ver >= "2022.1":
|
|
2056
|
+
arg3 = ["NAME:Point"]
|
|
2057
|
+
arg3.append(float(x[i]))
|
|
2058
|
+
arg3.append(float(y[i]))
|
|
2059
|
+
if self.z:
|
|
2060
|
+
arg3.append(float(z[i]))
|
|
2061
|
+
arg3.append(float(v[i]))
|
|
2062
|
+
arg2.append(arg3)
|
|
2063
|
+
else:
|
|
2064
|
+
arg3 = []
|
|
2065
|
+
arg3.append("NAME:Coordinate")
|
|
2066
|
+
arg4 = ["NAME:CoordPoint"]
|
|
2067
|
+
arg4.append(float(x[i]))
|
|
2068
|
+
arg4.append(float(y[i]))
|
|
2069
|
+
if self.z:
|
|
2070
|
+
arg4.append(float(z[i]))
|
|
2071
|
+
arg4.append(float(v[i]))
|
|
2072
|
+
arg3.append(arg4)
|
|
2073
|
+
arg2.append(arg3)
|
|
2074
|
+
arg.append(arg2)
|
|
2075
|
+
return arg
|
|
2076
|
+
|
|
2077
|
+
@pyedb_function_handler()
|
|
2078
|
+
def create(self): # pragma: no cover
|
|
2079
|
+
"""Create a dataset.
|
|
2080
|
+
|
|
2081
|
+
Returns
|
|
2082
|
+
-------
|
|
2083
|
+
bool
|
|
2084
|
+
``True`` when successful, ``False`` when failed.
|
|
2085
|
+
|
|
2086
|
+
References
|
|
2087
|
+
----------
|
|
2088
|
+
|
|
2089
|
+
>>> oProject.AddDataset
|
|
2090
|
+
>>> oDesign.AddDataset
|
|
2091
|
+
"""
|
|
2092
|
+
if self.name[0] == "$":
|
|
2093
|
+
self._app._oproject.AddDataset(self._args())
|
|
2094
|
+
else:
|
|
2095
|
+
self._app._odesign.AddDataset(self._args())
|
|
2096
|
+
return True
|
|
2097
|
+
|
|
2098
|
+
@pyedb_function_handler()
|
|
2099
|
+
def add_point(self, x, y, z=None, v=None): # pragma: no cover
|
|
2100
|
+
"""Add a point to the dataset.
|
|
2101
|
+
|
|
2102
|
+
Parameters
|
|
2103
|
+
----------
|
|
2104
|
+
x : float
|
|
2105
|
+
X coordinate of the point.
|
|
2106
|
+
y : float
|
|
2107
|
+
Y coordinate of the point.
|
|
2108
|
+
z : float, optional
|
|
2109
|
+
The default is ``None``.
|
|
2110
|
+
v : float, optional
|
|
2111
|
+
The default is ``None``.
|
|
2112
|
+
|
|
2113
|
+
Returns
|
|
2114
|
+
-------
|
|
2115
|
+
bool
|
|
2116
|
+
``True`` when successful, ``False`` when failed.
|
|
2117
|
+
|
|
2118
|
+
References
|
|
2119
|
+
----------
|
|
2120
|
+
|
|
2121
|
+
>>> oProject.EditDataset
|
|
2122
|
+
>>> oDesign.EditDataset
|
|
2123
|
+
"""
|
|
2124
|
+
self.x.append(x)
|
|
2125
|
+
self.y.append(y)
|
|
2126
|
+
if self.z and self.v:
|
|
2127
|
+
self.z.append(z)
|
|
2128
|
+
self.v.append(v)
|
|
2129
|
+
|
|
2130
|
+
return self.update()
|
|
2131
|
+
|
|
2132
|
+
@pyedb_function_handler()
|
|
2133
|
+
def remove_point_from_x(self, x): # pragma: no cover
|
|
2134
|
+
"""Remove a point from an X-axis value.
|
|
2135
|
+
|
|
2136
|
+
Parameters
|
|
2137
|
+
----------
|
|
2138
|
+
x : float
|
|
2139
|
+
|
|
2140
|
+
Returns
|
|
2141
|
+
-------
|
|
2142
|
+
bool
|
|
2143
|
+
``True`` when successful, ``False`` when failed.
|
|
2144
|
+
|
|
2145
|
+
References
|
|
2146
|
+
----------
|
|
2147
|
+
|
|
2148
|
+
>>> oProject.EditDataset
|
|
2149
|
+
>>> oDesign.EditDataset
|
|
2150
|
+
"""
|
|
2151
|
+
if x not in self.x:
|
|
2152
|
+
self._app.logger.error("Value {} is not found.".format(x))
|
|
2153
|
+
return False
|
|
2154
|
+
id_to_remove = self.x.index(x)
|
|
2155
|
+
return self.remove_point_from_index(id_to_remove)
|
|
2156
|
+
|
|
2157
|
+
@pyedb_function_handler()
|
|
2158
|
+
def remove_point_from_index(self, id_to_remove): # pragma: no cover
|
|
2159
|
+
"""Remove a point from an index.
|
|
2160
|
+
|
|
2161
|
+
Parameters
|
|
2162
|
+
----------
|
|
2163
|
+
id_to_remove : int
|
|
2164
|
+
ID of the index.
|
|
2165
|
+
|
|
2166
|
+
Returns
|
|
2167
|
+
-------
|
|
2168
|
+
bool
|
|
2169
|
+
``True`` when successful, ``False`` when failed.
|
|
2170
|
+
|
|
2171
|
+
References
|
|
2172
|
+
----------
|
|
2173
|
+
|
|
2174
|
+
>>> oProject.EditDataset
|
|
2175
|
+
>>> oDesign.EditDataset
|
|
2176
|
+
"""
|
|
2177
|
+
if id_to_remove < len(self.x) > 2:
|
|
2178
|
+
self.x.pop(id_to_remove)
|
|
2179
|
+
self.y.pop(id_to_remove)
|
|
2180
|
+
if self.z and self.v:
|
|
2181
|
+
self.z.pop(id_to_remove)
|
|
2182
|
+
self.v.pop(id_to_remove)
|
|
2183
|
+
return self.update()
|
|
2184
|
+
self._app.logger.error("cannot Remove {} index.".format(id_to_remove))
|
|
2185
|
+
return False
|
|
2186
|
+
|
|
2187
|
+
@pyedb_function_handler()
|
|
2188
|
+
def update(self): # pragma: no cover
|
|
2189
|
+
"""Update the dataset.
|
|
2190
|
+
|
|
2191
|
+
Returns
|
|
2192
|
+
-------
|
|
2193
|
+
bool
|
|
2194
|
+
``True`` when successful, ``False`` when failed.
|
|
2195
|
+
|
|
2196
|
+
References
|
|
2197
|
+
----------
|
|
2198
|
+
|
|
2199
|
+
>>> oProject.EditDataset
|
|
2200
|
+
>>> oDesign.EditDataset
|
|
2201
|
+
"""
|
|
2202
|
+
args = self._args()
|
|
2203
|
+
if not args:
|
|
2204
|
+
return False
|
|
2205
|
+
if self.name[0] == "$":
|
|
2206
|
+
self._app._oproject.EditDataset(self.name, self._args())
|
|
2207
|
+
else:
|
|
2208
|
+
self._app._odesign.EditDataset(self.name, self._args())
|
|
2209
|
+
return True
|
|
2210
|
+
|
|
2211
|
+
@pyedb_function_handler()
|
|
2212
|
+
def delete(self): # pragma: no cover
|
|
2213
|
+
"""Delete the dataset.
|
|
2214
|
+
|
|
2215
|
+
Returns
|
|
2216
|
+
-------
|
|
2217
|
+
bool
|
|
2218
|
+
``True`` when successful, ``False`` when failed.
|
|
2219
|
+
|
|
2220
|
+
References
|
|
2221
|
+
----------
|
|
2222
|
+
|
|
2223
|
+
>>> oProject.DeleteDataset
|
|
2224
|
+
>>> oDesign.DeleteDataset
|
|
2225
|
+
"""
|
|
2226
|
+
if self.name[0] == "$":
|
|
2227
|
+
self._app._oproject.DeleteDataset(self.name)
|
|
2228
|
+
del self._app.project_datasets[self.name]
|
|
2229
|
+
else:
|
|
2230
|
+
self._app._odesign.DeleteDataset(self.name)
|
|
2231
|
+
del self._app.project_datasets[self.name]
|
|
2232
|
+
return True
|
|
2233
|
+
|
|
2234
|
+
@pyedb_function_handler()
|
|
2235
|
+
def export(self, dataset_path=None): # pragma: no cover
|
|
2236
|
+
"""Export the dataset.
|
|
2237
|
+
|
|
2238
|
+
Parameters
|
|
2239
|
+
----------
|
|
2240
|
+
dataset_path : str, optional
|
|
2241
|
+
Path to export the dataset to. The default is ``None``, in which
|
|
2242
|
+
case the dataset is exported to the working_directory path.
|
|
2243
|
+
|
|
2244
|
+
Returns
|
|
2245
|
+
-------
|
|
2246
|
+
bool
|
|
2247
|
+
``True`` when successful, ``False`` when failed.
|
|
2248
|
+
|
|
2249
|
+
References
|
|
2250
|
+
----------
|
|
2251
|
+
|
|
2252
|
+
>>> oProject.ExportDataset
|
|
2253
|
+
>>> oDesign.ExportDataset
|
|
2254
|
+
"""
|
|
2255
|
+
if not dataset_path:
|
|
2256
|
+
dataset_path = os.path.join(self._app.working_directory, self.name + ".tab")
|
|
2257
|
+
if self.name[0] == "$":
|
|
2258
|
+
self._app._oproject.ExportDataset(self.name, dataset_path)
|
|
2259
|
+
else:
|
|
2260
|
+
self._app._odesign.ExportDataset(self.name, dataset_path)
|
|
2261
|
+
return True
|