Skip to content

Edit Sources in Q3D and Q2D #1298

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions _unittest/test_00_report_file_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_report_file_parser():
"Mag_H": {
"x_name": "Distance",
"x_unit": "meter",
"y_unit": "A_per_m",
"y_unit": "A_per_meter",
"curves": {
'Freq="1e-08GHz" Ip="10mA" Phase="0deg"': {
"x_data": [
Expand Down Expand Up @@ -2301,7 +2301,7 @@ def test_report_file_parser():
"Mag_H_1": {
"x_name": "Distance",
"x_unit": "meter",
"y_unit": "A_per_m",
"y_unit": "A_per_meter",
"curves": {
'Freq="1e-08GHz" Ip="10mA" Phase="0deg"': {
"x_data": [
Expand Down
19 changes: 18 additions & 1 deletion _unittest/test_30_Q2D.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,24 @@ def test_11_matrix_reduction(self):
assert q2d.matrices[5].name == "Test5"
self.aedtapp.close_project(q2d.project_name, False)

def test_12_get_all_conductors(self):
def test_12_edit_sources(self):
q2d = Q2d(self.test_matrix, specified_version=desktop_version)
sources_cg = {"Circle2": ("10V", "45deg"), "Circle3": "4A"}
assert q2d.edit_sources(sources_cg)

sources_cg = {"Circle2": "1V", "Circle3": "4A"}
sources_ac = {"Circle3": "40A"}
assert q2d.edit_sources(sources_cg, sources_ac)

sources_cg = {"Circle2": ["10V"], "Circle3": "4A"}
sources_ac = {"Circle3": ("100A", "5deg")}
assert q2d.edit_sources(sources_cg, sources_ac)

sources_ac = {"Circle5": "40A"}
assert not q2d.edit_sources(sources_cg, sources_ac)
self.aedtapp.close_project(q2d.project_name, False)

def test_13_get_all_conductors(self):
self.aedtapp.insert_design("condcutors")
o = self.aedtapp.create_rectangle([6, 6], [5, 3], name="Rectangle1", matname="Copper")
o1 = self.aedtapp.create_rectangle([7, 5], [5, 3], name="Rectangle2", matname="aluminum")
Expand Down
30 changes: 30 additions & 0 deletions _unittest/test_31_Q3D.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,33 @@ def test_13_matrix_reduction(self):
"C(Box1,Box1_2)"
]
self.aedtapp.close_project(q3d.project_name, False)

def test_14_edit_sources(self):
q3d = Q3d(self.test_matrix, specified_version=desktop_version)
sources_cg = {"Box1": ("2V", "45deg"), "Box1_2": "4V"}
sources_ac = {"Box1:Source1": "2A"}
assert q3d.edit_sources(sources_cg, sources_ac)

sources_cg = {"Box1": ("20V", "15deg"), "Box1_2": "40V"}
sources_ac = {"Box1:Source1": "2A", "Box1_1:Source2": "20A"}
sources_dc = {"Box1:Source1": "20V"}
assert q3d.edit_sources(sources_cg, sources_ac, sources_dc)

sources_cg = {"Box1": "2V"}
sources_ac = {"Box1:Source1": "2", "Box1_1:Source2": "5V"}
assert q3d.edit_sources(sources_cg, sources_ac)

sources_cg = {"Box1": ["20V"], "Box1_2": "4V"}
sources_ac = {"Box1:Source1": "2A"}
assert q3d.edit_sources(sources_cg, sources_ac)

sources_dc = {"Box1:Source1": "20"}
assert q3d.edit_sources(dcrl=sources_dc)

sources_cg = {"Box2": "2V"}
assert not q3d.edit_sources(sources_cg)
sources_ac = {"Box1:Source2": "2V"}
assert not q3d.edit_sources(sources_ac)
sources_dc = {"Box1:Source2": "2V"}
assert not q3d.edit_sources(sources_dc)
self.aedtapp.close_project(q3d.project_name, False)
12 changes: 11 additions & 1 deletion pyaedt/generic/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,15 @@ def scale_units(scale_to_unit):
"kA_per_m": 1e3,
"megA_per_m": 1e6,
"gA_per_m": 1e9,
"fA_per_meter": 1e-15,
"pA_per_meter": 1e-12,
"nA_per_meter": 1e-9,
"uA_per_meter": 1e-6,
"mA_per_meter": 1e-3,
"A_per_meter": 1.0,
"kA_per_meter": 1e3,
"megA_per_meter": 1e6,
"gA_per_meter": 1e9,
},
}
SI_UNITS = {
Expand All @@ -354,13 +363,14 @@ def scale_units(scale_to_unit):
"Mass": "kg",
"None": "",
"Resistance": "ohm",
"Speed": "m_per_sec",
"Time": "s",
"Torque": "NewtonMeter",
"Voltage": "V",
"Temperature": "kel",
"Power": "W",
"B-field": "tesla",
"H-field": "A_per_m",
"H-field": "A_per_meter",
}
UNIT_SYSTEM_OPERATIONS = {
# Multiplication of physical domains
Expand Down
153 changes: 153 additions & 0 deletions pyaedt/q3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from pyaedt.generic.general_methods import pyaedt_function_handler
from pyaedt.modules.Boundary import BoundaryObject
from pyaedt.modules.Boundary import Matrix
from pyaedt.application.Variables import decompose_variable_value


class QExtractor(FieldAnalysis3D, object):
Expand Down Expand Up @@ -189,6 +190,158 @@ def export_mesh_stats(self, setup_name, variation_string="", mesh_path=None, set
self.odesign.ExportMeshStats(setup_name, variation_string, setup_type, mesh_path)
return mesh_path

@pyaedt_function_handler()
def edit_sources(
self,
cg=None,
acrl=None,
dcrl=None,
):
"""Set up the source loaded for Q3D or Q2D in multiple sources simultaneously.

Parameters
----------
cg : dict, optional
Dictionary of input sources to modify module and phase of CG solution.
Dictionary values can be:
- 1 Value to setup 0deg as default or
- 2 values tuple or list (magnitude and phase).
acrl : dict, optional
Dictionary of input sources to modify module and phase of ACRL solution.
Dictionary values can be:
- 1 Value to setup 0deg as default or
- 2 values tuple or list (magnitude and phase).
Comment on lines +212 to +213
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- 1 Value to setup 0deg as default or
- 2 values tuple or list (magnitude and phase).
- 1 Value to set up ``0deg`` as the default
- 2 A values tuple or list (magnitude and phase)

dcrl : dict, optional
Dictionary of input sources to modify module and phase of DCRL solution, only available for Q3D.
Dictionary values can be:
- 1 Value to setup 0deg as default or
- 2 values tuple or list (magnitude and phase).

Returns
-------
bool

Examples
--------
>>> sources_cg = {"Box1": ("1V", "0deg"), "Box1_2": "1V"}
>>> sources_acrl = {"Box1:Source1": ("5A", "0deg")}
>>> sources_dcrl = {"Box1_1:Source2": ("5V", "0deg")}
>>> hfss.edit_sources(sources_cg, sources_acrl, sources_dcrl)
"""
setting_AC = []
setting_CG = []
setting_DC = []
if cg:
net_list = ["NAME:Source Names"]
if self.default_solution_type == "Q3D Extractor":
excitation = self.nets
else:
excitation = self.excitations

for key, value in cg.items():
if key not in excitation:
self.logger.error("Not existing net " + key)
return False
else:
net_list.append(key)

if self.default_solution_type == "Q3D Extractor":
value_list = ["NAME:Source Values"]
phase_list = ["NAME:Source Values"]
else:
value_list = ["NAME:Magnitude"]
phase_list = ["NAME:Phase"]

for key, vals in cg.items():
if isinstance(vals, str):
value = vals
phase = "0deg"
else:
value = vals[0]
if len(vals) == 1:
phase = "0deg"
else:
phase = vals[1]
value_list.append(value)
phase_list.append(phase)
if self.default_solution_type == "Q3D Extractor":
setting_CG = ["NAME:Cap", "Value Type:=", "N", net_list, value_list, phase_list]
else:
setting_CG = ["NAME:CGSources", net_list, value_list, phase_list]
if acrl:
source_list = ["NAME:Source Names"]
unit = "V"
for key, value in acrl.items():
excitation = self.excitations
if key not in excitation:
self.logger.error("Not existing excitation " + key)
return False
else:
source_list.append(key)
if self.default_solution_type == "Q3D Extractor":
value_list = ["NAME:Source Values"]
phase_list = ["NAME:Source Values"]
else:
value_list = ["NAME:Magnitude"]
phase_list = ["NAME:Phase"]
for key, vals in acrl.items():
if isinstance(vals, str):
magnitude = decompose_variable_value(vals)
value = vals
phase = "0deg"
else:
value = vals[0]
magnitude = decompose_variable_value(value)
if len(vals) == 1:
phase = "0deg"
else:
phase = vals[1]
if magnitude[1]:
unit = magnitude[1]
else:
value += unit

value_list.append(value)
phase_list.append(phase)

if self.default_solution_type == "Q3D Extractor":
setting_AC = ["NAME:AC", "Value Type:=", unit, source_list, value_list]
else:
setting_AC = ["NAME:RLSources", source_list, value_list, phase_list]
if dcrl and self.default_solution_type == "Q3D Extractor":
unit = "V"
source_list = ["NAME:Source Names"]
for key, value in dcrl.items():
excitation = self.excitations
if key not in excitation:
self.logger.error("Not existing excitation " + key)
return False
else:
source_list.append(key)
if self.default_solution_type == "Q3D Extractor":
value_list = ["NAME:Source Values"]
else:
value_list = ["NAME:Magnitude"]
for key, vals in dcrl.items():
magnitude = decompose_variable_value(vals)
if magnitude[1]:
unit = magnitude[1]
else:
vals += unit
if isinstance(vals, str):
value = vals
else:
value = vals[0]
value_list.append(value)
setting_DC = ["NAME:DC", "Value Type:=", unit, source_list, value_list]

if self.default_solution_type == "Q3D Extractor":
self.osolution.EditSources(setting_AC, setting_CG, setting_DC)
else:
self.osolution.EditSources(setting_CG, setting_AC)

return True


class Q3d(QExtractor, object):
"""Provides the Q3D application interface.
Expand Down