From e0749bbe2c829171099fd908fc42f1ea6bf2d35d Mon Sep 17 00:00:00 2001 From: JackB-Ansys Date: Tue, 11 Jun 2024 10:19:33 +0100 Subject: [PATCH 1/7] reformatting --- examples/basics/emag_basics.py | 120 +++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 50 deletions(-) diff --git a/examples/basics/emag_basics.py b/examples/basics/emag_basics.py index 655d0249b..9c4299eb1 100644 --- a/examples/basics/emag_basics.py +++ b/examples/basics/emag_basics.py @@ -19,9 +19,14 @@ # # Perform required imports # ~~~~~~~~~~~~~~~~~~~~~~~~ +# Import ``pymotorcad`` to access Motor-CAD. Import ``pyplot`` from ``matplotlib`` to display +# graphics. Import ``os``, ``shutil``, ``sys``, and ``tempfile`` to open and save a temporary MOT +# file if none is open. import os +import shutil +import tempfile import matplotlib.pyplot as plt @@ -33,27 +38,36 @@ # %% # Specify working directory # ~~~~~~~~~~~~~~~~~~~~~~~~~ - -working_folder = os.getcwd() - -if os.path.isdir(working_folder) is False: - print("Working folder does not exist. Choose a folder that exists and try again.") - print(working_folder) - exit() +# Save the file to a temporary folder +working_folder = os.path.join(tempfile.gettempdir(), "basic_examples") +try: + shutil.rmtree(working_folder) +except: + pass +os.mkdir(working_folder) +mot_name = "EMagnetic" +# mc.save_to_file(working_folder + "/" + mot_name + ".mot") + +# working_folder = os.getcwd() +# +# if os.path.isdir(working_folder) is False: +# print("Working folder does not exist. Choose a folder that exists and try again.") +# print(working_folder) +# exit() # %% # Launch Motor-CAD # ~~~~~~~~~~~~~~~~ print("Starting initialization.") -mcad = pymotorcad.MotorCAD() +mc = pymotorcad.MotorCAD(keep_instance_open=True) # %% # Disable popup messages # ~~~~~~~~~~~~~~~~~~~~~~ -mcad.set_variable("MessageDisplayState", 2) -print("Initialization completed.") +mc.set_variable("MessageDisplayState", 2) +print("Initialisation completed.") print("Running simulation.") # %% @@ -64,17 +78,21 @@ # the file. # # Show the magnetic context. -mcad.show_magnetic_context() +mc.show_magnetic_context() # %% # Display the **Scripting** tab. -mcad.display_screen("Scripting") +mc.display_screen("Scripting") + +# %% +# Ensure that the BPM Motor Type is set. +mc.set_variable("Motor_Type", 0) # %% # Set the geometry. -mcad.set_variable("Slot_Number", 24) -mcad.set_variable("Tooth_Width", 6) -mcad.set_variable("Magnet_Thickness", 4.5) +mc.set_variable("Slot_Number", 24) +mc.set_variable("Tooth_Width", 6) +mc.set_variable("Magnet_Thickness", 4.5) # %% # Set parameters for creating the custom winding pattern. @@ -82,69 +100,71 @@ # The following code creates only a partial winding pattern. # # Set the winding type to custom: -# :code:`mcad.set_variable('MagWindingType', 1)` +mc.set_variable("MagneticWindingType", 2) # :code:`mc.set_variable('MagWindingType', 1)` + # # Set the path type to upper and lower: -# :code:`mcad.set_variable('MagPathType', 1)` +mc.set_variable("MagPathType", 1) # :code:`mc.set_variable('MagPathType', 1)` # # Set the number of phases: -# :code:`mcad.set_variable('MagPhases', 3)` +mc.set_variable("MagPhases", 3) # :code:`mc.set_variable('MagPhases', 3)` # # Set the number of parallel paths: -# :code:`mcad.set_variable('ParallelPaths', 1)` +mc.set_variable("ParallelPaths", 1) # :code:`mc.set_variable('ParallelPaths', 1)` # # Set the number of winding layers: -# :code:`mcad.set_variable('WindingLayers', 2)` +mc.set_variable("WindingLayers", 2) # :code:`mc.set_variable('WindingLayers', 2)` # # Define a coil's parameters: +mc.set_winding_coil(2, 1, 3, 4, "b", 18, "a", 60) # :code:`set_winding_coil(phase, # path, coil, go_slot, go_position, return_slot, return_position, turns)` # %% # Set the stator/rotor lamination materials. -mcad.set_component_material("Stator Lam (Back Iron)", "M250-35A") -mcad.set_component_material("Rotor Lam (Back Iron)", "M250-35A") +mc.set_component_material("Stator Lam (Back Iron)", "M250-35A") +mc.set_component_material("Rotor Lam (Back Iron)", "M250-35A") # %% # Set the torque calculation options. points_per_cycle = 30 number_cycles = 1 -mcad.set_variable("TorquePointsPerCycle", points_per_cycle) -mcad.set_variable("TorqueNumberCycles", number_cycles) +mc.set_variable("TorquePointsPerCycle", points_per_cycle) +mc.set_variable("TorqueNumberCycles", number_cycles) # %% # Disable all performance tests except the ones for transient torque. -mcad.set_variable("BackEMFCalculation", False) -mcad.set_variable("CoggingTorqueCalculation", False) -mcad.set_variable("ElectromagneticForcesCalc_OC", False) -mcad.set_variable("TorqueSpeedCalculation", False) -mcad.set_variable("DemagnetizationCalc", False) -mcad.set_variable("ElectromagneticForcesCalc_Load", False) -mcad.set_variable("InductanceCalc", False) -mcad.set_variable("BPMShortCircuitCalc", False) +mc.set_variable("BackEMFCalculation", False) +mc.set_variable("CoggingTorqueCalculation", False) +mc.set_variable("ElectromagneticForcesCalc_OC", False) +mc.set_variable("TorqueSpeedCalculation", False) +mc.set_variable("DemagnetizationCalc", False) +mc.set_variable("ElectromagneticForcesCalc_Load", False) +mc.set_variable("InductanceCalc", False) +mc.set_variable("BPMShortCircuitCalc", False) # %% # Enable transient torque. -mcad.set_variable("TorqueCalculation", True) +mc.set_variable("TorqueCalculation", True) # %% # Set the operating point. -mcad.set_variable("Shaft_Speed_[RPM]", 1000) -mcad.set_variable("CurrentDefinition", 0) -mcad.set_variable("PeakCurrent", 3) -mcad.set_variable("DCBusVoltage", 350) -mcad.set_variable("PhaseAdvance", 45) +mc.set_variable("Shaft_Speed_[RPM]", 1000) +mc.set_variable("CurrentDefinition", 0) +mc.set_variable("PeakCurrent", 3) +mc.set_variable("DCBusVoltage", 350) +mc.set_variable("PhaseAdvance", 45) # %% # Save the file. filename = os.path.join(working_folder, "../ActiveX_Scripting_EMagnetic.mot") -mcad.save_to_file(filename) +mc.save_to_file(filename) # %% # Run simulation # -------------- # Run the simulation. -mcad.do_magnetic_calculation() +mc.do_magnetic_calculation() # %% # Export results to CSV file @@ -152,7 +172,7 @@ # Export results to a CSV file. exportFile = os.path.join(working_folder, "../Export_EMag_Results.csv") try: - mcad.export_results("EMagnetic", exportFile) + mc.export_results("EMagnetic", exportFile) print("Results successfully exported.") except pymotorcad.MotorCADError: print("Results failed to export.") @@ -161,8 +181,8 @@ # Get and analyze results # ----------------------- # Get torque and voltage data. -shaft_torque = mcad.get_variable("ShaftTorque") -line_voltage = mcad.get_variable("PeakLineLineVoltage") +shaft_torque = mc.get_variable("ShaftTorque") +line_voltage = mc.get_variable("PeakLineLineVoltage") # %% # Graph the torque data. @@ -171,7 +191,7 @@ torque_vw = [] for n in range(num_torque_points): - (x, y) = mcad.get_magnetic_graph_point("TorqueVW", n) + (x, y) = mc.get_magnetic_graph_point("TorqueVW", n) rotor_position.append(x) torque_vw.append(y) @@ -186,7 +206,7 @@ # Keep looking until you cannot find the point. while success == 0: try: - (x, y) = mcad.get_fea_graph_point("B Gap (on load)", 1, loop, 0) + (x, y) = mc.get_fea_graph_point("B Gap (on load)", 1, loop, 0) mech_angle.append(x) airgap_flux_density.append(y) loop = loop + 1 @@ -195,15 +215,15 @@ # %% # Graph the harmonic data. -mcad.initialise_tab_names() -mcad.display_screen("Graphs;Harmonics;Torque") +mc.initialise_tab_names() +mc.display_screen("Graphs;Harmonics;Torque") num_harmonic_points = (points_per_cycle * number_cycles) + 1 data_point = [] torque = [] for n in range(num_harmonic_points): try: - (x, y) = mcad.get_magnetic_graph_point("HarmonicDataCycle", n) + (x, y) = mc.get_magnetic_graph_point("HarmonicDataCycle", n) data_point.append(x) torque.append(y) except pymotorcad.MotorCADError: @@ -235,9 +255,9 @@ # Exit Motor-CAD # -------------- # Exit Motor-CAD. -mcad.quit() +mc.quit() # %% # If you want to continue working with this instance of Motor-CAD, rather # than using the preceding command, use this command: -# :code:`mcad.set_variable('MessageDisplayState', 0)` +# :code:`mc.set_variable('MessageDisplayState', 0)` From dccccbd2cf82321c91a37ac2d9f5a91219d67214 Mon Sep 17 00:00:00 2001 From: JackB-Ansys Date: Wed, 12 Jun 2024 17:54:45 +0100 Subject: [PATCH 2/7] Added new methods for getting fea and magnetic 3D graphs. updated graph method to work with new methods. Updated basic examples --- examples/basics/emag_basics.py | 259 +++++++++--------- examples/basics/thermal_basics.py | 145 ++++++---- .../core/methods/rpc_methods_graphs.py | 61 ++++- 3 files changed, 274 insertions(+), 191 deletions(-) diff --git a/examples/basics/emag_basics.py b/examples/basics/emag_basics.py index 9c4299eb1..bdb76621f 100644 --- a/examples/basics/emag_basics.py +++ b/examples/basics/emag_basics.py @@ -3,27 +3,26 @@ Motor-CAD E-magnetic example script =================================== -This example provides a Motor-CAD E-magnetic script. This script -creates a partial custom winding pattern to change -parameter values, run the analysis, and plot results. To create -a full winding pattern, parameters must be specified -for all coils. +This example provides a Motor-CAD E-magnetic script. This script will change model parameter values +(geometry, winding pattern and materials), run magnetic calculations, extract and plot results. """ - # %% +# .. note:: +# This script creates a partial custom winding pattern. To create a full winding pattern, +# parameters must be specified for all coils. +# # Set up example # -------------- -# Setting up this example consists of performing imports, specifying the -# working directory, launching Motor-CAD, and disabling all popup -# messages from Motor-CAD. +# To set up the example, perform imports, specify the working directory, launch Motor-CAD, and +# disable all popup messages from Motor-CAD. # # Perform required imports # ~~~~~~~~~~~~~~~~~~~~~~~~ # Import ``pymotorcad`` to access Motor-CAD. Import ``pyplot`` from ``matplotlib`` to display -# graphics. Import ``os``, ``shutil``, ``sys``, and ``tempfile`` to open and save a temporary MOT +# graphics. Import ``os``, ``shutil`` and ``tempfile`` to open and save a temporary MOT # file if none is open. - +# sphinx_gallery_thumbnail_number = -2 import os import shutil import tempfile @@ -32,9 +31,6 @@ import ansys.motorcad.core as pymotorcad -if "QT_API" in os.environ: - os.environ["QT_API"] = "pyqt" - # %% # Specify working directory # ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -46,91 +42,106 @@ pass os.mkdir(working_folder) mot_name = "EMagnetic" -# mc.save_to_file(working_folder + "/" + mot_name + ".mot") - -# working_folder = os.getcwd() -# -# if os.path.isdir(working_folder) is False: -# print("Working folder does not exist. Choose a folder that exists and try again.") -# print(working_folder) -# exit() # %% # Launch Motor-CAD # ~~~~~~~~~~~~~~~~ - +# Connect to Motor-CAD and open a new Motor-CAD instance. To keep a new Motor-CAD instance open +# after executing the script, use the ``MotorCAD(keep_instance_open=True)`` option when opening the +# new instance. print("Starting initialization.") -mc = pymotorcad.MotorCAD(keep_instance_open=True) +mc = pymotorcad.MotorCAD() # %% # Disable popup messages # ~~~~~~~~~~~~~~~~~~~~~~ - +# Disable all popup messages from Motor-CAD by setting the ``MessageDisplayState`` parameter to 2. +# +# .. note:: +# This will also disable crucial popups, for example prompts to save data or overwrite data, or +# dialogs used to reconcile differences in material data between the database and MOT file. In +# each case the default action will be taken. This setting will persist until Motor-CAD is +# closed. mc.set_variable("MessageDisplayState", 2) -print("Initialisation completed.") -print("Running simulation.") # %% -# Create analysis -# --------------- -# Creating the analysis consists of showing the magnetic context, displaying -# the **Scripting** tab, setting the geometry and parameters, and saving -# the file. -# -# Show the magnetic context. +# Set Motor-CAD to EMag +# ~~~~~~~~~~~~~~~~~~~~~ +# Show the E-Magnetic context in Motor-CAD and ensure that the BPM +# Motor Type is set. mc.show_magnetic_context() - -# %% -# Display the **Scripting** tab. -mc.display_screen("Scripting") - -# %% -# Ensure that the BPM Motor Type is set. mc.set_variable("Motor_Type", 0) # %% -# Set the geometry. +# Set up analysis +# --------------- +# Setting up the analysis consists of setting the geometry, winding and material parameters, setting +# the calculation options and operating point, and saving the file. +# +# Geometry setup +# ~~~~~~~~~~~~~~ +# Display the **Scripting** tab and set the ``Slot_Number``, ``Tooth_Width`` and +# ``Magnet_Thickness`` geometry parameters. +# +# .. note:: +# To set parameter values via automation with the GUI visible, a different tab must be displayed. +# The **Scripting** tab is chosen because no parameters on this tab will be changed in this +# script. It is best practice to display the **Scripting** tab when changing input parameters by +# automation. This is required only if the GUI is shown. +mc.display_screen("Scripting") mc.set_variable("Slot_Number", 24) mc.set_variable("Tooth_Width", 6) mc.set_variable("Magnet_Thickness", 4.5) # %% -# Set parameters for creating the custom winding pattern. +# Winding setup +# ~~~~~~~~~~~~~~ +# Instead of using the automatic winding pattern, set parameters for creating a partial custom +# winding pattern. This example sets up an unevenly distributed winding pattern. # -# The following code creates only a partial winding pattern. +# The script: # -# Set the winding type to custom: -mc.set_variable("MagneticWindingType", 2) # :code:`mc.set_variable('MagWindingType', 1)` - +# * Set the winding type to *Custom*. # -# Set the path type to upper and lower: -mc.set_variable("MagPathType", 1) # :code:`mc.set_variable('MagPathType', 1)` +# * Set the path type to *Upper/Lower*. # -# Set the number of phases: -mc.set_variable("MagPhases", 3) # :code:`mc.set_variable('MagPhases', 3)` +# * Set the number of phases to 3. # -# Set the number of parallel paths: -mc.set_variable("ParallelPaths", 1) # :code:`mc.set_variable('ParallelPaths', 1)` +# * Set the number of parallel paths to 1. # -# Set the number of winding layers: -mc.set_variable("WindingLayers", 2) # :code:`mc.set_variable('WindingLayers', 2)` +# * Set the number of winding layers to 2. # -# Define a coil's parameters: +# * Define parameters for coil 3 using the ``set_winding_coil()`` method. Set positions to a, b, c +# etc. when using Upper/Lower paths (when Left/Right paths are selected, L or R should be used +# instead). Define the third coil to have 60 turns in the second phase. +mc.set_variable("MagneticWindingType", 2) +mc.set_variable("MagPathType", 1) +mc.set_variable("MagPhases", 3) +mc.set_variable("ParallelPaths", 1) +mc.set_variable("WindingLayers", 2) mc.set_winding_coil(2, 1, 3, 4, "b", 18, "a", 60) -# :code:`set_winding_coil(phase, -# path, coil, go_slot, go_position, return_slot, return_position, turns)` # %% -# Set the stator/rotor lamination materials. +# the changes to the winding pattern are shown below +# +# .. image:: ../../images/basics_emag_2.png + +# %% +# Materials setup +# ~~~~~~~~~~~~~~~ +# Set the stator and rotor lamination materials. Component names are displayed in the +# *Materials* tab in Motor-CAD. Materials and their properties are defined in the Motor-CAD +# *Material database*. mc.set_component_material("Stator Lam (Back Iron)", "M250-35A") mc.set_component_material("Rotor Lam (Back Iron)", "M250-35A") # %% -# Set the torque calculation options. -points_per_cycle = 30 -number_cycles = 1 -mc.set_variable("TorquePointsPerCycle", points_per_cycle) -mc.set_variable("TorqueNumberCycles", number_cycles) +# Calculation options +# ~~~~~~~~~~~~~~~~~~~ +# Set the torque calculation options for a transient torque calculation with 30 points in 1 +# electrical cycle. +mc.set_variable("TorquePointsPerCycle", 30) +mc.set_variable("TorqueNumberCycles", 1) # %% # Disable all performance tests except the ones for transient torque. @@ -144,11 +155,14 @@ mc.set_variable("BPMShortCircuitCalc", False) # %% -# Enable transient torque. +# Enable transient torque calculation. mc.set_variable("TorqueCalculation", True) # %% -# Set the operating point. +# Operating point +# ~~~~~~~~~~~~~~~ +# Set the operating point of the machine, defined by the speed, current and phase advance. Ensure +# that the current definition is set to *Peak* (index 0 of the radio group option). mc.set_variable("Shaft_Speed_[RPM]", 1000) mc.set_variable("CurrentDefinition", 0) mc.set_variable("PeakCurrent", 3) @@ -156,79 +170,71 @@ mc.set_variable("PhaseAdvance", 45) # %% -# Save the file. -filename = os.path.join(working_folder, "../ActiveX_Scripting_EMagnetic.mot") -mc.save_to_file(filename) +# Save the file +# ~~~~~~~~~~~~~ +# Save the file to the temporary folder and display a message that the initialisation in complete. +mc.save_to_file(working_folder + "/" + mot_name + ".mot") +print("Initialisation completed.") # %% # Run simulation # -------------- -# Run the simulation. +# Run the electromagnetic calculation in Motor-CAD (solve the e-magnetic model). +print("Running simulation.") mc.do_magnetic_calculation() # %% # Export results to CSV file # -------------------------- -# Export results to a CSV file. -exportFile = os.path.join(working_folder, "../Export_EMag_Results.csv") +# Export results to a CSV file. Results will be saved as *Export_EMag_Results.csv* in the temporary +# working directory. A try and except block are used to raise an error in the case of the export +# failing. try: - mc.export_results("EMagnetic", exportFile) + mc.export_results("EMagnetic", working_folder + "/Export_EMag_Results.csv") print("Results successfully exported.") -except pymotorcad.MotorCADError: - print("Results failed to export.") +except pymotorcad.MotorCADError as e: + print("Results failed to export due to Motor-CAD Error: " + str(e)) # %% -# Get and analyze results +# Get and analyse results # ----------------------- -# Get torque and voltage data. +# Retrieve the torque and voltage output data values. shaft_torque = mc.get_variable("ShaftTorque") line_voltage = mc.get_variable("PeakLineLineVoltage") +print( + f"Shaft Torque: {shaft_torque:.2f} Nm, Line-Line Terminal Voltage (peak): {line_voltage:.2f} V" +) # %% -# Graph the torque data. -num_torque_points = points_per_cycle * number_cycles -rotor_position = [] -torque_vw = [] - -for n in range(num_torque_points): - (x, y) = mc.get_magnetic_graph_point("TorqueVW", n) - rotor_position.append(x) - torque_vw.append(y) - -# %% -# Graph the airgap flux density data. -loop = 0 -success = 0 -mech_angle = [] -airgap_flux_density = [] +# Retrieve the *Torque (VW)* graph data. The data type for this series is *E-Magnetics*, so use the +# ``get_magnetic_graph()`` method. +# +# .. note:: +# When retrieving graph data points, use the *Graph Viewer* under *Help* in the Motor-CAD +# interface to find the series names and data types. +rotor_position, torque_vw = mc.get_magnetic_graph("TorqueVW") # %% -# Keep looking until you cannot find the point. -while success == 0: - try: - (x, y) = mc.get_fea_graph_point("B Gap (on load)", 1, loop, 0) - mech_angle.append(x) - airgap_flux_density.append(y) - loop = loop + 1 - except pymotorcad.MotorCADError: - success = 1 +# Retrieve the airgap flux density graph data. This data can be found in the *Graph Viewer* in +# Motor-CAD. The data type for this series is *FEA Path*, so use the ``get_fea_graph()`` method. +mech_angle, airgap_flux_density = mc.get_fea_graph("B Gap (on load)", 1, 0) # %% -# Graph the harmonic data. +# Only the most recently displayed harmonic graphs are available in Motor-CAD via the +# *Graph Viewer*. To retrieve harmonic data by using Motor-CAD automation, first display the +# relevant *Graphs -> Harmonics* tab. Use the ``initialise_tab_names()`` method to initialise the +# available tabs in the Motor-CAD user interface. When the tabs have been initialised, the +# ``display_screen()`` method can be used until either the Motor-CAD context is changed, or the +# instance is closed. +# +# Open the *Graphs -> Harmonics -> Torque* tab to make the torque harmonic data available. mc.initialise_tab_names() mc.display_screen("Graphs;Harmonics;Torque") -num_harmonic_points = (points_per_cycle * number_cycles) + 1 -data_point = [] -torque = [] -for n in range(num_harmonic_points): - try: - (x, y) = mc.get_magnetic_graph_point("HarmonicDataCycle", n) - data_point.append(x) - torque.append(y) - except pymotorcad.MotorCADError: - print("Results failed to export.") - +# %% +# Retrieve the torque harmonic graph data. The data type for this series is *E-Magnetics*, so use +# the ``get_fea_graph()`` method. +harmonic_order, harmonic_amplitude = mc.get_magnetic_graph("HarmonicAmplitude") print("Simulation completed.") @@ -236,7 +242,8 @@ # %% # Plot results # ------------ -# Plot results from the simulation. +# Use``pyplot`` from ``matplotlib`` (imported as ``plt``) to plot graphs of the simulation results. +# Plot the Airgap Flux Density and the Torque (VW) results as subplots in the same figure. plt.subplot(211) plt.plot(mech_angle, airgap_flux_density) plt.xlabel("Mech Angle") @@ -245,19 +252,19 @@ plt.plot(rotor_position, torque_vw) plt.xlabel("Rotor Position") plt.ylabel("TorqueVW") -plt.figure(2) -plt.plot(data_point, torque) -plt.xlabel("DataPoint") -plt.ylabel("Torque (Nm)") plt.show() # %% -# Exit Motor-CAD -# -------------- -# Exit Motor-CAD. -mc.quit() +# Plot the Torque harmonic results as a bar chart. +plt.figure(2) +plt.bar(harmonic_order, harmonic_amplitude) +plt.xlabel("Harmonic order (Electrical)") +plt.ylabel("Harmonic amplitude (Nm)") +plt.show() # %% -# If you want to continue working with this instance of Motor-CAD, rather -# than using the preceding command, use this command: -# :code:`mc.set_variable('MessageDisplayState', 0)` +# If you want to continue working with this instance of Motor-CAD, use the +# ``MotorCAD(keep_instance_open=True)`` option when you launch Motor-CAD. If Motor-CAD is kept open, +# it is useful to restore the popup messages that were disabled earlier, using the +# ``set_variable()`` method (). +mc.set_variable("MessageDisplayState", 0) diff --git a/examples/basics/thermal_basics.py b/examples/basics/thermal_basics.py index 38ed64858..221cfd114 100644 --- a/examples/basics/thermal_basics.py +++ b/examples/basics/thermal_basics.py @@ -9,89 +9,114 @@ # %% # Set up example # -------------- -# Setting up this example consists of performing imports, launching -# Motor-CAD, disabling all popup messages from Motor-CAD, and -# opening the file for the thermal analysis. - +# To set up the example, perform imports, specify the working directory, launch Motor-CAD, and +# disable all popup messages from Motor-CAD. The e8 IPM motor template is loaded for the thermal +# analysis. +# # Perform required imports # ~~~~~~~~~~~~~~~~~~~~~~~~ -# Import the required packages. +# Import ``pymotorcad`` to access Motor-CAD. Import ``pyplot`` from ``matplotlib`` to display +# graphics. Import ``os``, ``shutil`` and ``tempfile`` to open and save a temporary MOT +# file if none is open. + +# sphinx_gallery_thumbnail_number = -2 import os +import shutil +import tempfile import matplotlib.pyplot as plt import ansys.motorcad.core as pymotorcad -if "QT_API" in os.environ: - os.environ["QT_API"] = "pyqt" +# %% +# Specify working directory +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# Save the file to a temporary folder +working_folder = os.path.join(tempfile.gettempdir(), "basic_examples") +try: + shutil.rmtree(working_folder) +except: + pass +os.mkdir(working_folder) +mot_name = "e8_Thermal" # %% # Launch Motor-CAD # ~~~~~~~~~~~~~~~~ -# Initialize ActiveX automation and launch Motor-CAD. -print("Starting initialization.") -mcad = pymotorcad.MotorCAD() +# Connect to Motor-CAD and open a new Motor-CAD instance. To keep a new Motor-CAD instance open +# after executing the script, use the ``MotorCAD(keep_instance_open=True)`` option when opening the +# new instance. +print("Starting initialisation.") +mc = pymotorcad.MotorCAD(keep_instance_open=True) # %% # Disable popup messages # ~~~~~~~~~~~~~~~~~~~~~~ -# Disable all popup messages from Motor-CAD. -mcad.set_variable("MessageDisplayState", 2) +# Disable all popup messages from Motor-CAD by setting the ``MessageDisplayState`` parameter to 2. +# +# .. note:: +# This will also disable crucial popups, for example prompts to save data or overwrite data, or +# dialogs used to reconcile differences in material data between the database and MOT file. In +# each case the default action will be taken. This setting will persist until Motor-CAD is +# closed. +mc.set_variable("MessageDisplayState", 2) # %% -# Open relevant file +# Open template file # ~~~~~~~~~~~~~~~~~~ -# Specify the working directory and open the relevant file for the -# thermal analysis. -working_folder = os.getcwd() -mcad.load_template("e8") -mcad_name = "e8_mobility" -mcad.save_to_file(os.path.join(working_folder, mcad_name)) - -mcad.load_from_file(os.path.join(working_folder, mcad_name + ".mot")) - -print("Initialization completed.") +# This example is based on the e8 IPM motor template. Open the template and save the file to the +# temporary folder. +mc.load_template("e8") +mc.save_to_file(working_folder + "/" + mot_name + ".mot") # %% -# Create analysis -# --------------- -# Creating the analysis consists of showing the thermal context, displaying -# the **Scripting** tab, setting parameters, and saving the file. - -# Show thermal context -# ----------------------- -mcad.show_thermal_context() - -# %% -# Display the **Scripting** tab. -mcad.display_screen("Scripting") +# Set Motor-CAD to Thermal +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Show the Thermal context in Motor-CAD and ensure that the BPM +# # Motor Type is set. +mc.show_thermal_context() +mc.set_variable("Motor_Type", 0) +print("Initialisation completed.") # %% -# Change the housing diameter. -mcad.set_variable("Housing_Dia", 250) +# Set up analysis +# --------------- +# Setting up the analysis consists of setting the model parameters and saving the file. +# +# Geometry setup +# ~~~~~~~~~~~~~~ +# Display the **Scripting** tab and set the housing outer diameter to 250 mm. +# +# .. note:: +# To set parameter values via automation with the GUI visible, a different tab must be displayed. +# The **Scripting** tab is chosen because no parameters on this tab will be changed in this +# script. It is best practice to display the **Scripting** tab when changing input parameters by +# automation. This is required only if the GUI is shown. +mc.display_screen("Scripting") +mc.set_variable("Housing_Dia", 250) # %% # Set the flow rate of the WJ fluid volume. -mcad.set_variable("WJ_Fluid_Volume_Flow_Rate", 0.002) +mc.set_variable("WJ_Fluid_Volume_Flow_Rate", 0.002) # %% # Set the temperature of the WJ fluid inlet. -mcad.set_variable("WJ_Fluid_Inlet_Temperature", 25) +mc.set_variable("WJ_Fluid_Inlet_Temperature", 25) # %% # Change the cooling fluid. -mcad.set_fluid("HousingWJFluid", "Dynalene HF-LO") +mc.set_fluid("HousingWJFluid", "Dynalene HF-LO") # %% # Set the heat transfer correlation. -mcad.set_variable("Calc/Input_h[WJ]_Rear_Housing", 1) -mcad.set_array_variable("HousingWJ_CalcInputH_A", 0, 1) +mc.set_variable("Calc/Input_h[WJ]_Rear_Housing", 1) +mc.set_array_variable("HousingWJ_CalcInputH_A", 0, 1) -wj_fluid_k = mcad.get_variable("WJ_Fluid_Thermal_Conductivity") -wj_fluid_rho = mcad.get_variable("WJ_Fluid_Density") -wj_fluid_mu = mcad.get_variable("WJ_Fluid_Dynamic_Viscosity") -wj_fluid_u_a = mcad.get_array_variable("HousingWJ_Velocity_A", 0) -wj_fluid_u_r = mcad.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") +wj_fluid_k = mc.get_variable("WJ_Fluid_Thermal_Conductivity") +wj_fluid_rho = mc.get_variable("WJ_Fluid_Density") +wj_fluid_mu = mc.get_variable("WJ_Fluid_Dynamic_Viscosity") +wj_fluid_u_a = mc.get_array_variable("HousingWJ_Velocity_A", 0) +wj_fluid_u_r = mc.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") h_A = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_a / wj_fluid_mu h_R = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_r / wj_fluid_mu @@ -99,33 +124,33 @@ print("h_A = ", h_A) print("h_R = ", h_R) -mcad.set_array_variable("HousingWJ_InputH_A", 0, h_A) -mcad.set_variable("Input_Value_h[WJ]_Rear_Housing", h_R) +mc.set_array_variable("HousingWJ_InputH_A", 0, h_A) +mc.set_variable("Input_Value_h[WJ]_Rear_Housing", h_R) # %% # Save the file. -mcad.save_to_file(os.path.join(working_folder, "../MotorCAD_Thermal_Python.mot")) +mc.save_to_file(os.path.join(working_folder, "../MotorCAD_Thermal_Python.mot")) # %% # Calculate steady state # ---------------------- # Calculate the steady state. try: - mcad.do_steady_state_analysis() + mc.do_steady_state_analysis() print("Thermal calculation successfully completed.") except pymotorcad.MotorCADError: print("Thermal calculation failed.") # %% # Retrieve the magnet temperature. -node_temperature = mcad.get_node_temperature(13) +node_temperature = mc.get_node_temperature(13) print("Node Temp = ", node_temperature) # %% # Retrieve the minimum, maximum, and average winding temperatures. -winding_temperature_min = mcad.get_variable("T_[Winding_Min]") -winding_temperature_max = mcad.get_variable("T_[Winding_Max]") -winding_temperature_average = mcad.get_variable("T_[Winding_Average]") +winding_temperature_min = mc.get_variable("T_[Winding_Min]") +winding_temperature_max = mc.get_variable("T_[Winding_Max]") +winding_temperature_average = mc.get_variable("T_[Winding_Average]") print("Min = ", winding_temperature_min) print("Max = ", winding_temperature_max) print("Average = ", winding_temperature_average) @@ -134,11 +159,11 @@ # Run simulation # -------------- # Run the transient simulation. -mcad.set_variable("Transient_Calculation_Type", 0) -mcad.set_variable("Transient_Time_Period", 60) +mc.set_variable("Transient_Calculation_Type", 0) +mc.set_variable("Transient_Time_Period", 60) try: - mcad.do_transient_analysis() + mc.do_transient_analysis() except pymotorcad.MotorCADError: print("Thermal calculation failed.") @@ -150,7 +175,7 @@ for timeStep in range(num_time_steps): try: - (x, y) = mcad.get_temperature_graph_point("Winding (Avg)", timeStep) + (x, y) = mc.get_temperature_graph_point("Winding (Avg)", timeStep) time.append(x) winding_temp_average_transient.append(y) except pymotorcad.MotorCADError: @@ -170,4 +195,4 @@ # Exit Motor-CAD # -------------- # Exit Motor-CAD. -mcad.quit() +mc.quit() diff --git a/src/ansys/motorcad/core/methods/rpc_methods_graphs.py b/src/ansys/motorcad/core/methods/rpc_methods_graphs.py index b8a4809dd..11f00da18 100644 --- a/src/ansys/motorcad/core/methods/rpc_methods_graphs.py +++ b/src/ansys/motorcad/core/methods/rpc_methods_graphs.py @@ -32,7 +32,14 @@ def _get_graph(self, graphing_func, *args): try: while True: try: - x, y = graphing_func(*args, loop) + # fea and magnetic 3D graph point functions require additional arguments + if len(args) > 1: + ( + x, + y, + ) = graphing_func(args[0], args[1], loop, args[2]) + else: + x, y = graphing_func(*args, loop) y_points.append(y) x_points.append(x) @@ -146,12 +153,12 @@ def get_fea_graph_point(self, graph_id, slice_number, point_number, time_step_nu graph_id : str, int Name (preferred) or ID of the graph. In Motor-CAD, you can select **Help -> Graph Viewer** to see the graph name. - slice_number - + slice_number : int + Slice number to get x and y coordinate values from. point_number : int Point number to get x and y coordinate values from. - time_step_number - + time_step_number : int + Time step number to get x and y coordinate values from. Returns ------- xValue : float @@ -163,6 +170,50 @@ def get_fea_graph_point(self, graph_id, slice_number, point_number, time_step_nu params = [{"variant": graph_id}, slice_number, point_number, time_step_number] return self.connection.send_and_receive(method, params) + def get_fea_graph(self, graph_name, slice_number, time_step_number): + """Get graph points from a Motor-CAD FEA graph. + + Parameters + ---------- + graph_name : str, int + Name (preferred) or ID of the graph. In Motor-CAD, you can + select **Help -> Graph Viewer** to see the graph name. + slice_number : int + Slice number to get x and y coordinate values from. + time_step_number : int + Time step number to get x and y coordinate values from. + Returns + ------- + x_values : list + Value of x coordinates from graph + y_values : list + Value of y coordinates from graph + """ + return self._get_graph(self.get_fea_graph_point, graph_name, slice_number, time_step_number) + + def get_magnetic_3d_graph(self, graph_name, slice_number, time_step_number): + """Get graph points from a Motor-CAD magnetic 3D graph. + + Parameters + ---------- + graph_name : str, int + Name (preferred) or ID of the graph. In Motor-CAD, you can + select **Help -> Graph Viewer** to see the graph name. + slice_number : int + Slice number to get x and y coordinate values from. + time_step_number : int + Time step number to get x and y coordinate values from. + Returns + ------- + x_values : list + Value of x coordinates from graph + y_values : list + Value of y coordinates from graph + """ + return self._get_graph( + self.get_magnetic_3d_graph_point, graph_name, slice_number, time_step_number + ) + def get_magnetic_graph(self, graph_name): """Get graph points from a Motor-CAD Magnetic graph. From ffff55706934adb23e385c93caef9104c852954d Mon Sep 17 00:00:00 2001 From: JackB-Ansys Date: Thu, 13 Jun 2024 10:50:02 +0100 Subject: [PATCH 3/7] Updates to thermal_basics.py --- examples/basics/thermal_basics.py | 44 ++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/examples/basics/thermal_basics.py b/examples/basics/thermal_basics.py index 221cfd114..b1a6bcabc 100644 --- a/examples/basics/thermal_basics.py +++ b/examples/basics/thermal_basics.py @@ -73,7 +73,7 @@ # Set Motor-CAD to Thermal # ~~~~~~~~~~~~~~~~~~~~~~~~ # Show the Thermal context in Motor-CAD and ensure that the BPM -# # Motor Type is set. +# Motor Type is set. mc.show_thermal_context() mc.set_variable("Motor_Type", 0) print("Initialisation completed.") @@ -81,7 +81,8 @@ # %% # Set up analysis # --------------- -# Setting up the analysis consists of setting the model parameters and saving the file. +# Setting up the analysis consists of setting the geometry and thermal input data parameters and +# saving the file. # # Geometry setup # ~~~~~~~~~~~~~~ @@ -96,40 +97,59 @@ mc.set_variable("Housing_Dia", 250) # %% -# Set the flow rate of the WJ fluid volume. +# Thermal input data setup +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Set the housing water jacket cooling parameters: +# +# * Fluid volume flow rate (in units of m\ :sup:`3`/s). +# +# * Fluid inlet temperature (in units of °C). +# +# * Fluid used by the HWJ (from material database). mc.set_variable("WJ_Fluid_Volume_Flow_Rate", 0.002) - -# %% -# Set the temperature of the WJ fluid inlet. mc.set_variable("WJ_Fluid_Inlet_Temperature", 25) +mc.set_fluid("HousingWJFluid", "Dynalene HF-LO") # %% -# Change the cooling fluid. -mc.set_fluid("HousingWJFluid", "Dynalene HF-LO") +# Disable the option for *Active Cooling Only*, so that the HWJ channel also cools the front and +# rear housing segments. +mc.set_variable("Water_Jacket_Active_Cooling_Only", 0) # %% -# Set the heat transfer correlation. +# Enable the *Input h* option to allow user input of the heat transfer coefficients for HWJ cooling +# of the rear and active segments of the housing. mc.set_variable("Calc/Input_h[WJ]_Rear_Housing", 1) mc.set_array_variable("HousingWJ_CalcInputH_A", 0, 1) +# %% +# Get fluid properties (thermal conductivity, density and dynamic viscosity) and the fluid +# velocities for the rear and active segments of the housing. Calculate new heat transfer +# coefficients for the rear and active segments of the housing. wj_fluid_k = mc.get_variable("WJ_Fluid_Thermal_Conductivity") wj_fluid_rho = mc.get_variable("WJ_Fluid_Density") wj_fluid_mu = mc.get_variable("WJ_Fluid_Dynamic_Viscosity") -wj_fluid_u_a = mc.get_array_variable("HousingWJ_Velocity_A", 0) + + +mc.initialise_tab_names() +mc.display_screen("Input Data;Housing Water Jacket;Heat Transfer") wj_fluid_u_r = mc.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") +wj_fluid_u_a = mc.get_array_variable("HousingWJ_Velocity_A", 0) -h_A = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_a / wj_fluid_mu h_R = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_r / wj_fluid_mu +h_A = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_a / wj_fluid_mu print("h_A = ", h_A) print("h_R = ", h_R) +# %% +# Set the calculated heat transfer coefficients for HWJ cooling of the rear and active segments of +# the housing. mc.set_array_variable("HousingWJ_InputH_A", 0, h_A) mc.set_variable("Input_Value_h[WJ]_Rear_Housing", h_R) # %% # Save the file. -mc.save_to_file(os.path.join(working_folder, "../MotorCAD_Thermal_Python.mot")) +mc.save_to_file(working_folder + "/" + mot_name + ".mot") # %% # Calculate steady state From 4539834e4f37a245ce94d54664faf53b4dae3fd3 Mon Sep 17 00:00:00 2001 From: JackB-Ansys Date: Thu, 13 Jun 2024 11:00:02 +0100 Subject: [PATCH 4/7] Updates to thermal_basics.py rolled back --- examples/basics/emag_basics.py | 6 +- examples/basics/thermal_basics.py | 177 +++++++++++------------------- 2 files changed, 70 insertions(+), 113 deletions(-) diff --git a/examples/basics/emag_basics.py b/examples/basics/emag_basics.py index bdb76621f..80ec9625c 100644 --- a/examples/basics/emag_basics.py +++ b/examples/basics/emag_basics.py @@ -3,10 +3,12 @@ Motor-CAD E-magnetic example script =================================== -This example provides a Motor-CAD E-magnetic script. This script will change model parameter values -(geometry, winding pattern and materials), run magnetic calculations, extract and plot results. +This example provides a Motor-CAD E-magnetic script to run calculations and plot results. """ # %% +# This script will change model parameter values (geometry, winding pattern and materials), +# run magnetic calculations, extract and plot results. +# # .. note:: # This script creates a partial custom winding pattern. To create a full winding pattern, # parameters must be specified for all coils. diff --git a/examples/basics/thermal_basics.py b/examples/basics/thermal_basics.py index b1a6bcabc..38ed64858 100644 --- a/examples/basics/thermal_basics.py +++ b/examples/basics/thermal_basics.py @@ -9,168 +9,123 @@ # %% # Set up example # -------------- -# To set up the example, perform imports, specify the working directory, launch Motor-CAD, and -# disable all popup messages from Motor-CAD. The e8 IPM motor template is loaded for the thermal -# analysis. -# +# Setting up this example consists of performing imports, launching +# Motor-CAD, disabling all popup messages from Motor-CAD, and +# opening the file for the thermal analysis. + # Perform required imports # ~~~~~~~~~~~~~~~~~~~~~~~~ -# Import ``pymotorcad`` to access Motor-CAD. Import ``pyplot`` from ``matplotlib`` to display -# graphics. Import ``os``, ``shutil`` and ``tempfile`` to open and save a temporary MOT -# file if none is open. - -# sphinx_gallery_thumbnail_number = -2 +# Import the required packages. import os -import shutil -import tempfile import matplotlib.pyplot as plt import ansys.motorcad.core as pymotorcad -# %% -# Specify working directory -# ~~~~~~~~~~~~~~~~~~~~~~~~~ -# Save the file to a temporary folder -working_folder = os.path.join(tempfile.gettempdir(), "basic_examples") -try: - shutil.rmtree(working_folder) -except: - pass -os.mkdir(working_folder) -mot_name = "e8_Thermal" +if "QT_API" in os.environ: + os.environ["QT_API"] = "pyqt" # %% # Launch Motor-CAD # ~~~~~~~~~~~~~~~~ -# Connect to Motor-CAD and open a new Motor-CAD instance. To keep a new Motor-CAD instance open -# after executing the script, use the ``MotorCAD(keep_instance_open=True)`` option when opening the -# new instance. -print("Starting initialisation.") -mc = pymotorcad.MotorCAD(keep_instance_open=True) +# Initialize ActiveX automation and launch Motor-CAD. +print("Starting initialization.") +mcad = pymotorcad.MotorCAD() # %% # Disable popup messages # ~~~~~~~~~~~~~~~~~~~~~~ -# Disable all popup messages from Motor-CAD by setting the ``MessageDisplayState`` parameter to 2. -# -# .. note:: -# This will also disable crucial popups, for example prompts to save data or overwrite data, or -# dialogs used to reconcile differences in material data between the database and MOT file. In -# each case the default action will be taken. This setting will persist until Motor-CAD is -# closed. -mc.set_variable("MessageDisplayState", 2) +# Disable all popup messages from Motor-CAD. +mcad.set_variable("MessageDisplayState", 2) # %% -# Open template file +# Open relevant file # ~~~~~~~~~~~~~~~~~~ -# This example is based on the e8 IPM motor template. Open the template and save the file to the -# temporary folder. -mc.load_template("e8") -mc.save_to_file(working_folder + "/" + mot_name + ".mot") +# Specify the working directory and open the relevant file for the +# thermal analysis. +working_folder = os.getcwd() +mcad.load_template("e8") +mcad_name = "e8_mobility" +mcad.save_to_file(os.path.join(working_folder, mcad_name)) -# %% -# Set Motor-CAD to Thermal -# ~~~~~~~~~~~~~~~~~~~~~~~~ -# Show the Thermal context in Motor-CAD and ensure that the BPM -# Motor Type is set. -mc.show_thermal_context() -mc.set_variable("Motor_Type", 0) -print("Initialisation completed.") +mcad.load_from_file(os.path.join(working_folder, mcad_name + ".mot")) + +print("Initialization completed.") # %% -# Set up analysis +# Create analysis # --------------- -# Setting up the analysis consists of setting the geometry and thermal input data parameters and -# saving the file. -# -# Geometry setup -# ~~~~~~~~~~~~~~ -# Display the **Scripting** tab and set the housing outer diameter to 250 mm. -# -# .. note:: -# To set parameter values via automation with the GUI visible, a different tab must be displayed. -# The **Scripting** tab is chosen because no parameters on this tab will be changed in this -# script. It is best practice to display the **Scripting** tab when changing input parameters by -# automation. This is required only if the GUI is shown. -mc.display_screen("Scripting") -mc.set_variable("Housing_Dia", 250) - -# %% -# Thermal input data setup -# ~~~~~~~~~~~~~~~~~~~~~~~~ -# Set the housing water jacket cooling parameters: -# -# * Fluid volume flow rate (in units of m\ :sup:`3`/s). -# -# * Fluid inlet temperature (in units of °C). -# -# * Fluid used by the HWJ (from material database). -mc.set_variable("WJ_Fluid_Volume_Flow_Rate", 0.002) -mc.set_variable("WJ_Fluid_Inlet_Temperature", 25) -mc.set_fluid("HousingWJFluid", "Dynalene HF-LO") +# Creating the analysis consists of showing the thermal context, displaying +# the **Scripting** tab, setting parameters, and saving the file. + +# Show thermal context +# ----------------------- +mcad.show_thermal_context() # %% -# Disable the option for *Active Cooling Only*, so that the HWJ channel also cools the front and -# rear housing segments. -mc.set_variable("Water_Jacket_Active_Cooling_Only", 0) +# Display the **Scripting** tab. +mcad.display_screen("Scripting") # %% -# Enable the *Input h* option to allow user input of the heat transfer coefficients for HWJ cooling -# of the rear and active segments of the housing. -mc.set_variable("Calc/Input_h[WJ]_Rear_Housing", 1) -mc.set_array_variable("HousingWJ_CalcInputH_A", 0, 1) +# Change the housing diameter. +mcad.set_variable("Housing_Dia", 250) # %% -# Get fluid properties (thermal conductivity, density and dynamic viscosity) and the fluid -# velocities for the rear and active segments of the housing. Calculate new heat transfer -# coefficients for the rear and active segments of the housing. -wj_fluid_k = mc.get_variable("WJ_Fluid_Thermal_Conductivity") -wj_fluid_rho = mc.get_variable("WJ_Fluid_Density") -wj_fluid_mu = mc.get_variable("WJ_Fluid_Dynamic_Viscosity") +# Set the flow rate of the WJ fluid volume. +mcad.set_variable("WJ_Fluid_Volume_Flow_Rate", 0.002) +# %% +# Set the temperature of the WJ fluid inlet. +mcad.set_variable("WJ_Fluid_Inlet_Temperature", 25) -mc.initialise_tab_names() -mc.display_screen("Input Data;Housing Water Jacket;Heat Transfer") -wj_fluid_u_r = mc.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") -wj_fluid_u_a = mc.get_array_variable("HousingWJ_Velocity_A", 0) +# %% +# Change the cooling fluid. +mcad.set_fluid("HousingWJFluid", "Dynalene HF-LO") + +# %% +# Set the heat transfer correlation. +mcad.set_variable("Calc/Input_h[WJ]_Rear_Housing", 1) +mcad.set_array_variable("HousingWJ_CalcInputH_A", 0, 1) + +wj_fluid_k = mcad.get_variable("WJ_Fluid_Thermal_Conductivity") +wj_fluid_rho = mcad.get_variable("WJ_Fluid_Density") +wj_fluid_mu = mcad.get_variable("WJ_Fluid_Dynamic_Viscosity") +wj_fluid_u_a = mcad.get_array_variable("HousingWJ_Velocity_A", 0) +wj_fluid_u_r = mcad.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") -h_R = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_r / wj_fluid_mu h_A = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_a / wj_fluid_mu +h_R = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_r / wj_fluid_mu print("h_A = ", h_A) print("h_R = ", h_R) -# %% -# Set the calculated heat transfer coefficients for HWJ cooling of the rear and active segments of -# the housing. -mc.set_array_variable("HousingWJ_InputH_A", 0, h_A) -mc.set_variable("Input_Value_h[WJ]_Rear_Housing", h_R) +mcad.set_array_variable("HousingWJ_InputH_A", 0, h_A) +mcad.set_variable("Input_Value_h[WJ]_Rear_Housing", h_R) # %% # Save the file. -mc.save_to_file(working_folder + "/" + mot_name + ".mot") +mcad.save_to_file(os.path.join(working_folder, "../MotorCAD_Thermal_Python.mot")) # %% # Calculate steady state # ---------------------- # Calculate the steady state. try: - mc.do_steady_state_analysis() + mcad.do_steady_state_analysis() print("Thermal calculation successfully completed.") except pymotorcad.MotorCADError: print("Thermal calculation failed.") # %% # Retrieve the magnet temperature. -node_temperature = mc.get_node_temperature(13) +node_temperature = mcad.get_node_temperature(13) print("Node Temp = ", node_temperature) # %% # Retrieve the minimum, maximum, and average winding temperatures. -winding_temperature_min = mc.get_variable("T_[Winding_Min]") -winding_temperature_max = mc.get_variable("T_[Winding_Max]") -winding_temperature_average = mc.get_variable("T_[Winding_Average]") +winding_temperature_min = mcad.get_variable("T_[Winding_Min]") +winding_temperature_max = mcad.get_variable("T_[Winding_Max]") +winding_temperature_average = mcad.get_variable("T_[Winding_Average]") print("Min = ", winding_temperature_min) print("Max = ", winding_temperature_max) print("Average = ", winding_temperature_average) @@ -179,11 +134,11 @@ # Run simulation # -------------- # Run the transient simulation. -mc.set_variable("Transient_Calculation_Type", 0) -mc.set_variable("Transient_Time_Period", 60) +mcad.set_variable("Transient_Calculation_Type", 0) +mcad.set_variable("Transient_Time_Period", 60) try: - mc.do_transient_analysis() + mcad.do_transient_analysis() except pymotorcad.MotorCADError: print("Thermal calculation failed.") @@ -195,7 +150,7 @@ for timeStep in range(num_time_steps): try: - (x, y) = mc.get_temperature_graph_point("Winding (Avg)", timeStep) + (x, y) = mcad.get_temperature_graph_point("Winding (Avg)", timeStep) time.append(x) winding_temp_average_transient.append(y) except pymotorcad.MotorCADError: @@ -215,4 +170,4 @@ # Exit Motor-CAD # -------------- # Exit Motor-CAD. -mc.quit() +mcad.quit() From 32dc007e70202ee779854cfa7ce4eef2d9a60cb9 Mon Sep 17 00:00:00 2001 From: JackB-Ansys Date: Thu, 13 Jun 2024 11:13:35 +0100 Subject: [PATCH 5/7] Updates to thermal_basics.py example --- examples/basics/thermal_basics.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/basics/thermal_basics.py b/examples/basics/thermal_basics.py index 38ed64858..22d7bacf8 100644 --- a/examples/basics/thermal_basics.py +++ b/examples/basics/thermal_basics.py @@ -3,10 +3,14 @@ Motor-CAD thermal example script ================================ -This example provides a Motor-CAD thermal script. +This example provides a Motor-CAD thermal script to run calculations and plot results. """ - # %% +# This script will change thermal model input data parameter values (geometry, housing water +# jacket), run thermal steady state and transient calculations, extract and plot results. The +# Motor-CAD heat transfer correlations for housing water jacket cooling are disabled and +# user-defined heat transfer coefficients are specified. +# # Set up example # -------------- # Setting up this example consists of performing imports, launching From 9c53810131bf44aad5026ae26b0cd26c026ae230 Mon Sep 17 00:00:00 2001 From: JackB-Ansys Date: Thu, 13 Jun 2024 11:27:34 +0100 Subject: [PATCH 6/7] Updates to thermal_basics.py example --- examples/basics/thermal_basics.py | 181 ++++++++++++++++++------------ 1 file changed, 111 insertions(+), 70 deletions(-) diff --git a/examples/basics/thermal_basics.py b/examples/basics/thermal_basics.py index 22d7bacf8..b1a6bcabc 100644 --- a/examples/basics/thermal_basics.py +++ b/examples/basics/thermal_basics.py @@ -3,133 +3,174 @@ Motor-CAD thermal example script ================================ -This example provides a Motor-CAD thermal script to run calculations and plot results. +This example provides a Motor-CAD thermal script. """ + # %% -# This script will change thermal model input data parameter values (geometry, housing water -# jacket), run thermal steady state and transient calculations, extract and plot results. The -# Motor-CAD heat transfer correlations for housing water jacket cooling are disabled and -# user-defined heat transfer coefficients are specified. -# # Set up example # -------------- -# Setting up this example consists of performing imports, launching -# Motor-CAD, disabling all popup messages from Motor-CAD, and -# opening the file for the thermal analysis. - +# To set up the example, perform imports, specify the working directory, launch Motor-CAD, and +# disable all popup messages from Motor-CAD. The e8 IPM motor template is loaded for the thermal +# analysis. +# # Perform required imports # ~~~~~~~~~~~~~~~~~~~~~~~~ -# Import the required packages. +# Import ``pymotorcad`` to access Motor-CAD. Import ``pyplot`` from ``matplotlib`` to display +# graphics. Import ``os``, ``shutil`` and ``tempfile`` to open and save a temporary MOT +# file if none is open. + +# sphinx_gallery_thumbnail_number = -2 import os +import shutil +import tempfile import matplotlib.pyplot as plt import ansys.motorcad.core as pymotorcad -if "QT_API" in os.environ: - os.environ["QT_API"] = "pyqt" +# %% +# Specify working directory +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# Save the file to a temporary folder +working_folder = os.path.join(tempfile.gettempdir(), "basic_examples") +try: + shutil.rmtree(working_folder) +except: + pass +os.mkdir(working_folder) +mot_name = "e8_Thermal" # %% # Launch Motor-CAD # ~~~~~~~~~~~~~~~~ -# Initialize ActiveX automation and launch Motor-CAD. -print("Starting initialization.") -mcad = pymotorcad.MotorCAD() +# Connect to Motor-CAD and open a new Motor-CAD instance. To keep a new Motor-CAD instance open +# after executing the script, use the ``MotorCAD(keep_instance_open=True)`` option when opening the +# new instance. +print("Starting initialisation.") +mc = pymotorcad.MotorCAD(keep_instance_open=True) # %% # Disable popup messages # ~~~~~~~~~~~~~~~~~~~~~~ -# Disable all popup messages from Motor-CAD. -mcad.set_variable("MessageDisplayState", 2) +# Disable all popup messages from Motor-CAD by setting the ``MessageDisplayState`` parameter to 2. +# +# .. note:: +# This will also disable crucial popups, for example prompts to save data or overwrite data, or +# dialogs used to reconcile differences in material data between the database and MOT file. In +# each case the default action will be taken. This setting will persist until Motor-CAD is +# closed. +mc.set_variable("MessageDisplayState", 2) # %% -# Open relevant file +# Open template file # ~~~~~~~~~~~~~~~~~~ -# Specify the working directory and open the relevant file for the -# thermal analysis. -working_folder = os.getcwd() -mcad.load_template("e8") -mcad_name = "e8_mobility" -mcad.save_to_file(os.path.join(working_folder, mcad_name)) - -mcad.load_from_file(os.path.join(working_folder, mcad_name + ".mot")) - -print("Initialization completed.") +# This example is based on the e8 IPM motor template. Open the template and save the file to the +# temporary folder. +mc.load_template("e8") +mc.save_to_file(working_folder + "/" + mot_name + ".mot") # %% -# Create analysis -# --------------- -# Creating the analysis consists of showing the thermal context, displaying -# the **Scripting** tab, setting parameters, and saving the file. - -# Show thermal context -# ----------------------- -mcad.show_thermal_context() +# Set Motor-CAD to Thermal +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Show the Thermal context in Motor-CAD and ensure that the BPM +# Motor Type is set. +mc.show_thermal_context() +mc.set_variable("Motor_Type", 0) +print("Initialisation completed.") # %% -# Display the **Scripting** tab. -mcad.display_screen("Scripting") +# Set up analysis +# --------------- +# Setting up the analysis consists of setting the geometry and thermal input data parameters and +# saving the file. +# +# Geometry setup +# ~~~~~~~~~~~~~~ +# Display the **Scripting** tab and set the housing outer diameter to 250 mm. +# +# .. note:: +# To set parameter values via automation with the GUI visible, a different tab must be displayed. +# The **Scripting** tab is chosen because no parameters on this tab will be changed in this +# script. It is best practice to display the **Scripting** tab when changing input parameters by +# automation. This is required only if the GUI is shown. +mc.display_screen("Scripting") +mc.set_variable("Housing_Dia", 250) # %% -# Change the housing diameter. -mcad.set_variable("Housing_Dia", 250) +# Thermal input data setup +# ~~~~~~~~~~~~~~~~~~~~~~~~ +# Set the housing water jacket cooling parameters: +# +# * Fluid volume flow rate (in units of m\ :sup:`3`/s). +# +# * Fluid inlet temperature (in units of °C). +# +# * Fluid used by the HWJ (from material database). +mc.set_variable("WJ_Fluid_Volume_Flow_Rate", 0.002) +mc.set_variable("WJ_Fluid_Inlet_Temperature", 25) +mc.set_fluid("HousingWJFluid", "Dynalene HF-LO") # %% -# Set the flow rate of the WJ fluid volume. -mcad.set_variable("WJ_Fluid_Volume_Flow_Rate", 0.002) +# Disable the option for *Active Cooling Only*, so that the HWJ channel also cools the front and +# rear housing segments. +mc.set_variable("Water_Jacket_Active_Cooling_Only", 0) # %% -# Set the temperature of the WJ fluid inlet. -mcad.set_variable("WJ_Fluid_Inlet_Temperature", 25) +# Enable the *Input h* option to allow user input of the heat transfer coefficients for HWJ cooling +# of the rear and active segments of the housing. +mc.set_variable("Calc/Input_h[WJ]_Rear_Housing", 1) +mc.set_array_variable("HousingWJ_CalcInputH_A", 0, 1) # %% -# Change the cooling fluid. -mcad.set_fluid("HousingWJFluid", "Dynalene HF-LO") +# Get fluid properties (thermal conductivity, density and dynamic viscosity) and the fluid +# velocities for the rear and active segments of the housing. Calculate new heat transfer +# coefficients for the rear and active segments of the housing. +wj_fluid_k = mc.get_variable("WJ_Fluid_Thermal_Conductivity") +wj_fluid_rho = mc.get_variable("WJ_Fluid_Density") +wj_fluid_mu = mc.get_variable("WJ_Fluid_Dynamic_Viscosity") -# %% -# Set the heat transfer correlation. -mcad.set_variable("Calc/Input_h[WJ]_Rear_Housing", 1) -mcad.set_array_variable("HousingWJ_CalcInputH_A", 0, 1) -wj_fluid_k = mcad.get_variable("WJ_Fluid_Thermal_Conductivity") -wj_fluid_rho = mcad.get_variable("WJ_Fluid_Density") -wj_fluid_mu = mcad.get_variable("WJ_Fluid_Dynamic_Viscosity") -wj_fluid_u_a = mcad.get_array_variable("HousingWJ_Velocity_A", 0) -wj_fluid_u_r = mcad.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") +mc.initialise_tab_names() +mc.display_screen("Input Data;Housing Water Jacket;Heat Transfer") +wj_fluid_u_r = mc.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") +wj_fluid_u_a = mc.get_array_variable("HousingWJ_Velocity_A", 0) -h_A = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_a / wj_fluid_mu h_R = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_r / wj_fluid_mu +h_A = 0.005 * wj_fluid_k * wj_fluid_rho * wj_fluid_u_a / wj_fluid_mu print("h_A = ", h_A) print("h_R = ", h_R) -mcad.set_array_variable("HousingWJ_InputH_A", 0, h_A) -mcad.set_variable("Input_Value_h[WJ]_Rear_Housing", h_R) +# %% +# Set the calculated heat transfer coefficients for HWJ cooling of the rear and active segments of +# the housing. +mc.set_array_variable("HousingWJ_InputH_A", 0, h_A) +mc.set_variable("Input_Value_h[WJ]_Rear_Housing", h_R) # %% # Save the file. -mcad.save_to_file(os.path.join(working_folder, "../MotorCAD_Thermal_Python.mot")) +mc.save_to_file(working_folder + "/" + mot_name + ".mot") # %% # Calculate steady state # ---------------------- # Calculate the steady state. try: - mcad.do_steady_state_analysis() + mc.do_steady_state_analysis() print("Thermal calculation successfully completed.") except pymotorcad.MotorCADError: print("Thermal calculation failed.") # %% # Retrieve the magnet temperature. -node_temperature = mcad.get_node_temperature(13) +node_temperature = mc.get_node_temperature(13) print("Node Temp = ", node_temperature) # %% # Retrieve the minimum, maximum, and average winding temperatures. -winding_temperature_min = mcad.get_variable("T_[Winding_Min]") -winding_temperature_max = mcad.get_variable("T_[Winding_Max]") -winding_temperature_average = mcad.get_variable("T_[Winding_Average]") +winding_temperature_min = mc.get_variable("T_[Winding_Min]") +winding_temperature_max = mc.get_variable("T_[Winding_Max]") +winding_temperature_average = mc.get_variable("T_[Winding_Average]") print("Min = ", winding_temperature_min) print("Max = ", winding_temperature_max) print("Average = ", winding_temperature_average) @@ -138,11 +179,11 @@ # Run simulation # -------------- # Run the transient simulation. -mcad.set_variable("Transient_Calculation_Type", 0) -mcad.set_variable("Transient_Time_Period", 60) +mc.set_variable("Transient_Calculation_Type", 0) +mc.set_variable("Transient_Time_Period", 60) try: - mcad.do_transient_analysis() + mc.do_transient_analysis() except pymotorcad.MotorCADError: print("Thermal calculation failed.") @@ -154,7 +195,7 @@ for timeStep in range(num_time_steps): try: - (x, y) = mcad.get_temperature_graph_point("Winding (Avg)", timeStep) + (x, y) = mc.get_temperature_graph_point("Winding (Avg)", timeStep) time.append(x) winding_temp_average_transient.append(y) except pymotorcad.MotorCADError: @@ -174,4 +215,4 @@ # Exit Motor-CAD # -------------- # Exit Motor-CAD. -mcad.quit() +mc.quit() From e8cdf3974a6f8e1e2e7d7f654de0aa5df8908869 Mon Sep 17 00:00:00 2001 From: JackB-Ansys Date: Thu, 13 Jun 2024 12:04:13 +0100 Subject: [PATCH 7/7] Updates to thermal_basics.py example --- examples/basics/thermal_basics.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/basics/thermal_basics.py b/examples/basics/thermal_basics.py index b1a6bcabc..2c8c918ec 100644 --- a/examples/basics/thermal_basics.py +++ b/examples/basics/thermal_basics.py @@ -124,14 +124,19 @@ # %% # Get fluid properties (thermal conductivity, density and dynamic viscosity) and the fluid # velocities for the rear and active segments of the housing. Calculate new heat transfer -# coefficients for the rear and active segments of the housing. +# coefficients for the rear and active segments of the housing. Run a steady state thermal +# calculation to ensure that the fluid properties and velocities are correctly calculated based on +# the model changes made earlier. +# +# .. note:: +# Some Motor-CAD output parameters are not automatically updated when an input parameter is set. +# Outputs will be updated when a steady state thermal calculation runs. Alternatively, the +# relevant tab (for example, *Input Data -> Housing Water Jacket -> Heat Transfer*) can be +# displayed - however this may not be suitable when running Motor-CAD without the GUI. +mc.do_steady_state_analysis() wj_fluid_k = mc.get_variable("WJ_Fluid_Thermal_Conductivity") wj_fluid_rho = mc.get_variable("WJ_Fluid_Density") wj_fluid_mu = mc.get_variable("WJ_Fluid_Dynamic_Viscosity") - - -mc.initialise_tab_names() -mc.display_screen("Input Data;Housing Water Jacket;Heat Transfer") wj_fluid_u_r = mc.get_variable("WJ_Channel_Fluid_Velocity_[Rear]") wj_fluid_u_a = mc.get_array_variable("HousingWJ_Velocity_A", 0)