From 9ad84e687f7916ef0f08b85ba7c8eb76295528d6 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Mon, 18 Nov 2024 10:58:23 +0100 Subject: [PATCH 01/26] Choke designer --- .../core/workflows/hfss/choke_designer.py | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 src/ansys/aedt/core/workflows/hfss/choke_designer.py diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py new file mode 100644 index 00000000000..12bcf2cee11 --- /dev/null +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2024 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# import datetime +import json +import os.path +import tkinter as tk +from tkinter import filedialog +from tkinter import messagebox +from tkinter import ttk + +import ansys.aedt.core + +# from ansys.aedt.core import Hfss +# from ansys.aedt.core.generic.general_methods import open_file +import ansys.aedt.core.workflows +from ansys.aedt.core.workflows.misc import get_aedt_version +from ansys.aedt.core.workflows.misc import get_arguments +from ansys.aedt.core.workflows.misc import get_port +from ansys.aedt.core.workflows.misc import get_process_id +from ansys.aedt.core.workflows.misc import is_student + +port = get_port() +version = get_aedt_version() +aedt_process_id = get_process_id() +is_student = is_student() + +default_config = { + "Number of Windings": {"1": True, "2": False, "3": False, "4": False}, + "Layer": {"Simple": True, "Double": False, "Triple": False}, + "Layer Type": {"Separate": True, "Linked": False}, + "Similar Layer": {"Similar": True, "Different": False}, + "Mode": {"Differential": True, "Common": False}, + "Wire Section": {"None": False, "Hexagon": False, "Octagon": False, "Circle": True}, + "Core": { + "Name": "Core", + "Material": "ferrite", + "Inner Radius": 20, + "Outer Radius": 30, + "Height": 10, + "Chamfer": 0.8, + }, + "Outer Winding": { + "Name": "Winding", + "Material": "copper", + "Inner Radius": 20, + "Outer Radius": 30, + "Height": 10, + "Wire Diameter": 1.5, + "Turns": 20, + "Coil Pit(deg)": 0.1, + "Occupation(%)": 0, + }, + "Mid Winding": { + "Turns": 25, + "Coil Pit(deg)": 0.1, + "Occupation(%)": 0, + }, + "Inner Winding": { + "Turns": 4, + "Coil Pit(deg)": 0.1, + "Occupation(%)": 0, + }, +} + +# Extension batch arguments +extension_arguments = {"file_path": "", "choice": ""} +extension_description = "Choke Designer in HFSS" + + +def frontend(): # pragma: no cover + """ + Interfaz gráfica para configurar los parámetros de diseño del Choke. + """ + master = tk.Tk() + master.geometry("800x600") + master.title("HFSS Choke Designer") + + # Configuración inicial + config = default_config.copy() + + # Crear panel principal + main_frame = ttk.PanedWindow(master, orient=tk.HORIZONTAL) + main_frame.pack(fill=tk.BOTH, expand=True) + + # Panel izquierdo (opciones booleanas) + left_frame = ttk.Frame(main_frame, width=250) + main_frame.add(left_frame, weight=1) + + def create_boolean_options(parent, config): + """Crea las opciones booleanas en el panel izquierdo.""" + for category, options in config.items(): + if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): + group_frame = ttk.LabelFrame(parent, text=category) + group_frame.pack(fill=tk.X, padx=10, pady=5) + + for option, value in options.items(): + var = tk.BooleanVar(value=value) + + def on_toggle(cat=category, opt=option): + for key in config[cat]: + config[cat][key] = key == opt + + btn = ttk.Radiobutton( + group_frame, + text=option, + variable=var, + value=True, + command=on_toggle, + ) + btn.pack(anchor=tk.W, padx=5) + + create_boolean_options(left_frame, config) + + # Panel derecho (notebook con pestañas) + right_frame = ttk.Notebook(master) + main_frame.add(right_frame, weight=3) + + def create_parameter_inputs(parent, config, category): + """Crea campos de entrada para parámetros numéricos y de texto.""" + for field, value in config[category].items(): + frame = ttk.Frame(parent) + frame.pack(fill=tk.X, padx=10, pady=2) + + label = ttk.Label(frame, text=field, width=20) + label.pack(side=tk.LEFT) + + entry = ttk.Entry(frame, width=15) + entry.insert(0, str(value)) + entry.pack(side=tk.LEFT, padx=5) + + # Pestañas de parámetros + for tab_name in ["Core", "Outer Winding", "Mid Winding", "Inner Winding"]: + tab = ttk.Frame(right_frame) + right_frame.add(tab, text=tab_name) + create_parameter_inputs(tab, config, tab_name) + + # Botones inferiores + def save_configuration(): + """Guarda la configuración en un archivo.""" + file_path = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("JSON files", "*.json")]) + if file_path: + try: + with open(file_path, "w") as f: + json.dump(config, f, indent=2) + messagebox.showinfo("Éxito", "Configuración guardada correctamente.") + except Exception as e: + messagebox.showerror("Error", f"No se pudo guardar la configuración: {e}") + + def load_configuration(): + """Carga una configuración desde un archivo.""" + file_path = filedialog.askopenfilename(filetypes=[("JSON files", "*.json")]) + if file_path: + try: + with open(file_path, "r") as f: + new_config = json.load(f) + for key in config: + if key in new_config: + config[key] = new_config[key] + messagebox.showinfo("Éxito", "Configuración cargada correctamente.") + except Exception as e: + messagebox.showerror("Error", f"No se pudo cargar la configuración: {e}") + + button_frame = ttk.Frame(master) + button_frame.pack(fill=tk.X, pady=5) + + save_button = ttk.Button(button_frame, text="Guardar Configuración", command=save_configuration) + load_button = ttk.Button(button_frame, text="Cargar Configuración", command=load_configuration) + save_button.pack(side=tk.LEFT, padx=5) + load_button.pack(side=tk.LEFT, padx=5) + + # Ejecutar la ventana principal + master.mainloop() + + +def main(extension_args): + choice = extension_args["choice"] + file_path = extension_args["file_path"] + + app = ansys.aedt.core.Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student, + ) + + if not os.path.isfile(file_path): # pragma: no cover + app.logger.error("File does not exist.") + elif choice: + app.logger.info(f"Choke type {choice}.") + app.logger.info(f"File: {file_path}.") + else: + app.logger.error("No parameter selected.") + + if not extension_args["is_test"]: # pragma: no cover + app.release_desktop(False, False) + return True + + +if __name__ == "__main__": # pragma: no cover + args = get_arguments(extension_arguments, extension_description) + + # Open UI + if not args["is_batch"]: # pragma: no cover + output = frontend() + if output: + for output_name, output_value in output.items(): + if output_name in extension_arguments: + args[output_name] = output_value + + main(args) From 8713a93069be80501d645ebef2f091a41bbf5543 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Mon, 18 Nov 2024 15:38:30 +0100 Subject: [PATCH 02/26] Choke designer in tkinter --- pyproject.toml | 3 +- .../core/workflows/hfss/choke_designer.py | 356 ++++++++++++++---- 2 files changed, 283 insertions(+), 76 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a463daad2a6..30dd6fa7ab3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,8 @@ dependencies = [ "pytomlpp; python_version < '3.12'", "rpyc>=6.0.0,<6.1", "pyyaml", - "defusedxml>=0.7,<8.0" + "defusedxml>=0.7,<8.0", + "sv-ttk" ] [project.optional-dependencies] diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 12bcf2cee11..284abab042a 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -21,18 +21,14 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -# import datetime -import json import os.path -import tkinter as tk -from tkinter import filedialog -from tkinter import messagebox -from tkinter import ttk +import shutil +import tempfile import ansys.aedt.core - -# from ansys.aedt.core import Hfss -# from ansys.aedt.core.generic.general_methods import open_file +from ansys.aedt.core import Hfss +from ansys.aedt.core.generic.general_methods import read_json +from ansys.aedt.core.generic.general_methods import write_configuration_file import ansys.aedt.core.workflows from ansys.aedt.core.workflows.misc import get_aedt_version from ansys.aedt.core.workflows.misc import get_arguments @@ -84,118 +80,199 @@ } # Extension batch arguments -extension_arguments = {"file_path": "", "choice": ""} +extension_arguments = {"choke_config": {}} extension_description = "Choke Designer in HFSS" +theme = "light" +if os.environ.get("AEDT_TOOLKIT_THEME", False): + if os.environ.get("AEDT_TOOLKIT_THEME") == "dark": + theme = "dark" + def frontend(): # pragma: no cover - """ - Interfaz gráfica para configurar los parámetros de diseño del Choke. - """ - master = tk.Tk() - master.geometry("800x600") - master.title("HFSS Choke Designer") - - # Configuración inicial - config = default_config.copy() - - # Crear panel principal - main_frame = ttk.PanedWindow(master, orient=tk.HORIZONTAL) - main_frame.pack(fill=tk.BOTH, expand=True) - - # Panel izquierdo (opciones booleanas) - left_frame = ttk.Frame(main_frame, width=250) + + import tkinter + from tkinter import filedialog + from tkinter import messagebox + from tkinter import ttk + + import PIL.Image + import PIL.ImageTk + import sv_ttk + + # Create UI + master = tkinter.Tk() + + master.geometry("900x800") + + master.title("HFSS Choke designer") + + # Detect if user close the UI + master.flag = False + + # Load the logo for the main window + icon_path = os.path.join(ansys.aedt.core.workflows.__path__[0], "images", "large", "logo.png") + im = PIL.Image.open(icon_path) + photo = PIL.ImageTk.PhotoImage(im) + + # Set the icon for the main window + master.iconphoto(True, photo) + + # Configure style for ttk buttons + style = ttk.Style() + style.configure("Toolbutton.TButton", padding=6, font=("Helvetica", 8)) + + # Load initial configuration + config_dict = default_config.copy() + + # Main panel + main_frame = ttk.PanedWindow(master, orient=tkinter.HORIZONTAL) + main_frame.pack(fill=tkinter.BOTH, expand=True) + + # Left panel + left_frame = ttk.Frame(main_frame, width=350) main_frame.add(left_frame, weight=1) def create_boolean_options(parent, config): - """Crea las opciones booleanas en el panel izquierdo.""" for category, options in config.items(): if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): group_frame = ttk.LabelFrame(parent, text=category) - group_frame.pack(fill=tk.X, padx=10, pady=5) + group_frame.pack(fill=tkinter.X, padx=10, pady=5) - for option, value in options.items(): - var = tk.BooleanVar(value=value) + selected_option = tkinter.StringVar(value=next((opt for opt, val in options.items() if val), "")) - def on_toggle(cat=category, opt=option): - for key in config[cat]: - config[cat][key] = key == opt + def on_toggle(cat, opt): + for key in config[cat]: + config[cat][key] = key == opt + for option, value in options.items(): btn = ttk.Radiobutton( group_frame, text=option, - variable=var, - value=True, - command=on_toggle, + variable=selected_option, + value=option, + command=lambda opt=option: on_toggle(category, opt), ) - btn.pack(anchor=tk.W, padx=5) + btn.pack(anchor=tkinter.W, padx=5) - create_boolean_options(left_frame, config) + create_boolean_options(left_frame, config_dict) - # Panel derecho (notebook con pestañas) + # Right panel right_frame = ttk.Notebook(master) main_frame.add(right_frame, weight=3) def create_parameter_inputs(parent, config, category): - """Crea campos de entrada para parámetros numéricos y de texto.""" + def update_config(cat, field, entry_widget): + """ + Update config_dict when the user changes an input. + """ + try: + # Save numeric values as floats, others as strings + new_value = ( + float(entry_widget.get()) + if entry_widget.get().replace(".", "", 1).isdigit() + else entry_widget.get() + ) + config[cat][field] = new_value + except ValueError: + pass # Ignore invalid input + for field, value in config[category].items(): frame = ttk.Frame(parent) - frame.pack(fill=tk.X, padx=10, pady=2) + frame.pack(fill=tkinter.X, padx=10, pady=2) label = ttk.Label(frame, text=field, width=20) - label.pack(side=tk.LEFT) + label.pack(side=tkinter.LEFT) entry = ttk.Entry(frame, width=15) entry.insert(0, str(value)) - entry.pack(side=tk.LEFT, padx=5) + entry.pack(side=tkinter.LEFT, padx=5) + + # Bind the `update_config` function to changes in the Entry widget + entry.bind("", lambda e, cat=category, fld=field, widget=entry: update_config(cat, fld, widget)) - # Pestañas de parámetros + # Parameters for tab_name in ["Core", "Outer Winding", "Mid Winding", "Inner Winding"]: tab = ttk.Frame(right_frame) right_frame.add(tab, text=tab_name) - create_parameter_inputs(tab, config, tab_name) - - # Botones inferiores + create_parameter_inputs(tab, config_dict, tab_name) + + def validate_configuration(config): + try: + if config["Core"]["Outer Radius"] <= config["Core"]["Inner Radius"]: + messagebox.showerror("Error", "Core outer radius must be greater than inner radius") + return False + + if config["Outer Winding"]["Outer Radius"] <= config["Outer Winding"]["Inner Radius"]: + messagebox.showerror("Error", "Winding outer radius must be greater than inner radius") + return False + + if config["Core"]["Height"] <= 0: + messagebox.showerror("Error", "Core height must be greater than 0") + return False + + if config["Outer Winding"]["Wire Diameter"] <= 0: + messagebox.showerror("Error", "Wire diameter must be greater than 0") + return False + return True + except (KeyError, TypeError) as e: + messagebox.showerror("Error", f"Validation error: {str(e)}") + return False + + # Buttons def save_configuration(): - """Guarda la configuración en un archivo.""" + if not validate_configuration(config_dict): + messagebox.showerror("Validation Error", "Please fix configuration errors before saving.") + return file_path = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("JSON files", "*.json")]) if file_path: try: - with open(file_path, "w") as f: - json.dump(config, f, indent=2) - messagebox.showinfo("Éxito", "Configuración guardada correctamente.") + write_configuration_file(config_dict, file_path) + messagebox.showinfo("Success", "Configuration saved successfully.") except Exception as e: - messagebox.showerror("Error", f"No se pudo guardar la configuración: {e}") + messagebox.showerror("Error", f"Failed to save configuration: {str(e)}") def load_configuration(): - """Carga una configuración desde un archivo.""" file_path = filedialog.askopenfilename(filetypes=[("JSON files", "*.json")]) if file_path: try: - with open(file_path, "r") as f: - new_config = json.load(f) + new_config = read_json(file_path) + if not validate_configuration(new_config): + messagebox.showerror("Validation Error", "Please fix configuration errors before loading.") + return for key in config: if key in new_config: config[key] = new_config[key] - messagebox.showinfo("Éxito", "Configuración cargada correctamente.") + messagebox.showinfo("Success", "Configuration saved successfully.") except Exception as e: - messagebox.showerror("Error", f"No se pudo cargar la configuración: {e}") + messagebox.showerror("Error", f"Failed to save configuration: {str(e)}") button_frame = ttk.Frame(master) - button_frame.pack(fill=tk.X, pady=5) + button_frame.pack(fill=tkinter.X, pady=5) + + save_button = ttk.Button(button_frame, text="Save Configuration", command=save_configuration) + load_button = ttk.Button(button_frame, text="Load Configuration", command=load_configuration) + save_button.pack(side=tkinter.LEFT, padx=5) + load_button.pack(side=tkinter.LEFT, padx=5) + + def callback(): + master.flag = True + if validate_configuration(config_dict): + master.destroy() - save_button = ttk.Button(button_frame, text="Guardar Configuración", command=save_configuration) - load_button = ttk.Button(button_frame, text="Cargar Configuración", command=load_configuration) - save_button.pack(side=tk.LEFT, padx=5) - load_button.pack(side=tk.LEFT, padx=5) + export_hfss = ttk.Button(button_frame, text="Export to HFSS", command=callback) + export_hfss.pack(side=tkinter.LEFT, padx=5) + sv_ttk.set_theme(theme) + tkinter.mainloop() - # Ejecutar la ventana principal - master.mainloop() + choke_config = {} + if master.flag: + choke_config = {"choke_config": config_dict} + return choke_config def main(extension_args): - choice = extension_args["choice"] - file_path = extension_args["file_path"] + choke_config = extension_args["choke_config"] app = ansys.aedt.core.Desktop( new_desktop=False, @@ -205,13 +282,141 @@ def main(extension_args): student_version=is_student, ) - if not os.path.isfile(file_path): # pragma: no cover - app.logger.error("File does not exist.") - elif choice: - app.logger.info(f"Choke type {choice}.") - app.logger.info(f"File: {file_path}.") - else: - app.logger.error("No parameter selected.") + active_project = app.active_project() + active_design = app.active_design() + + project_name = active_project.GetName() + design_name = active_design.GetName() + + hfss = Hfss(project_name, design_name) + + hfss.solution_type = "Terminal" + + # Create temporary directory for JSON file + temp_dir = tempfile.mkdtemp() + json_path = os.path.join(temp_dir, "choke_params.json") + + write_configuration_file(choke_config, json_path) + + # Verify parameters + dictionary_values = hfss.modeler.check_choke_values(json_path, create_another_file=False) + + # Create choke geometry + list_object = hfss.modeler.create_choke(json_path) + + # Get core and winding objects + core = list_object[1] + first_winding_list = list_object[2] + + # Get second winding list if it exists + second_winding_list = list_object[3] if len(list_object) > 3 else None + + # Create ground plane + ground_radius = 1.2 * dictionary_values[1]["Outer Winding"]["Outer Radius"] + ground_position = [0, 0, first_winding_list[1][0][2] - 2] + ground = hfss.modeler.create_circle("XY", ground_position, ground_radius, name="GND", material="copper") + hfss.assign_coating(ground, is_infinite_ground=True) + ground.transparency = 0.9 + + # Create mesh operation + cylinder_height = 2.5 * dictionary_values[1]["Outer Winding"]["Height"] + cylinder_position = [0, 0, first_winding_list[1][0][2] - 4] + mesh_operation_cylinder = hfss.modeler.create_cylinder( + "XY", + cylinder_position, + ground_radius, + cylinder_height, + num_sides=36, + name="mesh_cylinder", + ) + + # Create port positions list based on available windings + port_position_list = [ + # First winding start position + [ + first_winding_list[1][0][0], + first_winding_list[1][0][1], + first_winding_list[1][0][2] - 1, + ], + # First winding end position + [ + first_winding_list[1][-1][0], + first_winding_list[1][-1][1], + first_winding_list[1][-1][2] - 1, + ], + ] + + # Add second winding ports if it exists + if second_winding_list: + port_position_list.extend( + [ + # Second winding start position + [ + second_winding_list[1][0][0], + second_winding_list[1][0][1], + second_winding_list[1][0][2] - 1, + ], + # Second winding end position + [ + second_winding_list[1][-1][0], + second_winding_list[1][-1][1], + second_winding_list[1][-1][2] - 1, + ], + ] + ) + + # Port dimensions + wire_diameter = dictionary_values[1]["Outer Winding"]["Wire Diameter"] + port_dimension_list = [2, wire_diameter] + + # Create lumped ports + for i, position in enumerate(port_position_list): + # Create port sheet + sheet = hfss.modeler.create_rectangle("XZ", position, port_dimension_list, name=f"sheet_port_{i + 1}") + + # Move sheet to correct position relative to wire + sheet.move([-wire_diameter / 2, 0, -1]) + + # Create lumped port + hfss.lumped_port( + assignment=sheet.name, + name=f"port_{i + 1}", + reference=[ground], + ) + + # Assign mesh operation + hfss.mesh.assign_length_mesh( + [mesh_operation_cylinder], + maximum_length=15, + maximum_elements=None, + name="choke_mesh", + ) + + # Create region + region = hfss.modeler.create_region(pad_percent=1000) + + # Create setup + setup = hfss.create_setup("Setup1") + setup.props["Frequency"] = "50MHz" + setup["MaximumPasses"] = 10 + + # Create frequency sweep + hfss.create_linear_count_sweep( + setup=setup.name, + units="MHz", + start_frequency=0.1, + stop_frequency=100, + num_of_freq_points=100, + name="sweep1", + sweep_type="Interpolating", + save_fields=False, + ) + + # Save project + hfss.save_project() + + if os.path.exists(temp_dir): + shutil.rmtree(temp_dir, ignore_errors=True) if not extension_args["is_test"]: # pragma: no cover app.release_desktop(False, False) @@ -228,5 +433,6 @@ def main(extension_args): for output_name, output_value in output.items(): if output_name in extension_arguments: args[output_name] = output_value - - main(args) + main(args) + else: + main(args) From 76a4edf62113d1061f429475ca3068c8c6aa0b68 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Wed, 20 Nov 2024 11:05:09 +0100 Subject: [PATCH 03/26] Fix radio buttons --- .../aedt/core/modeler/cad/primitives_3d.py | 5 + .../core/workflows/hfss/choke_designer.py | 100 +++++++++++++----- .../choke_1winding_1Layer.json | 3 +- 3 files changed, 81 insertions(+), 27 deletions(-) diff --git a/src/ansys/aedt/core/modeler/cad/primitives_3d.py b/src/ansys/aedt/core/modeler/cad/primitives_3d.py index adb0d5d72d1..f96c19ecada 100644 --- a/src/ansys/aedt/core/modeler/cad/primitives_3d.py +++ b/src/ansys/aedt/core/modeler/cad/primitives_3d.py @@ -2489,6 +2489,11 @@ def create_choke(self, input_file): with open_file(input_file, "r") as read_file: values = json.load(read_file) + + # Change units + if "Settings" in values and "Units" in values["Settings"]: + self.model_units = values["Settings"]["Units"] + self.logger.info("CHOKE INFO: " + str(values)) sr = 1.1 # security factor diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 284abab042a..99fd9875e41 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -77,6 +77,7 @@ "Coil Pit(deg)": 0.1, "Occupation(%)": 0, }, + "Settings": {"Units": "mm"}, } # Extension batch arguments @@ -105,7 +106,7 @@ def frontend(): # pragma: no cover master.geometry("900x800") - master.title("HFSS Choke designer") + master.title("Choke designer") # Detect if user close the UI master.flag = False @@ -133,27 +134,33 @@ def frontend(): # pragma: no cover left_frame = ttk.Frame(main_frame, width=350) main_frame.add(left_frame, weight=1) + selected_options = {} + def create_boolean_options(parent, config): + for category, options in config.items(): - if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): - group_frame = ttk.LabelFrame(parent, text=category) - group_frame.pack(fill=tkinter.X, padx=10, pady=5) - - selected_option = tkinter.StringVar(value=next((opt for opt, val in options.items() if val), "")) - - def on_toggle(cat, opt): - for key in config[cat]: - config[cat][key] = key == opt - - for option, value in options.items(): - btn = ttk.Radiobutton( - group_frame, - text=option, - variable=selected_option, - value=option, - command=lambda opt=option: on_toggle(category, opt), + if category in ["Number of Windings", "Layer", "Layer Type", "Similar Layer", "Mode"]: + if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): + group_frame = ttk.LabelFrame(parent, text=category) + group_frame.pack(fill=tkinter.X, padx=10, pady=5) + + selected_options[category] = tkinter.StringVar( + value=next((opt for opt, val in options.items() if val), "") ) - btn.pack(anchor=tkinter.W, padx=5) + + def update_config(cat, selected_option_u): + for key in config[cat]: + config[cat][key] = key == selected_option_u.get() + + for option, value in options.items(): + btn = ttk.Radiobutton( + group_frame, + text=option, + variable=selected_options[category], + value=option, + command=lambda cat=category: update_config(cat, selected_options[cat]), + ) + btn.pack(anchor=tkinter.W, padx=5) create_boolean_options(left_frame, config_dict) @@ -161,6 +168,8 @@ def on_toggle(cat, opt): right_frame = ttk.Notebook(master) main_frame.add(right_frame, weight=3) + entries_dict = {} + def create_parameter_inputs(parent, config, category): def update_config(cat, field, entry_widget): """ @@ -188,11 +197,13 @@ def update_config(cat, field, entry_widget): entry.insert(0, str(value)) entry.pack(side=tkinter.LEFT, padx=5) + entries_dict[(category, field)] = entry + # Bind the `update_config` function to changes in the Entry widget entry.bind("", lambda e, cat=category, fld=field, widget=entry: update_config(cat, fld, widget)) # Parameters - for tab_name in ["Core", "Outer Winding", "Mid Winding", "Inner Winding"]: + for tab_name in ["Core", "Outer Winding", "Mid Winding", "Inner Winding", "Settings"]: tab = ttk.Frame(right_frame) right_frame.add(tab, text=tab_name) create_parameter_inputs(tab, config_dict, tab_name) @@ -240,13 +251,42 @@ def load_configuration(): if not validate_configuration(new_config): messagebox.showerror("Validation Error", "Please fix configuration errors before loading.") return - for key in config: - if key in new_config: - config[key] = new_config[key] - messagebox.showinfo("Success", "Configuration saved successfully.") + for key in new_config: + if key in config_dict: + config_dict[key] = new_config[key] + update_radio_buttons() + update_entries() + messagebox.showinfo("Success", "Configuration loaded successfully.") except Exception as e: messagebox.showerror("Error", f"Failed to save configuration: {str(e)}") + def update_radio_buttons(): + """ + Update the Radiobuttons with the values from config_dict. + """ + for category, options in config_dict.items(): + if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): + # Get the selected option from config_dict + selected_option = next((opt for opt, val in options.items() if val), "") + + # Update the StringVar for the category (to reflect the new value) + if category in selected_options: + selected_options[category].set(selected_option) + + def update_entries(): + """ + Update the Entry widgets with the values from config_dict. + """ + for category, options in config_dict.items(): + for field, value in options.items(): + # Find the entry widget for this field and category + entry_widget = entries_dict.get((category, field)) # Assuming you stored entry widgets in a dictionary + + if entry_widget: + # Update the value of the Entry widget with the new value from config_dict + entry_widget.delete(0, tkinter.END) # Clear current value + entry_widget.insert(0, str(value)) # Insert the new value + button_frame = ttk.Frame(master) button_frame.pack(fill=tkinter.X, pady=5) @@ -283,12 +323,20 @@ def main(extension_args): ) active_project = app.active_project() + + hfss = None + if not active_project: + hfss = Hfss() + hfss.save_project() + active_project = app.active_project() + active_design = app.active_design() project_name = active_project.GetName() design_name = active_design.GetName() - hfss = Hfss(project_name, design_name) + if not hfss: + hfss = Hfss(project_name, design_name) hfss.solution_type = "Terminal" @@ -398,7 +446,7 @@ def main(extension_args): # Create setup setup = hfss.create_setup("Setup1") setup.props["Frequency"] = "50MHz" - setup["MaximumPasses"] = 10 + setup.props["MaximumPasses"] = 10 # Create frequency sweep hfss.create_linear_count_sweep( diff --git a/tests/system/general/example_models/choke_json_file/choke_1winding_1Layer.json b/tests/system/general/example_models/choke_json_file/choke_1winding_1Layer.json index 8094f7e28da..44af7f445a6 100644 --- a/tests/system/general/example_models/choke_json_file/choke_1winding_1Layer.json +++ b/tests/system/general/example_models/choke_json_file/choke_1winding_1Layer.json @@ -56,5 +56,6 @@ "Turns": 20, "Coil Pit(deg)": 3.8227, "Occupation(%)": 84.94888888888889 - } + }, + "Units": "mm" } \ No newline at end of file From 7f8c9dbb967fb6842c95bf65f21c956a0fb9a1e9 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Wed, 20 Nov 2024 15:56:03 +0100 Subject: [PATCH 04/26] Change theme Create component --- .../core/workflows/hfss/choke_designer.py | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 99fd9875e41..7a322f90a42 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -78,17 +78,13 @@ "Occupation(%)": 0, }, "Settings": {"Units": "mm"}, + "Create Component": {"True": True, "False": False}, } # Extension batch arguments extension_arguments = {"choke_config": {}} extension_description = "Choke Designer in HFSS" -theme = "light" -if os.environ.get("AEDT_TOOLKIT_THEME", False): - if os.environ.get("AEDT_TOOLKIT_THEME") == "dark": - theme = "dark" - def frontend(): # pragma: no cover @@ -139,7 +135,7 @@ def frontend(): # pragma: no cover def create_boolean_options(parent, config): for category, options in config.items(): - if category in ["Number of Windings", "Layer", "Layer Type", "Similar Layer", "Mode"]: + if category in ["Number of Windings", "Layer", "Layer Type", "Similar Layer", "Mode", "Create Component"]: if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): group_frame = ttk.LabelFrame(parent, text=category) group_frame.pack(fill=tkinter.X, padx=10, pady=5) @@ -260,40 +256,41 @@ def load_configuration(): except Exception as e: messagebox.showerror("Error", f"Failed to save configuration: {str(e)}") + def toggle_theme(): + current_theme = sv_ttk.get_theme() + if current_theme == "light": + sv_ttk.set_theme("dark") + change_theme_button.config(text="\U0001F319") # Cambiar a ícono de luna + else: + sv_ttk.set_theme("light") + change_theme_button.config(text="\u2600") # Cambiar a ícono de sol + def update_radio_buttons(): - """ - Update the Radiobuttons with the values from config_dict. - """ for category, options in config_dict.items(): if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): - # Get the selected option from config_dict selected_option = next((opt for opt, val in options.items() if val), "") - # Update the StringVar for the category (to reflect the new value) if category in selected_options: selected_options[category].set(selected_option) def update_entries(): - """ - Update the Entry widgets with the values from config_dict. - """ for category, options in config_dict.items(): for field, value in options.items(): - # Find the entry widget for this field and category - entry_widget = entries_dict.get((category, field)) # Assuming you stored entry widgets in a dictionary + entry_widget = entries_dict.get((category, field)) if entry_widget: - # Update the value of the Entry widget with the new value from config_dict - entry_widget.delete(0, tkinter.END) # Clear current value - entry_widget.insert(0, str(value)) # Insert the new value + entry_widget.delete(0, tkinter.END) + entry_widget.insert(0, str(value)) button_frame = ttk.Frame(master) button_frame.pack(fill=tkinter.X, pady=5) save_button = ttk.Button(button_frame, text="Save Configuration", command=save_configuration) load_button = ttk.Button(button_frame, text="Load Configuration", command=load_configuration) + change_theme_button = ttk.Button(button_frame, text="\u2600", command=toggle_theme) save_button.pack(side=tkinter.LEFT, padx=5) load_button.pack(side=tkinter.LEFT, padx=5) + change_theme_button.pack(side=tkinter.RIGHT, padx=5, pady=40) def callback(): master.flag = True @@ -302,7 +299,7 @@ def callback(): export_hfss = ttk.Button(button_frame, text="Export to HFSS", command=callback) export_hfss.pack(side=tkinter.LEFT, padx=5) - sv_ttk.set_theme(theme) + sv_ttk.set_theme("light") tkinter.mainloop() choke_config = {} @@ -333,7 +330,10 @@ def main(extension_args): active_design = app.active_design() project_name = active_project.GetName() - design_name = active_design.GetName() + + design_name = None + if active_design: + design_name = active_design.GetName() if not hfss: hfss = Hfss(project_name, design_name) @@ -363,7 +363,7 @@ def main(extension_args): ground_radius = 1.2 * dictionary_values[1]["Outer Winding"]["Outer Radius"] ground_position = [0, 0, first_winding_list[1][0][2] - 2] ground = hfss.modeler.create_circle("XY", ground_position, ground_radius, name="GND", material="copper") - hfss.assign_coating(ground, is_infinite_ground=True) + hfss.assign_coating(ground.name, is_infinite_ground=True) ground.transparency = 0.9 # Create mesh operation @@ -440,8 +440,12 @@ def main(extension_args): name="choke_mesh", ) + # Create 3D Component + if choke_config["Create Component"]["True"]: + _ = hfss.modeler.replace_3dcomponent() + # Create region - region = hfss.modeler.create_region(pad_percent=1000) + _ = hfss.modeler.create_region(pad_percent=1000) # Create setup setup = hfss.create_setup("Setup1") From e421733adff3fcc33c47727a7f8be942d9d968ba Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Wed, 27 Nov 2024 08:44:42 +0100 Subject: [PATCH 05/26] New extension style --- pyproject.toml | 3 +- .../core/workflows/hfss/choke_designer.py | 59 +++++---- .../hfss3dlayout/images/large/push.png | Bin 0 -> 1987 bytes src/ansys/aedt/core/workflows/misc.py | 117 ++++++++++++++++++ 4 files changed, 155 insertions(+), 24 deletions(-) create mode 100644 src/ansys/aedt/core/workflows/hfss3dlayout/images/large/push.png diff --git a/pyproject.toml b/pyproject.toml index f8507da8e0c..9694d99825c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,8 +42,7 @@ dependencies = [ "pytomlpp; python_version < '3.12'", "rpyc>=6.0.0,<6.1", "pyyaml", - "defusedxml>=0.7,<8.0", - "sv-ttk" + "defusedxml>=0.7,<8.0" ] [project.optional-dependencies] diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 7a322f90a42..4b689b8c875 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -95,7 +95,7 @@ def frontend(): # pragma: no cover import PIL.Image import PIL.ImageTk - import sv_ttk + from ansys.aedt.core.workflows.misc import ExtensionTheme # Create UI master = tkinter.Tk() @@ -117,17 +117,20 @@ def frontend(): # pragma: no cover # Configure style for ttk buttons style = ttk.Style() - style.configure("Toolbutton.TButton", padding=6, font=("Helvetica", 8)) + theme = ExtensionTheme() + + theme.apply_light_theme(style) + master.theme = "light" # Load initial configuration config_dict = default_config.copy() # Main panel - main_frame = ttk.PanedWindow(master, orient=tkinter.HORIZONTAL) + main_frame = ttk.PanedWindow(master, orient=tkinter.HORIZONTAL, style="TPanedwindow") main_frame.pack(fill=tkinter.BOTH, expand=True) # Left panel - left_frame = ttk.Frame(main_frame, width=350) + left_frame = ttk.Frame(main_frame, width=350, style="PyAEDT.TFrame") main_frame.add(left_frame, weight=1) selected_options = {} @@ -137,7 +140,7 @@ def create_boolean_options(parent, config): for category, options in config.items(): if category in ["Number of Windings", "Layer", "Layer Type", "Similar Layer", "Mode", "Create Component"]: if isinstance(options, dict) and all(isinstance(v, bool) for v in options.values()): - group_frame = ttk.LabelFrame(parent, text=category) + group_frame = ttk.LabelFrame(parent, text=category, style="PyAEDT.TLabelframe") group_frame.pack(fill=tkinter.X, padx=10, pady=5) selected_options[category] = tkinter.StringVar( @@ -154,6 +157,7 @@ def update_config(cat, selected_option_u): text=option, variable=selected_options[category], value=option, + style="PyAEDT.TRadiobutton", command=lambda cat=category: update_config(cat, selected_options[cat]), ) btn.pack(anchor=tkinter.W, padx=5) @@ -161,7 +165,7 @@ def update_config(cat, selected_option_u): create_boolean_options(left_frame, config_dict) # Right panel - right_frame = ttk.Notebook(master) + right_frame = ttk.Notebook(master, style="TNotebook") main_frame.add(right_frame, weight=3) entries_dict = {} @@ -183,10 +187,10 @@ def update_config(cat, field, entry_widget): pass # Ignore invalid input for field, value in config[category].items(): - frame = ttk.Frame(parent) + frame = ttk.Frame(parent, style="PyAEDT.TFrame") frame.pack(fill=tkinter.X, padx=10, pady=2) - label = ttk.Label(frame, text=field, width=20) + label = ttk.Label(frame, text=field, width=20, style="PyAEDT.TLabel") label.pack(side=tkinter.LEFT) entry = ttk.Entry(frame, width=15) @@ -200,7 +204,7 @@ def update_config(cat, field, entry_widget): # Parameters for tab_name in ["Core", "Outer Winding", "Mid Winding", "Inner Winding", "Settings"]: - tab = ttk.Frame(right_frame) + tab = ttk.Frame(right_frame, style="PyAEDT.TFrame") right_frame.add(tab, text=tab_name) create_parameter_inputs(tab, config_dict, tab_name) @@ -257,13 +261,20 @@ def load_configuration(): messagebox.showerror("Error", f"Failed to save configuration: {str(e)}") def toggle_theme(): - current_theme = sv_ttk.get_theme() - if current_theme == "light": - sv_ttk.set_theme("dark") - change_theme_button.config(text="\U0001F319") # Cambiar a ícono de luna + if master.theme == "light": + set_dark_theme() + master.theme = "dark" else: - sv_ttk.set_theme("light") - change_theme_button.config(text="\u2600") # Cambiar a ícono de sol + set_light_theme() + master.theme = "light" + + def set_light_theme(): + theme.apply_light_theme(style) + change_theme_button.config(text="\u263D") + + def set_dark_theme(): + theme.apply_dark_theme(style) + change_theme_button.config(text="\u2600") def update_radio_buttons(): for category, options in config_dict.items(): @@ -282,12 +293,16 @@ def update_entries(): entry_widget.delete(0, tkinter.END) entry_widget.insert(0, str(value)) - button_frame = ttk.Frame(master) - button_frame.pack(fill=tkinter.X, pady=5) + button_frame = ttk.Frame(master, style="PyAEDT.TFrame", relief=tkinter.SUNKEN, borderwidth=2) + button_frame.pack(fill=tkinter.X, pady=0) - save_button = ttk.Button(button_frame, text="Save Configuration", command=save_configuration) - load_button = ttk.Button(button_frame, text="Load Configuration", command=load_configuration) - change_theme_button = ttk.Button(button_frame, text="\u2600", command=toggle_theme) + save_button = ttk.Button( + button_frame, text="Save Configuration", command=save_configuration, style="PyAEDT.TButton" + ) + load_button = ttk.Button( + button_frame, text="Load Configuration", command=load_configuration, style="PyAEDT.TButton" + ) + change_theme_button = ttk.Button(button_frame, text="\u263D", command=toggle_theme, style="PyAEDT.TButton") save_button.pack(side=tkinter.LEFT, padx=5) load_button.pack(side=tkinter.LEFT, padx=5) change_theme_button.pack(side=tkinter.RIGHT, padx=5, pady=40) @@ -297,9 +312,9 @@ def callback(): if validate_configuration(config_dict): master.destroy() - export_hfss = ttk.Button(button_frame, text="Export to HFSS", command=callback) + export_hfss = ttk.Button(button_frame, text="Export to HFSS", command=callback, style="PyAEDT.TButton") export_hfss.pack(side=tkinter.LEFT, padx=5) - sv_ttk.set_theme("light") + tkinter.mainloop() choke_config = {} diff --git a/src/ansys/aedt/core/workflows/hfss3dlayout/images/large/push.png b/src/ansys/aedt/core/workflows/hfss3dlayout/images/large/push.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb7c639efbcd451615c5c23b2e8d40d9207fc18 GIT binary patch literal 1987 zcmV;!2R!(RP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vG&=l}pD=mCOb1snhX2Utl&K~z{ry;s+k z+c*;S|Nqs#?1Sy;b}L7UIcG756v4Z|htbf`g1{9zcTvG4n7oOv^Urss8`&objU%2CrelRWPx5aF5tly0Ci zblk>nQk@9ODC;uLyqQ1K^SaPynR)%0C+`!0f+`o=)NM-u4s7Ea-qaH6{`gRC@OL#Z zuRrtTeFAXf&BYJIUZWkrvc6-hc9Xz_o=69R83&F(c@xo0GM_hny#HAnpVyyx^8RiD z#X~Ck!RUpslMOVbp;hfeWmSWAXmR5lBZ0_|CX@}vpEQt^B7dTXdd14~T*-mLBXj1- zWCC!#UMKGq?^mu5t31H$brhh4f4YwX)KPU-}`QMd&m)WyU`ZDF+)j^rsiZ(2Gy zQgf%PLY!9^5A=L>=3YLwH9?v-I?usQZD7=Qxb063i0b1cL7nBe`vl83w|J`uhINWzx5d6&VA)w%R2>pMMDA{2-VS)_ zLpVW$>f*u=7X)Qv-PQ1o1dV-yQ>-cDLeDzn{4VmAI1d-R-E)|G?*X7`8bnEqIwB=5 z0W6poB77A9MvfwP5ab7JZyBtLn|oJ;`5u1l@OCM}s6rBD@UkVeF306|r3Ol*xrwkm zV|B~n&x$01(D88b8D}v3c7KvLwa2j}bZr+}cBIEwJbc_=OMG ztEZbqiH|>q0I40qWE6$LE6#NZz4Z|2Il<~kgEPM06GWj0hXB0v4Q`%cGx#{~-47Fp z$JTVLvWV%u9Nm{niz0$_)8O3md<1T@d0 zGZ=9WzR2M*)o;2s7FmQ$6-e?ELaSuxoRF9v4+-eKCv2|-5G`QxCgR z+P=c6JW?|RFh(eCgL67x_yRM%;@IiPc*`?mymU@@p;ILZV?L;17b||3F(h4-yugu8 zn7MD*^Bk)>BQQ#uNkE0khEHl^(v)VG75Cm6iyiSLjtq z01l!{3X_qLd3${CGsLM2$FJaK3xsJ*&3Ob#2fd~==___^35)VR0SJ&XB>=g(lwyzl zKz42MpZ0{FDl@eRk$<8+&)CrWuU`{>o%yTsx#jjKp8V=r!_UhHQn#^58MKt*Mdyt)&TKT-^i0 z+I#?z$|Qau<~F(HPIWDc!D`J8Yk|gRPa;FtzpuwoKEd z=HO~>u^rb;(*?AMeZ@|r`PTHW6PBzAp&g++ZQ%BFLIIGl4oI8SHuPW$)ct@<+Cbep zG(!Ws>F`=A)`W-MHfn_(=T=6U)d8pBh-1(6%G`c4Ec6#03$=X7gbJsn=~y4cu64`VnR;U;)NV<~Hv;eoAigPhES2I5kD5Qw zE^H|HE;QBi2@I>C93V{y51r@lGO{-Fr34kOb!!RaOR4huO3F(xDBsh~%gBEY`Tm(NBt>unAnHh2Fl^g?NB&HLR@1a;lV7dN z#@p?78h^F!v(uJ8rn4EO2N9>2eZR~?^Yi@SGtJNM*5vu!y1dK5mSs)^z{{UIo VT`|B^wXXmG002ovPDHLkV1mLSy5|4@ literal 0 HcmV?d00001 diff --git a/src/ansys/aedt/core/workflows/misc.py b/src/ansys/aedt/core/workflows/misc.py index 8bc29409882..0c6c934f3e2 100644 --- a/src/ansys/aedt/core/workflows/misc.py +++ b/src/ansys/aedt/core/workflows/misc.py @@ -76,6 +76,123 @@ def get_arguments(args=None, description=""): # pragma: no cover return output_args +class ExtensionTheme: # pragma: no cover + def __init__(self): + # Define light and dark theme colors + self.light = { + "widget_bg": "#FFFFFF", + "text": "#000000", + "button_bg": "#E6E6E6", + "button_hover_bg": "#D9D9D9", + "button_active_bg": "#B8B8B8", + "tab_bg_inactive": "#F0F0F0", + "tab_bg_active": "#FFFFFF", + "tab_border": "#D9D9D9", + "label_bg": "#FFFFFF", + "label_fg": "#000000", + "labelframe_bg": "#FFFFFF", + "labelframe_fg": "#000000", + "labelframe_title_bg": "#FFFFFF", # Background for title (text) + "labelframe_title_fg": "#000000", # Text color for title + "radiobutton_bg": "#FFFFFF", # Background for Radiobutton + "radiobutton_fg": "#000000", # Text color for Radiobutton + "radiobutton_selected": "#E0E0E0", # Color when selected + "radiobutton_unselected": "#FFFFFF", # Color when unselected + "pane_bg": "#F0F0F0", # Background for PanedWindow + "sash_color": "#C0C0C0", # Color for sash (separator) in PanedWindo + } + + self.dark = { + "widget_bg": "#3C3C3C", + "text": "#FFFFFF", + "button_bg": "#4D4D4D", + "button_hover_bg": "#606060", + "button_active_bg": "#808080", + "tab_bg_inactive": "#2E2E2E", + "tab_bg_active": "#3C3C3C", + "tab_border": "#505050", + "label_bg": "#3C3C3C", # Background for labels + "label_fg": "#FFFFFF", # Text color for labels + "labelframe_bg": "#3C3C3C", # Background for LabelFrame + "labelframe_fg": "#FFFFFF", # Text color for LabelFrame + "labelframe_title_bg": "#3C3C3C", # Dark background for title (text) + "labelframe_title_fg": "#FFFFFF", # Dark text color for title + "radiobutton_bg": "#2E2E2E", # Background for Radiobutton + "radiobutton_fg": "#FFFFFF", # Text color for Radiobutton + "radiobutton_selected": "#2E2E2E", # Color when selected + "radiobutton_unselected": "#3C3C3C", # Color when unselected + "pane_bg": "#2E2E2E", # Background for PanedWindow + } + + # Set default font + self.default_font = ("Helvetica", 10) + + def apply_light_theme(self, style): + self._apply_theme(style, self.light) + + def apply_dark_theme(self, style): + self._apply_theme(style, self.dark) + + def _apply_theme(self, style, colors): + # Apply the colors and font to the style + style.theme_use("clam") + + style.configure("TPanedwindow", background=colors["pane_bg"]) + + style.configure( + "PyAEDT.TButton", background=colors["button_bg"], foreground=colors["text"], font=self.default_font + ) + + # Apply the color for hover and active states + style.map( + "PyAEDT.TButton", + background=[("active", colors["button_active_bg"]), ("!active", colors["button_hover_bg"])], + foreground=[("active", colors["text"]), ("!active", colors["text"])], + ) + + # Apply the color for hover and active states + + # Apply the colors and font to the style for Frames and Containers + style.configure("PyAEDT.TFrame", background=colors["widget_bg"]) + + # Apply the colors and font to the style for Tabs + style.configure("TNotebook", background=colors["tab_bg_inactive"], bordercolor=colors["tab_border"]) + style.configure("TNotebook.Tab", background=colors["tab_bg_inactive"], foreground=colors["text"]) + style.map("TNotebook.Tab", background=[("selected", colors["tab_bg_active"])]) + + # Apply the colors and font to the style for Labels + style.configure( + "PyAEDT.TLabel", background=colors["label_bg"], foreground=colors["label_fg"], font=self.default_font + ) + + # Apply the colors and font to the style for LabelFrames + style.configure( + "PyAEDT.TLabelframe", + background=colors["labelframe_bg"], + foreground=colors["labelframe_fg"], + font=self.default_font, + ) + style.configure( + "PyAEDT.TLabelframe.Label", # Specific style for the title text (label) + background=colors["labelframe_title_bg"], + foreground=colors["labelframe_title_fg"], + font=self.default_font, + ) + + # Apply the colors and font to the style for Radiobuttons + style.configure( + "PyAEDT.TRadiobutton", + background=colors["radiobutton_bg"], + foreground=colors["radiobutton_fg"], + font=self.default_font, + ) + + style.map( + "TRadiobutton", + background=[("selected", colors["radiobutton_selected"]), ("!selected", colors["radiobutton_unselected"])], + ) + + def __string_to_bool(v): # pragma: no cover """Change string to bool.""" if isinstance(v, str) and v.lower() in ("true", "1"): From 90fd4a6c976f82b825f33b9e0efe2833706874f8 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Wed, 27 Nov 2024 11:57:11 +0100 Subject: [PATCH 06/26] Change font --- src/ansys/aedt/core/workflows/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/aedt/core/workflows/misc.py b/src/ansys/aedt/core/workflows/misc.py index 0c6c934f3e2..0007a803391 100644 --- a/src/ansys/aedt/core/workflows/misc.py +++ b/src/ansys/aedt/core/workflows/misc.py @@ -125,7 +125,7 @@ def __init__(self): } # Set default font - self.default_font = ("Helvetica", 10) + self.default_font = ("Arial", 12) def apply_light_theme(self, style): self._apply_theme(style, self.light) From ae37b934505de69154f95c780ed40d5ed26a88db Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Wed, 27 Nov 2024 12:21:03 +0100 Subject: [PATCH 07/26] Improve font --- src/ansys/aedt/core/workflows/hfss/choke_designer.py | 2 +- src/ansys/aedt/core/workflows/misc.py | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 4b689b8c875..1483cca840e 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -193,7 +193,7 @@ def update_config(cat, field, entry_widget): label = ttk.Label(frame, text=field, width=20, style="PyAEDT.TLabel") label.pack(side=tkinter.LEFT) - entry = ttk.Entry(frame, width=15) + entry = ttk.Entry(frame, width=15, font=theme.default_font) entry.insert(0, str(value)) entry.pack(side=tkinter.LEFT, padx=5) diff --git a/src/ansys/aedt/core/workflows/misc.py b/src/ansys/aedt/core/workflows/misc.py index 0007a803391..00c152453f4 100644 --- a/src/ansys/aedt/core/workflows/misc.py +++ b/src/ansys/aedt/core/workflows/misc.py @@ -153,11 +153,15 @@ def _apply_theme(self, style, colors): # Apply the color for hover and active states # Apply the colors and font to the style for Frames and Containers - style.configure("PyAEDT.TFrame", background=colors["widget_bg"]) + style.configure("PyAEDT.TFrame", background=colors["widget_bg"], font=self.default_font) # Apply the colors and font to the style for Tabs - style.configure("TNotebook", background=colors["tab_bg_inactive"], bordercolor=colors["tab_border"]) - style.configure("TNotebook.Tab", background=colors["tab_bg_inactive"], foreground=colors["text"]) + style.configure( + "TNotebook", background=colors["tab_bg_inactive"], bordercolor=colors["tab_border"], font=self.default_font + ) + style.configure( + "TNotebook.Tab", background=colors["tab_bg_inactive"], foreground=colors["text"], font=self.default_font + ) style.map("TNotebook.Tab", background=[("selected", colors["tab_bg_active"])]) # Apply the colors and font to the style for Labels From a02e93dc8b035c8c29138a4271f045507abd5400 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 08:42:40 +0100 Subject: [PATCH 08/26] Add choke UT --- .../core/workflows/hfss/choke_designer.py | 20 +++++----- tests/system/solvers/test_45_workflows.py | 37 +++++++++++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 1483cca840e..27e8b8b977d 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -21,7 +21,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import os.path +from pathlib import Path import shutil import tempfile @@ -102,13 +102,13 @@ def frontend(): # pragma: no cover master.geometry("900x800") - master.title("Choke designer") + master.title("Choke Designer") # Detect if user close the UI master.flag = False # Load the logo for the main window - icon_path = os.path.join(ansys.aedt.core.workflows.__path__[0], "images", "large", "logo.png") + icon_path = Path(ansys.aedt.core.workflows.__path__[0]) / "images" / "large" / "logo.png" im = PIL.Image.open(icon_path) photo = PIL.ImageTk.PhotoImage(im) @@ -350,22 +350,22 @@ def main(extension_args): if active_design: design_name = active_design.GetName() - if not hfss: + if not hfss: # pragma: no cover hfss = Hfss(project_name, design_name) hfss.solution_type = "Terminal" # Create temporary directory for JSON file - temp_dir = tempfile.mkdtemp() - json_path = os.path.join(temp_dir, "choke_params.json") + temp_dir = Path(tempfile.mkdtemp()) + json_path = temp_dir / "choke_params.json" - write_configuration_file(choke_config, json_path) + write_configuration_file(choke_config, str(json_path)) # Verify parameters - dictionary_values = hfss.modeler.check_choke_values(json_path, create_another_file=False) + dictionary_values = hfss.modeler.check_choke_values(str(json_path), create_another_file=False) # Create choke geometry - list_object = hfss.modeler.create_choke(json_path) + list_object = hfss.modeler.create_choke(str(json_path)) # Get core and winding objects core = list_object[1] @@ -482,7 +482,7 @@ def main(extension_args): # Save project hfss.save_project() - if os.path.exists(temp_dir): + if temp_dir.exists(): shutil.rmtree(temp_dir, ignore_errors=True) if not extension_args["is_test"]: # pragma: no cover diff --git a/tests/system/solvers/test_45_workflows.py b/tests/system/solvers/test_45_workflows.py index df9ce3c1d34..016aef68a55 100644 --- a/tests/system/solvers/test_45_workflows.py +++ b/tests/system/solvers/test_45_workflows.py @@ -536,3 +536,40 @@ def test_16_arbitrary_waveport(self, local_scratch): assert os.path.isfile(os.path.join(temp_dir.name, "wave_port.a3dcomp")) temp_dir.cleanup() + + def test_17_choke_designer(self, local_scratch): + from ansys.aedt.core.workflows.hfss.choke_designer import main + + choke_config = { + "Number of Windings": {"1": True, "2": False, "3": False, "4": False}, + "Layer": {"Simple": True, "Double": False, "Triple": False}, + "Layer Type": {"Separate": True, "Linked": False}, + "Similar Layer": {"Similar": True, "Different": False}, + "Mode": {"Differential": True, "Common": False}, + "Wire Section": {"None": False, "Hexagon": False, "Octagon": False, "Circle": True}, + "Core": { + "Name": "Core", + "Material": "ferrite", + "Inner Radius": 20, + "Outer Radius": 30, + "Height": 10, + "Chamfer": 0.8, + }, + "Outer Winding": { + "Name": "Winding", + "Material": "copper", + "Inner Radius": 20, + "Outer Radius": 30, + "Height": 10, + "Wire Diameter": 1.5, + "Turns": 20, + "Coil Pit(deg)": 0.1, + "Occupation(%)": 0, + }, + "Mid Winding": {"Turns": 25, "Coil Pit(deg)": 0.1, "Occupation(%)": 0}, + "Inner Winding": {"Turns": 4, "Coil Pit(deg)": 0.1, "Occupation(%)": 0}, + "Settings": {"Units": "mm"}, + "Create Component": {"True": True, "False": False}, + } + extension_args = {"is_test": True, "choke_config": choke_config} + assert main(extension_args) From de6bbe2bacdc8d17d62f5d451c22047dcff7ae19 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 09:09:10 +0100 Subject: [PATCH 09/26] Add misc unit test --- src/ansys/aedt/core/workflows/misc.py | 14 +-- tests/unit/test_extension_misc.py | 122 ++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 tests/unit/test_extension_misc.py diff --git a/src/ansys/aedt/core/workflows/misc.py b/src/ansys/aedt/core/workflows/misc.py index 00c152453f4..09f0f52face 100644 --- a/src/ansys/aedt/core/workflows/misc.py +++ b/src/ansys/aedt/core/workflows/misc.py @@ -68,11 +68,15 @@ def get_arguments(args=None, description=""): # pragma: no cover output_args = {"is_batch": False, "is_test": False} if len(sys.argv) != 1: # pragma: no cover - parsed_args = __parse_arguments(args, description) - output_args["is_batch"] = True - for k, v in parsed_args.__dict__.items(): - if v is not None: - output_args[k] = __string_to_bool(v) + try: + parsed_args = __parse_arguments(args, description) + output_args["is_batch"] = True + for k, v in parsed_args.__dict__.items(): + if v is not None: + output_args[k] = __string_to_bool(v) + except SystemExit as e: + print(f"Argument parsing failed: {e}") + raise return output_args diff --git a/tests/unit/test_extension_misc.py b/tests/unit/test_extension_misc.py new file mode 100644 index 00000000000..9e8a4c89b6f --- /dev/null +++ b/tests/unit/test_extension_misc.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2024 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Test extension utilities functions. +""" + +import os +from unittest.mock import MagicMock +from unittest.mock import patch + +from ansys.aedt.core.workflows.misc import ExtensionTheme +from ansys.aedt.core.workflows.misc import __string_to_bool +from ansys.aedt.core.workflows.misc import get_aedt_version +from ansys.aedt.core.workflows.misc import get_arguments +from ansys.aedt.core.workflows.misc import get_port +from ansys.aedt.core.workflows.misc import get_process_id +from ansys.aedt.core.workflows.misc import is_student +import pytest + +DUMMY_ENV_VARS = { + "PYAEDT_SCRIPT_PROCESS_ID": "12345", + "PYAEDT_SCRIPT_PORT": "6789", + "PYAEDT_SCRIPT_VERSION": "3024.2", + "PYAEDT_STUDENT_VERSION": "True", +} + + +@pytest.fixture(scope="module", autouse=True) +def desktop(): + """Override the desktop fixture to DO NOT open the Desktop when running this test class""" + return + + +@pytest.fixture +def mock_env_vars(): + """Fixture to temporarily set environment variables.""" + with patch.dict(os.environ, DUMMY_ENV_VARS): + yield + + +def test_get_process_id(mock_env_vars): + assert get_process_id() == 12345 + + +def test_get_port(mock_env_vars): + assert get_port() == 6789 + + +def test_get_aedt_version(mock_env_vars): + assert get_aedt_version() == "3024.2" + + +def test_is_student(mock_env_vars): + assert is_student() is True + + +def test_get_arguments_with_default_values(): + """Test `get_arguments` when no command-line arguments are passed.""" + mock_argv = ["script_name"] + with patch("sys.argv", mock_argv): + result = get_arguments(args={"is_batch": False, "is_test": False}) + assert result["is_batch"] is False + assert result["is_test"] is False + + +def test_get_arguments_with_custom_values(): + """Test `get_arguments` with custom command-line arguments.""" + mock_argv = ["script_name", "--is_batch", "true", "--is_test", "false"] + with patch("sys.argv", mock_argv): + result = get_arguments(args={"is_batch": False, "is_test": False}) + assert result["is_batch"] is True + assert result["is_test"] is False + + +def test_get_arguments_with_invalid_arguments(): + """Test `get_arguments` with invalid command-line arguments.""" + mock_argv = ["script_name", "--invalid_arg", "true"] + with patch("sys.argv", mock_argv): + with pytest.raises(SystemExit): + get_arguments() + + +@pytest.mark.parametrize( + "input_value, expected", + [("true", True), ("false", False), ("1", True), ("0", False), (True, True), (False, False)], +) +def test_string_to_bool(input_value, expected): + assert __string_to_bool(input_value) == expected + + +def test_extension_theme(): + mock_style = MagicMock() + theme = ExtensionTheme() + + # Test light theme application + theme.apply_light_theme(mock_style) + mock_style.configure.assert_called() + + # Test dark theme application + theme.apply_dark_theme(mock_style) + mock_style.configure.assert_called() From 588b049a1addea8129c273f7449d59e556672f66 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 09:36:23 +0100 Subject: [PATCH 10/26] Add toolkit --- .../core/workflows/hfss/images/large/choke.png | Bin 0 -> 1722 bytes .../core/workflows/hfss/toolkits_catalog.toml | 7 +++++++ 2 files changed, 7 insertions(+) create mode 100644 src/ansys/aedt/core/workflows/hfss/images/large/choke.png diff --git a/src/ansys/aedt/core/workflows/hfss/images/large/choke.png b/src/ansys/aedt/core/workflows/hfss/images/large/choke.png new file mode 100644 index 0000000000000000000000000000000000000000..d3ce6e7aa5982041fe0b99e65d1dea08371670b0 GIT binary patch literal 1722 zcmV;r21WUaP)#s(W>u<_maemy?Rr0k935ovGB_u+~E zdlVjnxJX5$lTnn)t58_1?d|S5{+eR9wk?+CuO}kzARa1^sEKSUf}NtULnX@EljqM5 zOe`4fztdDyUbuSs-OC`zw&UHcU3#77{QX(`hjLZLiD%FDeP*({-_Inra@YY1J0uh< z+m3X!yi`(Ba-n&D-3tuE5K2V}NRmJ}5-ZT@w6CYr>8`T!J&MVDv+rb5p)7WQLLN$$ zp5RO5B28KCu|tQNexgyAs$@mdLg%KNNTt$9rqVE)Z1DPm5D0jLUZ)kUtvLvVTvqN4 z=H`V`MT+9`Gnr%qJvS75?$*Z47>=9}+PimxgbG zU~=d`-HtzB8HHHHMRBnV=9M)x@2km0<0-=7aNYgnFQd=IwyYj(g9M9Hy86(Cfrg84sqbM&^kv@Nf z_|f+VS|t+ci(o;4MRkqg+kGcHs}Hu+;l|iB%J#@ntJlIC2xHD@gF-1sMY$TOOctNr zxDSsffMY!eakR4q$z&RvZa+@-9>naD9TRtEZiW1gacqMF79LN~IW=d-)sb=Z^&CJB z6jGrGPWK){D3ZkRU$4Wy89+Ln#Ml?6`S(ZP4T05&$^>1eD4W@OgaP8oP_$V+YY_(4(il8B0qR6iEv)erFcZL>8$O zjZButip36_#rEk|H2!8L?qjeG5-cKtm0)LkbFi_Y683cuOv_f>pISsX9EQ^yLI0U< za40}3=A*5p9+!r$fyd*60f}%V2CqK|iBt@=N@0n6mvUf1A`gn9a$GJKZ@={lGU+U= zHW#e64WyEB+?!s)ZjB0Ge7%U_k*|Is;c|IF5i}|*%fX>YaCltgLm`jD?Hw0$ z3}g>XYq@3u0e=C3r#+78gw5^SQ{; zxW8sKj(`ORdC)nA$Yg1}{NgeE{8u00oZ-kJf@r@=uG#WJ+ zl7wk_1Cd|=jr$ESnU;}b7zTMzU?DBl3mXj8Z{`4z-M)!eUwIzaKmQ6t!`G1mfu{Yn zXltp5wp;~&B#8y%8XhbzLs=q$MytWhv=KZ$7tv^Z&9xC8W|$bZLxDv{XU{u^y}IKr zZvg$LkKhlN{)V$p_uy<_JN*72u8odkWOM=(cjge@3ZY7?Mty@GkwgY&;|l8QYvA<- zP+BZAI5vIrsf5pnZE(P%T%)K{%4N8A{WfllP2%EUKYsK3E1($yogD}8+II)QrAWBl zUQ8S9Fq-X{doYC}u>eiYdoed>M!*-qiJn$WPR-Ya{n!=pwh?Uw<%! zU?_%H2hSmyNaF7!w{ZE&KM_l$@oxkeRFtc6fg zz#^S16qXbhJ?#oah+?q-p>Py8C+4u>bmM4uE1o~ojkA3nXxgWTq)3VkLtx2l$Esxw zN`(yJXaXdMi}?j}+-9}^G@bA{u?+%w$draR8k_dMx2sT)tJYVL1PBO)JbW}X0+mV* ziMRmCR0dn&IAYN#s&!h(m8Ebv+^||~ZeBrw!fvs4gnTRGU_l`du~b>w@>Iif*G9)* zipNt@g5p#$G>vd1f%ks)1H@wq=ql8xt}4T=u}K&jYGGSlXJ)46-y#@dq`pqqwZ6Xb zb|UJJfCYs-ViAwY=?c8-cbVp52`;0rsd#R4)9a;ans=bNj*^uWV`6$48}2QTxoq0u zaQj6fp_fqf8lW~XYdd~GI5e5vR{5Vp(QDf_D>&P9nzHT zX|%1{>2=%2kbiUif=E*Qt(qF``!r26cqr&H()eGIlvWYD6b3aO;c!Jn|2JQb=o{LH z@JNxOmLpRd6nG3A>`>TiVE{Ps9~?2`bb9_6k0-vyBU|pJEC4s2c;Yeq3z{42i2d;a QKmY&$07*qoM6N<$f*P Date: Thu, 28 Nov 2024 09:40:44 +0100 Subject: [PATCH 11/26] Replace RunProgram. Stability issues in 2025R1 --- .../run_pyaedt_toolkit_script.py_build | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build b/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build index aa624beffdc..c511dfaa66f 100644 --- a/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build +++ b/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build @@ -63,23 +63,10 @@ def main(): # Add environment variables pyaedt_utils.environment_variables(oDesktop) # Run workflow - if pyaedt_utils.is_linux: - pyaedt_utils.set_ansys_em_environment(oDesktop) - my_env = dict(os.environ.copy()) - command = [python_exe, pyaedt_script] - subprocess.Popen(command, env=my_env) - else: - toolkit_name = r"##TOOLKIT_NAME##" - runme = "run_pyaedt_toolkit_{0}.cmd".format(toolkit_name) - edt_temp = oDesktop.GetTempDirectory() - cmd = '"{0}"'.format(pyaedt_script) - target = os.path.join(edt_temp, runme) - my_env = dict(os.environ.copy()) - with open(target, 'w') as cmdfile: - for env in my_env: - cmdfile.write('SET {0}={1}\n'.format(env, my_env[env])) - cmdfile.write('"{0}" {1}\n'.format(python_exe, cmd)) - oDesktop.RunProgram(runme, edt_temp, edt_temp, "") + pyaedt_utils.set_ansys_em_environment(oDesktop) + my_env = dict(os.environ.copy()) + command = [python_exe, pyaedt_script] + subprocess.Popen(command, env=my_env) except Exception as e: pyaedt_utils.show_error(str(e), oDesktop) From e28cdf452de0423eb80940ae3c53c677237bcbdf Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 09:44:49 +0100 Subject: [PATCH 12/26] Replace RunProgram. Stability issues in 2025R1 --- .../core/workflows/templates/run_pyaedt_toolkit_script.py_build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build b/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build index c511dfaa66f..9eb6c460899 100644 --- a/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build +++ b/src/ansys/aedt/core/workflows/templates/run_pyaedt_toolkit_script.py_build @@ -33,6 +33,8 @@ is_linux = os.name == "posix" if is_linux: import subprocessdotnet as subprocess +else: + import subprocess toolkits_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) From dd9188e43783144f1191a21e283280b446c2b3e3 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 11:00:58 +0100 Subject: [PATCH 13/26] Merge run_pyaedt_toolkit_script template because it is equivalent to pyedb now without RunProgram --- .../workflows/circuit/toolkits_catalog.toml | 2 +- .../hfss3dlayout/toolkits_catalog.toml | 6 +- .../workflows/project/toolkits_catalog.toml | 2 +- .../run_pyedb_toolkit_script.py_build | 77 ------------------- .../hfss3dlayout/toolkits_catalog.toml | 4 +- .../workflows/project/toolkits_catalog.toml | 2 +- 6 files changed, 8 insertions(+), 85 deletions(-) delete mode 100644 src/ansys/aedt/core/workflows/templates/run_pyedb_toolkit_script.py_build diff --git a/src/ansys/aedt/core/workflows/circuit/toolkits_catalog.toml b/src/ansys/aedt/core/workflows/circuit/toolkits_catalog.toml index df49448e0ab..1b4c9371cb5 100644 --- a/src/ansys/aedt/core/workflows/circuit/toolkits_catalog.toml +++ b/src/ansys/aedt/core/workflows/circuit/toolkits_catalog.toml @@ -2,5 +2,5 @@ name = "Schematic Importer" script = "import_schematic.py" icon = "images/large/schematic.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" diff --git a/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml b/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml index f2c1e3e473a..eec0a9e881c 100644 --- a/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml +++ b/src/ansys/aedt/core/workflows/hfss3dlayout/toolkits_catalog.toml @@ -16,21 +16,21 @@ pip = "" name = "Export Layout info" script = "export_layout.py" icon = "images/large/export.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" [Cutout] name = "Advanced cutout" script = "cutout.py" icon = "images/large/cutout.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" [Parametrize] name = "Parametrize layout" script = "parametrize_edb.py" icon = "images/large/parametrize.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" [ArbitraryWaveport] diff --git a/src/ansys/aedt/core/workflows/project/toolkits_catalog.toml b/src/ansys/aedt/core/workflows/project/toolkits_catalog.toml index 6974adca284..8a77bd4ac81 100644 --- a/src/ansys/aedt/core/workflows/project/toolkits_catalog.toml +++ b/src/ansys/aedt/core/workflows/project/toolkits_catalog.toml @@ -16,7 +16,7 @@ pip = "" name = "Configure layout" script = "configure_edb.py" icon = "images/large/aedb.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" [FieldsCalculator] diff --git a/src/ansys/aedt/core/workflows/templates/run_pyedb_toolkit_script.py_build b/src/ansys/aedt/core/workflows/templates/run_pyedb_toolkit_script.py_build deleted file mode 100644 index a08cc97e06d..00000000000 --- a/src/ansys/aedt/core/workflows/templates/run_pyedb_toolkit_script.py_build +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -""" -* * * This script is meant to run in IronPython within AEDT. * * * - -The script executes the PyAEDT workflow. - -""" -import os -import sys - -is_linux = os.name == "posix" - -if is_linux: - import subprocessdotnet as subprocess -else: - import subprocess - -toolkits_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) - -sys.path.append(toolkits_dir) - -import pyaedt_utils - - -def main(): - try: - # Get AEDT version - short_version = oDesktop.GetVersion()[2:6].replace(".", "") - oDesktop.AddMessage("", "", 0, "Toolkit launched. Wait.") - # CPython interpreter - python_exe = r"##PYTHON_EXE##" - # Python script - pyaedt_script = r"##PYTHON_SCRIPT##" - # Check if CPython interpreter and AEDT release match - python_exe = pyaedt_utils.sanitize_interpreter_path(python_exe, short_version) - # Check python executable - python_exe_flag = pyaedt_utils.check_file(python_exe, oDesktop) - if not python_exe_flag: - return - # Check script file - pyaedt_script_flag = pyaedt_utils.check_file(pyaedt_script, oDesktop) - if not pyaedt_script_flag: - return - # Add environment variables - pyaedt_utils.environment_variables(oDesktop) - # Run workflow - my_env = dict(os.environ.copy()) - command = [python_exe, pyaedt_script] - pyaedt_utils.set_ansys_em_environment(oDesktop) - subprocess.Popen(command, env=my_env) - except Exception as e: - pyaedt_utils.show_error(str(e), oDesktop) - - -if __name__ == "__main__": - main() diff --git a/src/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml b/src/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml index 58893164913..da4a75d9425 100644 --- a/src/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml +++ b/src/pyaedt/workflows/hfss3dlayout/toolkits_catalog.toml @@ -16,12 +16,12 @@ pip = "" name = "Export Layout info" script = "export_layout.py" icon = "images/large/export.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" [Cutout] name = "Advanced cutout" script = "cutout.py" icon = "images/large/cutout.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" \ No newline at end of file diff --git a/src/pyaedt/workflows/project/toolkits_catalog.toml b/src/pyaedt/workflows/project/toolkits_catalog.toml index 6974adca284..8a77bd4ac81 100644 --- a/src/pyaedt/workflows/project/toolkits_catalog.toml +++ b/src/pyaedt/workflows/project/toolkits_catalog.toml @@ -16,7 +16,7 @@ pip = "" name = "Configure layout" script = "configure_edb.py" icon = "images/large/aedb.png" -template = "run_pyedb_toolkit_script" +template = "run_pyaedt_toolkit_script" pip = "" [FieldsCalculator] From 31beeb7f7dc950df1900d98641e06fe9fcec60ee Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 12:04:44 +0100 Subject: [PATCH 14/26] Import ansys.aedt.core --- .../aedt/core/workflows/installer/console_setup.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ansys/aedt/core/workflows/installer/console_setup.py b/src/ansys/aedt/core/workflows/installer/console_setup.py index 3045a6336cd..48d5f81d1eb 100644 --- a/src/ansys/aedt/core/workflows/installer/console_setup.py +++ b/src/ansys/aedt/core/workflows/installer/console_setup.py @@ -54,14 +54,14 @@ sys.path.append(os.path.join(console_setup_dir, "../..", "..", "..")) if version <= "2023.1": import pyaedt + from pyaedt import Desktop + from pyaedt.generic.general_methods import active_sessions + from pyaedt.generic.general_methods import is_windows else: - import ansys.aedt.core as pyaedt - -# ansys.aedt.core.settings.use_grpc_api = False -settings = pyaedt.settings -from pyaedt import Desktop -from pyaedt.generic.general_methods import active_sessions -from pyaedt.generic.general_methods import is_windows + import ansys.aedt.core + from ansys.aedt.core import Desktop + from ansys.aedt.core.generic.general_methods import active_sessions + from ansys.aedt.core.generic.general_methods import is_windows def release(d): From 5dbed889473822fe7c87a680417461f839a006af Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 12:29:20 +0100 Subject: [PATCH 15/26] Update doc --- doc/source/User_guide/extensions.rst | 47 ++++++++++++++++-- .../hfss/choke_designer.rst | 25 ++++++++++ .../pyaedt_extensions_doc/hfss/index.rst | 11 ++++ .../pyaedt_extensions_doc/icepak/index.rst | 11 ++++ .../User_guide/pyaedt_file_data/choke.rst | 2 + .../_static/extensions/choke_designer_ui.png | Bin 0 -> 32410 bytes 6 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst create mode 100644 doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst create mode 100644 doc/source/User_guide/pyaedt_extensions_doc/icepak/index.rst create mode 100644 doc/source/_static/extensions/choke_designer_ui.png diff --git a/doc/source/User_guide/extensions.rst b/doc/source/User_guide/extensions.rst index fbe71ed841e..d533a2f63d8 100644 --- a/doc/source/User_guide/extensions.rst +++ b/doc/source/User_guide/extensions.rst @@ -45,7 +45,7 @@ They are small automated workflow with a simple UI. :link-type: doc :margin: 2 2 0 0 - Lear how to use the Advanced Fields Calculator. + Lear how to use the Advanced Fields Calculator extension. .. grid-item-card:: Kernel converter @@ -59,12 +59,17 @@ They are small automated workflow with a simple UI. HFSS 3D Layout extensions ~~~~~~~~~~~~~~~~~~~~~~~~~ +Pre-installed extensions are available at HFSS 3D Layout level. +They are small automated workflow with a simple UI. + +.. grid:: 2 + .. grid-item-card:: Parametrize Layout :link: pyaedt_extensions_doc/hfss3dlayout/parametrize_edb :link-type: doc :margin: 2 2 0 0 - Learn how to parametrize a full aedb. + Parametrize a full layout design. .. grid-item-card:: Generate arbitrary wave ports @@ -72,7 +77,39 @@ HFSS 3D Layout extensions :link-type: doc :margin: 2 2 0 0 - Generate arbitrary wave ports in HFSS + Generate arbitrary wave ports in HFSS. + + +HFSS extensions +~~~~~~~~~~~~~~~ + +Pre-installed extensions are available at HFSS level. +They are small automated workflow with a simple UI. + +.. grid:: 2 + + .. grid-item-card:: Choke Designer + :link: pyaedt_extensions_doc/hfss/choke_designer + :link-type: doc + :margin: 2 2 0 0 + + Design a choke and import it in HFSS. + + +Icepak extensions +~~~~~~~~~~~~~~~~~ + +Pre-installed extensions are available at Icepak level. +They are small automated workflow with a simple UI. + +.. grid:: 2 + + .. grid-item-card:: Create power map + :link: pyaedt_extensions_doc/icepak/create_power_map + :link-type: doc + :margin: 2 2 0 0 + + Import a CSV file containing sources layout and power dissipation information. .. toctree:: @@ -81,13 +118,15 @@ HFSS 3D Layout extensions pyaedt_extensions_doc/project/index pyaedt_extensions_doc/hfss3dlayout/index + pyaedt_extensions_doc/hfss/index + pyaedt_extensions_doc/icepak/index Open source toolkits -------------------- Open source toolkits are available at application level. -They are complex workflows where backend and frontend are split. +They are advanced workflows where backend and frontend are split. They are also fully documented and tested. Here are some links to existing toolkits: diff --git a/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst b/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst new file mode 100644 index 00000000000..c114bb1fa00 --- /dev/null +++ b/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst @@ -0,0 +1,25 @@ +Choke Designer +============== + +You can design a choke in HFSS. + +You can access the extension from the icon created on the **Automation** tab using the Extension Manager. + +The following image shows the extension user interface: + +.. image:: ../../../_static/extensions/choke_designer_ui.png + :width: 800 + :alt: Choke Designer UI + + +The available argument is: ``choke_config``. + +The ``choke_config`` parameter is a dictionary with choke configuration file. See more information: :ref:`choke-file`. + +You can also launch the extension user interface from the terminal. An example can be found here: + + +.. toctree:: + :maxdepth: 2 + + ../commandline \ No newline at end of file diff --git a/doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst b/doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst new file mode 100644 index 00000000000..3c6b26682ef --- /dev/null +++ b/doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst @@ -0,0 +1,11 @@ +HFSS extensions +=============== + +.. grid:: 2 + + .. grid-item-card:: Choke Designer + :link: choke_designer + :link-type: doc + :margin: 2 2 0 0 + + Design a choke and import it in HFSS. diff --git a/doc/source/User_guide/pyaedt_extensions_doc/icepak/index.rst b/doc/source/User_guide/pyaedt_extensions_doc/icepak/index.rst new file mode 100644 index 00000000000..c3f6a3487eb --- /dev/null +++ b/doc/source/User_guide/pyaedt_extensions_doc/icepak/index.rst @@ -0,0 +1,11 @@ +Icepak extensions +================= + +.. grid:: 2 + + .. grid-item-card:: Create power map + :link: create_power_map + :link-type: doc + :margin: 2 2 0 0 + + Import a CSV file containing sources layout and power dissipation information. diff --git a/doc/source/User_guide/pyaedt_file_data/choke.rst b/doc/source/User_guide/pyaedt_file_data/choke.rst index d88ac303875..ce1db45bbd9 100644 --- a/doc/source/User_guide/pyaedt_file_data/choke.rst +++ b/doc/source/User_guide/pyaedt_file_data/choke.rst @@ -1,3 +1,5 @@ +.. _choke-file: + Choke file ========== diff --git a/doc/source/_static/extensions/choke_designer_ui.png b/doc/source/_static/extensions/choke_designer_ui.png new file mode 100644 index 0000000000000000000000000000000000000000..5e8a32cb9d7890f65986d4ff46225660dee9e1db GIT binary patch literal 32410 zcmb4rc|4Tg`}ZIziZ)R~3(2m8EJKotv1FNHEQ4%WhO)-c$XW^6vr`z1ea$e4%5Ln- z*h(0TEzHbF4t1*WzjqmGxgCmd4Q^M>l;Zw`KS+YG}c@>+Ws|YVlEivCcKf?*m~2&y0IY zMfe*Q#Dpj8W`2)#yjKrGx|Ce(x*{OJ)2`)pW#>+EE?qT;XGZXa!{5W?&{`+WtC7jw z`ZdpU!=HHK#-mRfPT_|79T(e1A>-1OLAyS6lLU^f*Y#WUTlBl8BCF%1rgf>m`|rg4 zR+uL_6zk88qW1!VuU?k-5;#9QX)zVe1iZmBvh=$6=i=ywN2~O}*E1OnQFxT%p2hle z3G~MPO44KQt+bco>J`DFj-SX>#Mg+kGpI-1$7nSLOj;3B&1?9g%xRD9^HS??@EVZ4 z7D|zWmyGhaXG(!##lJP`IZ|%Q9PVk&xvpyibwEFja*E@h-<_uZM91)wFQogYv3e-g zEj?b_FXH)lxDkPdDQ?}z1aSAC;5RvSv#o*DY)k9bhl-~smnzv5`INRZ)8XP4wa

kN9QI_6{q3)ZS*RKe?ddH{ zvQ3lIl&&h(iC*)xvUk~Cs#5!MR#9}X3=ON8Tvf8wu3tx^Ta6CL+cUF&USCN)s|owQWqh@%7ApZi*=7XJjV_o~yi^(A#-f$B zUOsT*Fip|xJjfj_K%+NQ##4)AxMyGgZPjj}@*bwk7994W?FW~`c9&}=T@_`V>jc>L zXY9%w?c#jHmU`HE}4J#S^dVeR;ILDw$`V#-}k0(e^bdEDQSQ3 zbMlq`>)kOd@(tmnw|B}!wi&o-BE;?8c*J4;-m3I|_T7Hg)3SdT&0^U4>y=>b=)FI| zVsmAIt#kxl({lRQB-STi9)?ux@_t39>;B}v_K*&E+-{W8>eAggyYVL4N;=5eoe@{? zZ6dBR^vSj#9w?30?2rA{tX`6ieyabA92@2SYGnZJ-@ldzr~L^uFDxXjITNqbkjPIP&6?aaz1ec$Ug(`nZn zpPJm}W|tedvwyI^gNZM24@q0rg}Mp2LAxYq%f|0XHN&JBL8LHCx0FvLSMfc z4bhM58<292fArZRsP55}$Myk}{U+OG7fJ!z0(mH)w3o4SxUBX|TubBA<8P_xF0t*t zzM4tzs!RE9oN}8BjM`9$XHKu%N4Xcj6t{oY6N_gliic}v`{Y^0`lxnzd(&2R+OF(2 zbuf!bE05j{%-{clb}Vp>=UZsl+1Aaio;>{P zd01Fs!c;eT5K?5gYY0`r>SYvg!cHvN4EXxkeLwPy?0~Tcal>N zcD_f<2qU>$t5*>e>dx?QrkZS6n}du3T!My>DZ=q z`_reRX$HWg^01yaF!2nx=YXbXY?re8Y1HI?N?Np%(x#@}SgHi{o+?6ItA%Y~&uoj4 zTjQJ%F}HiDc*w45(#do9-1P5|LwT%~kPz+yAp=6^{?%pOv-UHlSXnK;5xiz_m`59H zx8nW?_p1)Drj2>|PnQlzyAEhkhP&k%~JE)AGUF^cft4?9*^HY%yy;7f6+VN&?N__KLwLO-fqY^QWGKq@{^f^w9}-ymaI2+sg{Z*=N_}*_FxJ zutlJ!&Lg4vwCQy797R^OZq{v@N)9cv9j>w!ARlRBx(q!oZ^_m5rfu~wtsR6c$MPDR zA{W-=3$CGObJ5~xkL8*{iBna%Sv!Xny~1hnX*;cHF=>16(n@FLd$KI#Vq~EgC>tGR zgv5%JdFhupa9UYJA$6{BFn302pA550LlgzXJB`jxVEVQ^afz8_VX1EJ5Kp#@l<+Sq z8D$#vH_?KrP6n9Knd+*OP4#9N-KG|uEZRP@Ty(Dc7#+fP;A1}e0KA`d=+R5GiJ9{+ z)An5$BKoH`o%E@vIvj?=&mo@eMxeU~Tb5JV4!yRu&9>i;{hd5iTKk6Nje0Z{vLLd! zkRUfU&wUQI=W45p5$GD7o+KZ`Rt({scS_bUc&6?D|>XT*!;znsq{} z_WmlvcE-TLvPvh_yK>@3Y9QVNm#O19yH?}ugWMdQT)KEP#}d;1(Z+vN*31+)Fw@QN zMhE(zZf@c35)u|s2Ttc5aeRc__qhS7%XV�X)EC{7TLlmWJG(IpFgwTjDl21r$lF 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 Date: Thu, 28 Nov 2024 13:03:50 +0100 Subject: [PATCH 16/26] Fix vale --- .../User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst b/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst index c114bb1fa00..aa0bccd2bee 100644 --- a/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst +++ b/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst @@ -1,4 +1,4 @@ -Choke Designer +Choke designer ============== You can design a choke in HFSS. From 413f4236961aa4f6842e00680c9172cf657369dc Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 13:10:33 +0100 Subject: [PATCH 17/26] Import ansys.aedt.core --- .../aedt/core/workflows/installer/console_setup.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ansys/aedt/core/workflows/installer/console_setup.py b/src/ansys/aedt/core/workflows/installer/console_setup.py index 48d5f81d1eb..27b12922b2c 100644 --- a/src/ansys/aedt/core/workflows/installer/console_setup.py +++ b/src/ansys/aedt/core/workflows/installer/console_setup.py @@ -44,8 +44,14 @@ try: if version <= "2023.1": import pyaedt + from pyaedt import Desktop + from pyaedt.generic.general_methods import active_sessions + from pyaedt.generic.general_methods import is_windows else: - import ansys.aedt.core as pyaedt + import ansys.aedt.core + from ansys.aedt.core import Desktop + from ansys.aedt.core.generic.general_methods import active_sessions + from ansys.aedt.core.generic.general_methods import is_windows except ImportError: # Debug only purpose. If the tool is added to the ribbon from a GitHub clone, then a link # to PyAEDT is created in the personal library. @@ -79,7 +85,6 @@ def release(d): if aedt_process_id in sessions: session_found = True if sessions[aedt_process_id] != -1: - # ansys.aedt.core.settings.use_grpc_api = True port = sessions[aedt_process_id] if not session_found: sessions = active_sessions(version=version, student_version=True) @@ -87,7 +92,6 @@ def release(d): session_found = True student_version = True if sessions[aedt_process_id] != -1: - # ansys.aedt.core.settings.use_grpc_api = True port = sessions[aedt_process_id] error = False @@ -110,7 +114,7 @@ def release(d): student_version=student_version, ) else: - print("Error. AEDT should be started in gRPC mode in Linux to connect to Pyaedt") + print("Error. AEDT should be started in gRPC mode in Linux to connect to PyAEDT") print("use ansysedt -grpcsrv portnumber command.") error = True if not error: From 475d47076358df08fd63cf6bc2637bc89cf0b9e8 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 13:59:17 +0100 Subject: [PATCH 18/26] Fix vale --- doc/source/User_guide/extensions.rst | 2 +- doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/User_guide/extensions.rst b/doc/source/User_guide/extensions.rst index d533a2f63d8..8c1ddb02ba0 100644 --- a/doc/source/User_guide/extensions.rst +++ b/doc/source/User_guide/extensions.rst @@ -88,7 +88,7 @@ They are small automated workflow with a simple UI. .. grid:: 2 - .. grid-item-card:: Choke Designer + .. grid-item-card:: Choke designer :link: pyaedt_extensions_doc/hfss/choke_designer :link-type: doc :margin: 2 2 0 0 diff --git a/doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst b/doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst index 3c6b26682ef..461b8930112 100644 --- a/doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst +++ b/doc/source/User_guide/pyaedt_extensions_doc/hfss/index.rst @@ -3,7 +3,7 @@ HFSS extensions .. grid:: 2 - .. grid-item-card:: Choke Designer + .. grid-item-card:: Choke designer :link: choke_designer :link-type: doc :margin: 2 2 0 0 From 0c41ec99740776ae1420c65b7b12897130a2d3ec Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 14:01:43 +0100 Subject: [PATCH 19/26] Exclude pre-commit files --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e5a15195aef..41db4e47818 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,6 +17,7 @@ exclude: | (?x)( ^src/ansys/aedt/core/rpc/| ^src/ansys/aedt/core/sbrplus/matlab/| + ^src/ansys/aedt/core/workflows/installer| tests/system/general/example_models/| tests/system/solvers/example_models/ ) From a1b45f35b34c5bb528feeb135576e61771c12347 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Thu, 28 Nov 2024 14:02:51 +0100 Subject: [PATCH 20/26] Fix codacy --- src/ansys/aedt/core/workflows/hfss/choke_designer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 27e8b8b977d..095d295d8ef 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -151,7 +151,7 @@ def update_config(cat, selected_option_u): for key in config[cat]: config[cat][key] = key == selected_option_u.get() - for option, value in options.items(): + for option, _ in options.items(): btn = ttk.Radiobutton( group_frame, text=option, @@ -368,7 +368,7 @@ def main(extension_args): list_object = hfss.modeler.create_choke(str(json_path)) # Get core and winding objects - core = list_object[1] + _ = list_object[1] first_winding_list = list_object[2] # Get second winding list if it exists From a4e5de8936c036697bf72cf7449511839ca304e5 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Fri, 29 Nov 2024 08:33:32 +0100 Subject: [PATCH 21/26] Modify Extension Theme --- src/ansys/aedt/core/workflows/misc.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ansys/aedt/core/workflows/misc.py b/src/ansys/aedt/core/workflows/misc.py index 09f0f52face..943b41e0eba 100644 --- a/src/ansys/aedt/core/workflows/misc.py +++ b/src/ansys/aedt/core/workflows/misc.py @@ -107,24 +107,24 @@ def __init__(self): } self.dark = { - "widget_bg": "#3C3C3C", + "widget_bg": "#313335", "text": "#FFFFFF", - "button_bg": "#4D4D4D", + "button_bg": "#FFFFFF", "button_hover_bg": "#606060", "button_active_bg": "#808080", - "tab_bg_inactive": "#2E2E2E", - "tab_bg_active": "#3C3C3C", - "tab_border": "#505050", - "label_bg": "#3C3C3C", # Background for labels + "tab_bg_inactive": "#313335", + "tab_bg_active": "#2B2B2B", + "tab_border": "#3E4042", + "label_bg": "#313335", # Background for labels "label_fg": "#FFFFFF", # Text color for labels - "labelframe_bg": "#3C3C3C", # Background for LabelFrame + "labelframe_bg": "#313335", # Background for LabelFrame "labelframe_fg": "#FFFFFF", # Text color for LabelFrame - "labelframe_title_bg": "#3C3C3C", # Dark background for title (text) + "labelframe_title_bg": "#313335", # Dark background for title (text) "labelframe_title_fg": "#FFFFFF", # Dark text color for title "radiobutton_bg": "#2E2E2E", # Background for Radiobutton "radiobutton_fg": "#FFFFFF", # Text color for Radiobutton - "radiobutton_selected": "#2E2E2E", # Color when selected - "radiobutton_unselected": "#3C3C3C", # Color when unselected + "radiobutton_selected": "#45494A", # Color when selected + "radiobutton_unselected": "#313335", # Color when unselected "pane_bg": "#2E2E2E", # Background for PanedWindow } From 317731913e241404af7c0279fc2e7c6e82b65284 Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:04:06 +0100 Subject: [PATCH 22/26] Update doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- .../User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst b/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst index aa0bccd2bee..e13a30cf3d6 100644 --- a/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst +++ b/doc/source/User_guide/pyaedt_extensions_doc/hfss/choke_designer.rst @@ -14,7 +14,7 @@ The following image shows the extension user interface: The available argument is: ``choke_config``. -The ``choke_config`` parameter is a dictionary with choke configuration file. See more information: :ref:`choke-file`. +The ``choke_config`` parameter is a dictionary with choke configuration file content. See more information: :ref:`choke-file`. You can also launch the extension user interface from the terminal. An example can be found here: From 54973e5c317cf9f5b4c97ae5bcf43b2e53eff92b Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:04:31 +0100 Subject: [PATCH 23/26] Update src/ansys/aedt/core/workflows/hfss/choke_designer.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- src/ansys/aedt/core/workflows/hfss/choke_designer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 095d295d8ef..4eaf430e590 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -367,8 +367,7 @@ def main(extension_args): # Create choke geometry list_object = hfss.modeler.create_choke(str(json_path)) - # Get core and winding objects - _ = list_object[1] + # Get winding objects first_winding_list = list_object[2] # Get second winding list if it exists From 1e53ca68b1449dd02cdefb58da0156f9d33554e6 Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:09:11 +0100 Subject: [PATCH 24/26] Update src/ansys/aedt/core/workflows/hfss/choke_designer.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- src/ansys/aedt/core/workflows/hfss/choke_designer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 4eaf430e590..1f8ca7f3d48 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -371,7 +371,7 @@ def main(extension_args): first_winding_list = list_object[2] # Get second winding list if it exists - second_winding_list = list_object[3] if len(list_object) > 3 else None + second_winding_list = list_object[3] if len(list_object) >= 3 else None # Create ground plane ground_radius = 1.2 * dictionary_values[1]["Outer Winding"]["Outer Radius"] From 49b2aae88c64e5254a33c94f1d091c4595570530 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Fri, 29 Nov 2024 10:16:44 +0100 Subject: [PATCH 25/26] Remove _ = --- src/ansys/aedt/core/workflows/hfss/choke_designer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 1f8ca7f3d48..91f7795273a 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -456,10 +456,10 @@ def main(extension_args): # Create 3D Component if choke_config["Create Component"]["True"]: - _ = hfss.modeler.replace_3dcomponent() + hfss.modeler.replace_3dcomponent() # Create region - _ = hfss.modeler.create_region(pad_percent=1000) + hfss.modeler.create_region(pad_percent=1000) # Create setup setup = hfss.create_setup("Setup1") From 1bc62f809265e11e3c573934661d4929d095ffa4 Mon Sep 17 00:00:00 2001 From: Samuelopez-ansys Date: Fri, 29 Nov 2024 12:47:20 +0100 Subject: [PATCH 26/26] Modify typo --- src/ansys/aedt/core/workflows/hfss/choke_designer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/aedt/core/workflows/hfss/choke_designer.py b/src/ansys/aedt/core/workflows/hfss/choke_designer.py index 91f7795273a..0bd442fa66c 100644 --- a/src/ansys/aedt/core/workflows/hfss/choke_designer.py +++ b/src/ansys/aedt/core/workflows/hfss/choke_designer.py @@ -371,7 +371,7 @@ def main(extension_args): first_winding_list = list_object[2] # Get second winding list if it exists - second_winding_list = list_object[3] if len(list_object) >= 3 else None + second_winding_list = list_object[3] if len(list_object) > 3 else None # Create ground plane ground_radius = 1.2 * dictionary_values[1]["Outer Winding"]["Outer Radius"]