Skip to content

Commit

Permalink
FIX: Allow Optimetrics multi goals (#5583)
Browse files Browse the repository at this point in the history
Co-authored-by: mcapodif <massimo.capodiferro@ansys.com>
  • Loading branch information
Samuelopez-ansys and maxcapodi78 authored Dec 17, 2024
1 parent a68479b commit c10d896
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 62 deletions.
22 changes: 21 additions & 1 deletion src/ansys/aedt/core/generic/data_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,15 @@ def _dict2arg(d, arg_out):
arg = ["NAME:" + k, v[0], v[1]]
arg_out.append(arg)
elif k == "Range":
if isinstance(v[0], (list, tuple)):
if isinstance(v[0], dict):
for rr in v:
arg_out.append("Range:=")
new_range = []
for rk, ri in rr.items():
new_range.append(rk + ":=")
new_range.append(ri)
arg_out.append(new_range)
elif isinstance(v[0], (list, tuple)):
for e in v:
arg_out.append(k + ":=")
arg_out.append([i for i in e])
Expand Down Expand Up @@ -165,6 +173,18 @@ def _arg2dict(arg, dict_out):
dict_out[arg[0][5:]].append(list(arg[1:]))
else:
dict_out[arg[0][5:]] = list(arg[1:])
elif "NAME:Ranges" in arg[0]:
dict_out["Ranges"] = {"Range": []}
for el, val in enumerate(arg[1:]):
if val == "Range:=":
rr = {}
vals = arg[el + 2]
k = 0
while k < len(vals):
rr[vals[k][:-2]] = vals[k + 1]
k += 2
dict_out["Ranges"]["Range"].append(rr)

elif arg[0][:5] == "NAME:":
top_key = arg[0][5:]
dict_in = {}
Expand Down
10 changes: 9 additions & 1 deletion src/ansys/aedt/core/generic/load_aedt_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def load_keyword_in_aedt_file(filename, keyword, design_name=None):
"Rotation",
"PostProcessingCells",
]
_recognized_subkeys = ["simple(", "IDMap(", "WireSeg(", "PC("]
_recognized_subkeys = ["simple(", "IDMap(", "WireSeg(", "PC(", "Range("]

# global variables
_all_lines = []
Expand Down Expand Up @@ -201,6 +201,14 @@ def _decode_recognized_subkeys(sk, d):
d["PC"] = []
d["PC"].append(pclist)
return True
if sk.startswith(_recognized_subkeys[4]):
pclist = [i for i in sk.lstrip("Range(").rstrip(")").split(", ")]
if "Range" in d.keys():
d["Range"].append(pclist)
else:
d["Range"] = []
d["Range"].append(pclist)
return True
return False


Expand Down
133 changes: 73 additions & 60 deletions src/ansys/aedt/core/modules/design_xploration.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@

import copy
import csv
from typing import Any
from typing import Dict
from typing import Optional

from ansys.aedt.core.generic.data_handlers import _arg2dict
from ansys.aedt.core.generic.data_handlers import _dict2arg
Expand All @@ -45,15 +48,15 @@ class CommonOptimetrics(PropsManager, object):
Parameters
----------
p_app :
name :
dictinputs
p_app : :class:`ansys.aedt.core.application.analysis.Analysis`
PyAEDT analysis instance.
name : str
Optimetrics setup name.
dictinputs : dict
Input setup parameters.
optimtype : str
Type of the optimization.
Type of the optimization. Available options are: ``"OptiParametric"``, ``"OptiDesignExplorer"`,
``"OptiOptimization"``, ``"OptiSensitivity"``, ``"OptiStatistical"``, ``"OptiDXDOE"``, and ``"optiSLang"``.
"""

def __init__(self, p_app, name, dictinputs, optimtype):
Expand Down Expand Up @@ -114,11 +117,20 @@ def __init__(self, p_app, name, dictinputs, optimtype):
if self._app._is_object_oriented_enabled():
oparams = self.omodule.GetChildObject(self.name).GetCalculationInfo()
oparam = [i for i in oparams[0]]
calculation = ["NAME:Goal"]
calculation.extend(oparam)
arg1 = {}
_arg2dict(calculation, arg1)
self.props["Goals"] = arg1
idx = None
if oparam[0] in oparam[1:]:
idx = oparam[1:].index(oparam[0]) + 1
if idx:
oparam = [["NAME:Goal"] + oparam[k : idx + k] for k in range(0, len(oparam), idx)]
else:
oparam = [["NAME:Goal"] + oparam]

self.props["Goals"]["Goal"] = []
for param in oparam:
arg1 = {}
_arg2dict(param, arg1)
self._get_setup_props(arg1)
self.props["Goals"]["Goal"].append(SetupProps(self, arg1["Goal"]))

if inputd.get("Variables"): # pragma: no cover
for var in inputd.get("Variables"):
Expand All @@ -136,6 +148,16 @@ def __init__(self, p_app, name, dictinputs, optimtype):

self.auto_update = True

def _get_setup_props(self, arg1: Dict[str, Any]) -> None:
for k, v in arg1.items():
if isinstance(v, dict):
arg1[k] = SetupProps(self, v)
self._get_setup_props(v)
elif isinstance(v, list):
for idx, item in enumerate(v):
if isinstance(item, dict):
v[idx] = SetupProps(self, item)

@pyaedt_function_handler()
def _get_context(
self,
Expand All @@ -155,17 +177,16 @@ def _get_context(
did = 3
if domain != "Sweep":
did = 1
sweepdefinition = {}
sweepdefinition["ReportType"] = report_category
sweep_definition = {"ReportType": report_category}
if not setup_sweep_name:
setup_sweep_name = self._app.nominal_sweep
sweepdefinition["Solution"] = setup_sweep_name
sweep_definition["Solution"] = setup_sweep_name
ctxt = {}

if self._app.solution_type in ["TR", "AC", "DC"]:
ctxt["SimValueContext"] = [did, 0, 2, 0, False, False, -1, 1, 0, 1, 1, "", 0, 0]
setup_sweep_name = self._app.solution_type
sweepdefinition["Solution"] = setup_sweep_name
sweep_definition["Solution"] = setup_sweep_name

elif self._app.solution_type in ["HFSS3DLayout"]:
if context == "Differential Pairs":
Expand Down Expand Up @@ -215,12 +236,12 @@ def _get_context(
ctxt["PointCount"] = polyline_points
else:
ctxt = {"Domain": domain}
sweepdefinition["SimValueContext"] = ctxt
sweepdefinition["Calculation"] = expressions
sweepdefinition["Name"] = expressions
sweepdefinition["Ranges"] = {}
sweep_definition["SimValueContext"] = ctxt
sweep_definition["Calculation"] = expressions
sweep_definition["Name"] = expressions
sweep_definition["Ranges"] = {}
if context and context in self._app.modeler.line_names and intrinsics and "Distance" not in intrinsics:
sweepdefinition["Ranges"]["Range"] = ("Var:=", "Distance", "Type:=", "a")
sweep_definition["Ranges"]["Range"] = ("Var:=", "Distance", "Type:=", "a")
if not setup_sweep_name:
setup_sweep_name = self._app.nominal_sweep
if not setup_sweep_name:
Expand All @@ -231,43 +252,35 @@ def _get_context(
return False
if intrinsics:
for v, k in intrinsics.items():
r = {}
if not k:
r = ["Var:=", v, "Type:=", "a"]
r = {"Var": v, "Type": "a"}
elif isinstance(k, tuple):
r = ["Var:=", v, "Type:=", "rd"]
r.append("Start:=")
r.append(k[0])
r.append("Stop:=")
r.append(k[1])
r.append("DiscreteValues:=")
r.append("")
r = {"Var": v, "Type": "rd", "Start": k[0], "Stop": k[1], "DiscreteValues": ""}
elif isinstance(k, (list, str)):
r = ["Var:=", v, "Type:=", "d"]
r.append("DiscreteValues:=")
if isinstance(k, list):
r.append(",".join(k))
else:
r.append(k)

if not sweepdefinition["Ranges"]:
sweepdefinition["Ranges"]["Range"] = tuple(r)
elif isinstance(sweepdefinition["Ranges"]["Range"], list):
sweepdefinition["Ranges"]["Range"].append(tuple(r))
r = {"Var": v, "Type": "d", "DiscreteValues": ",".join(k) if isinstance(k, list) else k}
r = SetupProps(self, r)
if not sweep_definition["Ranges"]:
sweep_definition["Ranges"]["Range"] = [r]
elif isinstance(sweep_definition["Ranges"]["Range"], list):
sweep_definition["Ranges"]["Range"].append(r)
else:
sweepdefinition["Ranges"]["Range"] = [sweepdefinition["Ranges"]["Range"]]
sweepdefinition["Ranges"]["Range"].append(tuple(r))
sweep_definition["Ranges"]["Range"] = [sweep_definition["Ranges"]["Range"]]
sweep_definition["Ranges"]["Range"].append(r)
if is_goal:
sweepdefinition["Condition"] = condition
sweepdefinition["GoalValue"] = {
sweep_definition["Condition"] = condition
goal_value = {
"GoalValueType": "Independent",
"Format": "Real/Imag",
"bG": ["v:=", f"[{goal_value};]"],
}
sweepdefinition["Weight"] = f"[{goal_weight};]"
return sweepdefinition
goal_value = SetupProps(self, goal_value)
sweep_definition["GoalValue"] = goal_value
sweep_definition["Weight"] = f"[{goal_weight};]"
return sweep_definition

@pyaedt_function_handler()
def update(self, update_dictionary=None):
def update(self, update_dictionary: Optional[Dict[str, Any]] = None) -> bool:
"""Update the setup based on stored properties.
Parameters
Expand Down Expand Up @@ -302,7 +315,7 @@ def update(self, update_dictionary=None):
return True

@pyaedt_function_handler()
def create(self):
def create(self) -> bool:
"""Create a setup.
Returns
Expand Down Expand Up @@ -395,7 +408,7 @@ def _add_calculation(
optigoalname = "Goals"
if "Goal" in self.props[optigoalname]:
if type(self.props[optigoalname]["Goal"]) is not list:
self.props[optigoalname]["Goal"] = [self.props[optigoalname]["Goal"], sweepdefinition]
self.props[optigoalname]["Goal"] = [self.props[optigoalname]["Goal"], SetupProps(self, sweepdefinition)]
else:
self.props[optigoalname]["Goal"].append(sweepdefinition)
else:
Expand Down Expand Up @@ -534,16 +547,16 @@ def _activate_variable(self, variable_name):
@pyaedt_function_handler(num_cores="cores", num_tasks="tasks", num_gpu="gpus")
def analyze(
self,
cores=1,
tasks=1,
gpus=0,
acf_file=None,
use_auto_settings=True,
solve_in_batch=False,
machine="localhost",
run_in_thread=False,
revert_to_initial_mesh=False,
):
cores: int = 1,
tasks: int = 1,
gpus: int = 0,
acf_file: str = None,
use_auto_settings: bool = True,
solve_in_batch: bool = False,
machine: str = "localhost",
run_in_thread: bool = False,
revert_to_initial_mesh: bool = False,
) -> bool:
"""Solve the active design.
Parameters
Expand Down
14 changes: 14 additions & 0 deletions tests/system/general/test_11_Setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,22 @@ def test_26_create_optimization(self):
if "NAME:Ranges" in el:
break
assert "rd" in el[2]

assert setup2.props["Goals"]["Goal"][0]["Ranges"]["Range"][0]["DiscreteValues"] == "2.5GHz"

setup2.props["Goals"]["Goal"][0]["Ranges"]["Range"][0]["DiscreteValues"] = "2.7GHz"

oo = self.aedtapp.get_oo_object(self.aedtapp.odesign, f"Optimetrics\\{setup2.name}")
oo_calculation = oo.GetCalculationInfo()[0]
for el in oo_calculation:
if "NAME:Ranges" in el:
break
assert el[2][5] == "2.7GHz"

assert self.aedtapp.optimizations.delete(setup2.name)

assert not self.aedtapp.get_oo_object(self.aedtapp.odesign, f"Optimetrics\\{setup2.name}")

def test_27_create_doe(self):
calculation = "db(S(1,1))"
new_setup = self.aedtapp.create_setup("MyDOESetup")
Expand Down

0 comments on commit c10d896

Please sign in to comment.