From 9e7796258a937c7df63e1339b60065b77bc39efe Mon Sep 17 00:00:00 2001 From: Jamie MacLeod Date: Tue, 11 Mar 2025 11:18:11 +0000 Subject: [PATCH 1/7] Add refreshWindingPattern call to the create_winding_pattern function. --- src/ansys/motorcad/core/methods/rpc_methods_calculations.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py index af07c33cc..cdb39ba3e 100644 --- a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py +++ b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py @@ -128,5 +128,11 @@ def create_winding_pattern(self): Refreshes the UI to recreate winding pattern. Will be replaced by direct API call soon. """ + if self.connection.check_version_at_least("2025.2"): + # Update parameters on the Winding Pattern page. + method = "RefreshWindingPattern" + return self.connection.send_and_receive(method) + + # Retain for now, as still lots of work done in the UI on this tab. self.display_screen("Scripting") self.display_screen("Winding;Definition") From 1ebdfeb7edf9ae50f9dfda7f87947fa3ba6c4be5 Mon Sep 17 00:00:00 2001 From: Jamie MacLeod Date: Thu, 5 Jun 2025 09:16:59 +0100 Subject: [PATCH 2/7] Update the version number, and don't return when doing RefreshWindingPattern. Still go to winding tab. --- src/ansys/motorcad/core/methods/rpc_methods_calculations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py index cdb39ba3e..924df0c40 100644 --- a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py +++ b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py @@ -128,10 +128,10 @@ def create_winding_pattern(self): Refreshes the UI to recreate winding pattern. Will be replaced by direct API call soon. """ - if self.connection.check_version_at_least("2025.2"): + if self.connection.check_version_at_least("2026.1"): # Update parameters on the Winding Pattern page. method = "RefreshWindingPattern" - return self.connection.send_and_receive(method) + self.connection.send_and_receive(method) # Retain for now, as still lots of work done in the UI on this tab. self.display_screen("Scripting") From 0d6f4050687dabc1c0f7494df541b7508cb2a2cb Mon Sep 17 00:00:00 2001 From: Jamie MacLeod Date: Wed, 11 Jun 2025 10:24:42 +0100 Subject: [PATCH 3/7] Add call into create_winding_pattern --- .../core/methods/rpc_methods_calculations.py | 18 +++++++++++++++--- tests/test_winding.py | 0 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 tests/test_winding.py diff --git a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py index 924df0c40..21e214625 100644 --- a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py +++ b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py @@ -132,7 +132,19 @@ def create_winding_pattern(self): # Update parameters on the Winding Pattern page. method = "RefreshWindingPattern" self.connection.send_and_receive(method) + self.refresh_winding_definition() + else: + # Retain for now, as still lots of work done in the UI on this tab. + self.display_screen("Scripting") + self.display_screen("Winding;Definition") + self.display_screen("Winding;Pattern") - # Retain for now, as still lots of work done in the UI on this tab. - self.display_screen("Scripting") - self.display_screen("Winding;Definition") + def refresh_winding_definition(self): + """Refresh winding definition. + + Calls a function to update the winding definition page properties after changing parameters. + """ + if self.connection.check_version_at_least("2025.2.1"): + # Update parameters on the Winding Pattern page. + method = "RefreshWindingDefinition" + return self.connection.send_and_receive(method) diff --git a/tests/test_winding.py b/tests/test_winding.py new file mode 100644 index 000000000..e69de29bb From 8b6099bd738d5fc347edb9eeb89f451cd3d38851 Mon Sep 17 00:00:00 2001 From: Jamie MacLeod Date: Mon, 16 Jun 2025 12:03:31 +0100 Subject: [PATCH 4/7] Refactor the API call to now call the new CreateWindingPattern function. The necessary work is done internally now rather than in PyMotorCAD. Add some testing functions for the integration --- .../core/methods/rpc_methods_calculations.py | 22 +--- tests/test_winding.py | 119 ++++++++++++++++++ 2 files changed, 125 insertions(+), 16 deletions(-) diff --git a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py index 21e214625..6cfcb6714 100644 --- a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py +++ b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py @@ -126,25 +126,15 @@ def do_mechanical_calculation(self): def create_winding_pattern(self): """Create winding pattern. - Refreshes the UI to recreate winding pattern. Will be replaced by direct API call soon. + With Motor-CAD version 26R1 or greater, updates winding pattern, properties, and weights, after + changing winding parameters. + With Motor-CAD version less than 26R1, refreshes the UI to recreate winding pattern. """ if self.connection.check_version_at_least("2026.1"): # Update parameters on the Winding Pattern page. - method = "RefreshWindingPattern" - self.connection.send_and_receive(method) - self.refresh_winding_definition() + method = "CreateWindingPattern" + return self.connection.send_and_receive(method) else: # Retain for now, as still lots of work done in the UI on this tab. self.display_screen("Scripting") - self.display_screen("Winding;Definition") - self.display_screen("Winding;Pattern") - - def refresh_winding_definition(self): - """Refresh winding definition. - - Calls a function to update the winding definition page properties after changing parameters. - """ - if self.connection.check_version_at_least("2025.2.1"): - # Update parameters on the Winding Pattern page. - method = "RefreshWindingDefinition" - return self.connection.send_and_receive(method) + self.display_screen("Winding;Definition") \ No newline at end of file diff --git a/tests/test_winding.py b/tests/test_winding.py index e69de29bb..d215a9af0 100644 --- a/tests/test_winding.py +++ b/tests/test_winding.py @@ -0,0 +1,119 @@ +from RPC_Test_Common import almost_equal_percentage, get_dir_path + +def test_winding_stranded(mc): + # Starting from the e9 template, change a bunch of winding parameters + mc.load_template("e9") + mc.set_variable("SlotType", 2) + mc.set_variable("Armature_WindingType", 1) + + # Set rectangular winding definition. + mc.set_variable("Wire_Type_Stator", 3) + mc.set_variable("Copper_Width", 0.75) + mc.set_variable("Copper_Height", 0.65) + mc.set_variable("Copper_Corner_Radius", 0.2) + mc.set_variable("Insulation_Thickness", 0.05) + mc.set_variable("NumberStrandsHand", 14) + + mc.set_variable("Liner_Thickness", 0.15) + mc.set_variable("Copper_Depth_[%]", 90) + mc.set_variable("ConductorSeparation", 0.01) + mc.set_variable("Coil_Divider_Width", 2.2) + mc.set_variable("CoilDivider_DepthReduction_Stator", 3) + + mc.create_winding_pattern() + + # Compare outputs against UI results + ui_dict = { + "WIRE_SLOT_FILL_(WDG_AREA)": 0.5918, + "SLOT_FILL_(SLOT_AREA)": 0.3552, + "GrossSlotFillFactor": 0.2757, + "WINDING_DEPTH": 16.948, + "Area_CoilDivider": 30.69, + "Area_Covered_Wire_Total": 49.04, + "Area_Wire_Ins_Total": 10.9776, + "Wire_Copper_Factor": 0.81713, + "Volume_Copper_Active": 416922, + "Volume_WireIns_A": 93302.58, + "Weight_Internal_Calc_Copper_Total": 5.801, + } + auto_dict = {param : mc.get_variable(param) for param in ui_dict.keys()} + + for param in ui_dict.keys(): + assert almost_equal_percentage(ui_dict[param], auto_dict[param], 10) + + +def test_winding_hairpin(mc): + # Starting from the e2 template, change a bunch of winding parameters + mc.load_template("e2") + mc.set_variable("Armature_WindingType", 3) # solid rect upper/lower + + # Set rectangular winding definition. + mc.set_variable("Armature_Winding_Definition_Hairpin", 1) + mc.set_variable("ConductorHeightRatio", 0.16) + mc.set_variable("Liner_Wire_Gap", 0.2) + mc.set_variable("Copper_Corner_Radius", 0.2) + mc.set_variable("Insulation_Thickness", 0.15) + + mc.set_variable("Liner_Thickness", 0.25) + mc.set_variable("Copper_Depth_[%]", 90) + mc.set_variable("ConductorSeparation", 0.1) + mc.set_variable("Coil_Divider_Width", 2.4) + mc.set_variable("CoilDividerOffset", 0.2) + + mc.create_winding_pattern() + + # Compare outputs against UI results + ui_dict = { + "WIRE_SLOT_FILL_(WDG_AREA)": 0.8428, + "SLOT_FILL_(SLOT_AREA)": 0.5976, + "GrossSlotFillFactor": 0.5045, + "WINDING_DEPTH": 21.672, + "Area_CoilDivider": 12, + "Area_Covered_Wire_Total": 81.22, + "Area_Wire_Ins_Total": 12.653, + "Wire_Copper_Factor": 0.9032, + "Volume_Copper_Active": 427248, + "Volume_WireIns_A": 457912, + "Weight_Internal_Calc_Copper_Total": 7.2446, + } + auto_dict = {param : mc.get_variable(param) for param in ui_dict.keys()} + + for param in ui_dict.keys(): + assert almost_equal_percentage(ui_dict[param], auto_dict[param], 10) + + +def test_winding_IM1PH(mc): + # Load default IM1PH file as there is no template. + default_file = ( + get_dir_path() + r"\test_files\default_IM1PH.mot" + ) + mc.load_from_file(default_file) + + mc.set_variable("AWG_WireGaugeIndex", 53) + mc.set_variable("AWG_WireGaugeIndex_Aux", 50) + mc.set_variable("NumberStrandsHand", 2) + mc.set_variable("NumberStrandsHand_Aux", 2) + mc.set_variable("Liner_Thickness", 0.15) + mc.set_variable("Copper_Depth_[%]", 90) + mc.set_variable("ConductorSeparation", 0.2) + mc.create_winding_pattern() + + # Compare outputs against UI results + ui_dict = { + "WIRE_SLOT_FILL_(WDG_AREA)": 0.0949, + "SLOT_FILL_(SLOT_AREA)": 0.0813, + "GrossSlotFillFactor": 0.0632, + "WINDING_DEPTH": 14.348, + "Area_Covered_Wire_Total": 11.71, + "Area_Wire_Ins_Total": 2.6076, + "Wire_Copper_Factor": 0.77728, + "Volume_Copper_Active": 13104.8, + "Volume_Copper_Active_Aux": 18450.16, + "Volume_WireIns_A": 4693.7, + "Weight_Internal_Calc_Copper_Total": 0.577065, + } + auto_dict = {param : mc.get_variable(param) for param in ui_dict.keys()} + + for param in ui_dict.keys(): + assert almost_equal_percentage(ui_dict[param], auto_dict[param], 10) + From d4ff5b70ab51095e635f8ff5a3f36cf49b19e7b8 Mon Sep 17 00:00:00 2001 From: Jamie MacLeod Date: Thu, 26 Jun 2025 14:56:38 +0100 Subject: [PATCH 5/7] Add temporary function for testing rotor winding. --- .../core/methods/rpc_methods_calculations.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py index 6cfcb6714..4000f7ac7 100644 --- a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py +++ b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py @@ -137,4 +137,15 @@ def create_winding_pattern(self): else: # Retain for now, as still lots of work done in the UI on this tab. self.display_screen("Scripting") - self.display_screen("Winding;Definition") \ No newline at end of file + self.display_screen("Winding;Definition") + + def create_winding_pattern_rotor(self): + """Create rotor winding pattern. + + Update the rotor winding and weights and volumes post edit of winding parameters. + Requires MotorCAD version 26R1 or greater. + """ + + method = "RefreshWindingDefinitionRotor" + return self.connection.send_and_receive(method) + From a34ff7b29e948db0cd19fbfe5532a43a2344ae75 Mon Sep 17 00:00:00 2001 From: Jamie MacLeod Date: Tue, 23 Sep 2025 16:37:45 +0100 Subject: [PATCH 6/7] Update to avoid a deprecation warning. --- src/ansys/motorcad/core/rpc_client_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/motorcad/core/rpc_client_core.py b/src/ansys/motorcad/core/rpc_client_core.py index e7f2441e2..2719617d6 100644 --- a/src/ansys/motorcad/core/rpc_client_core.py +++ b/src/ansys/motorcad/core/rpc_client_core.py @@ -122,7 +122,7 @@ class MotorCADWarning(Warning): def _get_port_from_motorcad_process(process): - connection_list = process.connections() + connection_list = process.net_connections() if len(connection_list) > 0: for connect in connection_list: if connect.family == socket.AddressFamily.AF_INET6: From 25e3de0bac3a330cc80f2fde27601159a7b48e8b Mon Sep 17 00:00:00 2001 From: Jack Davies Date: Tue, 7 Oct 2025 17:43:51 +0100 Subject: [PATCH 7/7] pre-commit changed --- .../core/methods/rpc_methods_calculations.py | 6 ++-- tests/test_winding.py | 36 ++++++++++++++----- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py index 4000f7ac7..7868ee3e2 100644 --- a/src/ansys/motorcad/core/methods/rpc_methods_calculations.py +++ b/src/ansys/motorcad/core/methods/rpc_methods_calculations.py @@ -126,8 +126,8 @@ def do_mechanical_calculation(self): def create_winding_pattern(self): """Create winding pattern. - With Motor-CAD version 26R1 or greater, updates winding pattern, properties, and weights, after - changing winding parameters. + With Motor-CAD version 26R1 or greater, updates winding pattern, properties, and weights, + after changing winding parameters. With Motor-CAD version less than 26R1, refreshes the UI to recreate winding pattern. """ if self.connection.check_version_at_least("2026.1"): @@ -145,7 +145,5 @@ def create_winding_pattern_rotor(self): Update the rotor winding and weights and volumes post edit of winding parameters. Requires MotorCAD version 26R1 or greater. """ - method = "RefreshWindingDefinitionRotor" return self.connection.send_and_receive(method) - diff --git a/tests/test_winding.py b/tests/test_winding.py index d215a9af0..d63be145d 100644 --- a/tests/test_winding.py +++ b/tests/test_winding.py @@ -1,5 +1,28 @@ +# Copyright (C) 2022 - 2025 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. + from RPC_Test_Common import almost_equal_percentage, get_dir_path + def test_winding_stranded(mc): # Starting from the e9 template, change a bunch of winding parameters mc.load_template("e9") @@ -36,7 +59,7 @@ def test_winding_stranded(mc): "Volume_WireIns_A": 93302.58, "Weight_Internal_Calc_Copper_Total": 5.801, } - auto_dict = {param : mc.get_variable(param) for param in ui_dict.keys()} + auto_dict = {param: mc.get_variable(param) for param in ui_dict.keys()} for param in ui_dict.keys(): assert almost_equal_percentage(ui_dict[param], auto_dict[param], 10) @@ -45,7 +68,7 @@ def test_winding_stranded(mc): def test_winding_hairpin(mc): # Starting from the e2 template, change a bunch of winding parameters mc.load_template("e2") - mc.set_variable("Armature_WindingType", 3) # solid rect upper/lower + mc.set_variable("Armature_WindingType", 3) # solid rect upper/lower # Set rectangular winding definition. mc.set_variable("Armature_Winding_Definition_Hairpin", 1) @@ -76,7 +99,7 @@ def test_winding_hairpin(mc): "Volume_WireIns_A": 457912, "Weight_Internal_Calc_Copper_Total": 7.2446, } - auto_dict = {param : mc.get_variable(param) for param in ui_dict.keys()} + auto_dict = {param: mc.get_variable(param) for param in ui_dict.keys()} for param in ui_dict.keys(): assert almost_equal_percentage(ui_dict[param], auto_dict[param], 10) @@ -84,9 +107,7 @@ def test_winding_hairpin(mc): def test_winding_IM1PH(mc): # Load default IM1PH file as there is no template. - default_file = ( - get_dir_path() + r"\test_files\default_IM1PH.mot" - ) + default_file = get_dir_path() + r"\test_files\default_IM1PH.mot" mc.load_from_file(default_file) mc.set_variable("AWG_WireGaugeIndex", 53) @@ -112,8 +133,7 @@ def test_winding_IM1PH(mc): "Volume_WireIns_A": 4693.7, "Weight_Internal_Calc_Copper_Total": 0.577065, } - auto_dict = {param : mc.get_variable(param) for param in ui_dict.keys()} + auto_dict = {param: mc.get_variable(param) for param in ui_dict.keys()} for param in ui_dict.keys(): assert almost_equal_percentage(ui_dict[param], auto_dict[param], 10) -