{ "cells": [ { "cell_type": "markdown", "id": "0e219389", "metadata": {}, "source": [ "# IPM geometry optimization\n", "\n", "This example shows how to use PyAEDT to find the best machine 2D geometry\n", "to achieve high torque and low losses.\n", "The example shows how to setup an optimetrics analysis to sweep geometries\n", "for a single value of stator current angle and a varying material for the magnets.\n", "The torque and losses results are then exported in a .csv file.\n", "\n", "Keywords: **Maxwell 2D**, **transient**, **motor**, **optimization**." ] }, { "cell_type": "markdown", "id": "96506367", "metadata": {}, "source": [ "## Perform imports and define constants\n", "\n", "Perform required imports." ] }, { "cell_type": "code", "execution_count": null, "id": "c5e6c6ac", "metadata": {}, "outputs": [], "source": [ "import csv\n", "import os\n", "import tempfile\n", "import time\n", "\n", "import ansys.aedt.core\n", "from ansys.aedt.core.examples.downloads import download_file\n" ] }, { "cell_type": "markdown", "id": "f9924e6d", "metadata": {}, "source": [ "Define constants." ] }, { "cell_type": "code", "execution_count": null, "id": "5c20f37b", "metadata": {}, "outputs": [], "source": [ "AEDT_VERSION = \"2025.2\"\n", "NUM_CORES = 4\n", "NG_MODE = False # Open AEDT UI when it is launched." ] }, { "cell_type": "markdown", "id": "dbd084a0", "metadata": {}, "source": [ "## Create temporary directory and download files\n", "\n", "Create a temporary directory where downloaded data or\n", "dumped data can be stored.\n", "If you'd like to retrieve the project data for subsequent use,\n", "the temporary folder name is given by ``temp_folder.name``." ] }, { "cell_type": "code", "execution_count": null, "id": "421001e3", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "5a37ddf3", "metadata": {}, "source": [ "## Download AEDT file example\n", "\n", "Set the local temporary folder to export the AEDT file to." ] }, { "cell_type": "code", "execution_count": null, "id": "e5532f7f", "metadata": {}, "outputs": [], "source": [ "aedt_file = download_file(\n", " source=\"maxwell_motor_optimization\",\n", " name=\"IPM_optimization.aedt\",\n", " local_path=temp_folder.name,\n", ")" ] }, { "cell_type": "markdown", "id": "f3b2fd57", "metadata": {}, "source": [ "## Launch Maxwell 2D\n", "\n", "Launch AEDT and Maxwell 2D after first setting up the project, the version and the graphical mode." ] }, { "cell_type": "code", "execution_count": null, "id": "24d722ec", "metadata": {}, "outputs": [], "source": [ "m2d = ansys.aedt.core.Maxwell2d(\n", " project=aedt_file,\n", " version=AEDT_VERSION,\n", " new_desktop=True,\n", " non_graphical=NG_MODE,\n", ")" ] }, { "cell_type": "markdown", "id": "4e94d3bc", "metadata": {}, "source": [ "## Design variables\n", "\n", "Define the materials array to be used in the parametric sweep." ] }, { "cell_type": "code", "execution_count": null, "id": "eac9ec48", "metadata": {}, "outputs": [], "source": [ "m2d[\"mat_sweep\"] = '[\"XG196/96_2DSF1.000_X\", \"NdFe30\", \"NdFe35\"]'\n", "m2d[\"mat_index\"] = 0" ] }, { "cell_type": "markdown", "id": "af6487fe", "metadata": {}, "source": [ "## Assign material array to magnets\n", "\n", "Get all magnets in the design that by default have the material ``\"XG196/96_2DSF1.000_X\"`` assigned.\n", "Assign the material array defined above to all magnets." ] }, { "cell_type": "code", "execution_count": null, "id": "b835cdca", "metadata": {}, "outputs": [], "source": [ "magnets = m2d.modeler.get_objects_by_material(\"XG196/96_2DSF1.000_X\")" ] }, { "cell_type": "code", "execution_count": null, "id": "82a536cf", "metadata": {}, "outputs": [], "source": [ "for mag in magnets:\n", " mag.material_name = \"mat_sweep[mat_index]\"" ] }, { "cell_type": "markdown", "id": "7466d720", "metadata": {}, "source": [ "## Add parametric setup\n", "\n", "Add a parametric setup made up of geometry variable sweep definitions and single value for the stator current angle.\n", "Note: Step variations have been minimized to reduce the analysis time. If needed they can be increased by changing\n", "the ``step`` argument." ] }, { "cell_type": "code", "execution_count": null, "id": "0c09d7a4", "metadata": {}, "outputs": [], "source": [ "param_sweep = m2d.parametrics.add(\n", " variable=\"bridge\",\n", " start_point=\"0.5mm\",\n", " variation_type=\"SingleValue\",\n", ")\n", "param_sweep.add_variation(\n", " sweep_variable=\"din\",\n", " start_point=78,\n", " end_point=80,\n", " step=10,\n", " units=\"mm\",\n", " variation_type=\"LinearStep\",\n", ")\n", "param_sweep.add_variation(\n", " sweep_variable=\"phase_advance\",\n", " start_point=45,\n", " units=\"deg\",\n", " variation_type=\"SingleValue\",\n", ")\n", "param_sweep.add_variation(\n", " sweep_variable=\"Ipeak\", start_point=200, units=\"A\", variation_type=\"SingleValue\"\n", ")" ] }, { "cell_type": "markdown", "id": "a68aad99", "metadata": {}, "source": [ "Add material variation to the parametric setup and sweep the index of the material array defined above." ] }, { "cell_type": "code", "execution_count": null, "id": "92473237", "metadata": {}, "outputs": [], "source": [ "param_sweep.add_variation(\n", " sweep_variable=\"mat_index\",\n", " start_point=0,\n", " end_point=2,\n", " step=1,\n", " variation_type=\"LinearStep\",\n", ")" ] }, { "cell_type": "markdown", "id": "00eb6ece", "metadata": {}, "source": [ "## Alternative way to add a parametric setup from file\n", "\n", "Suppose you have a .csv file with all the parameters to be swept defined in columns, such as:\n", "\n", "# \"\"\n", "\n", "You can add a parametric setup from that file using the ``add_from_file`` method:" ] }, { "cell_type": "code", "execution_count": null, "id": "c936a7c5", "metadata": {}, "outputs": [], "source": [ "# param_sweep_from_file = m2d.parametrics.add_from_file(csv_file_path)" ] }, { "cell_type": "markdown", "id": "b1d165cc", "metadata": {}, "source": [ "## Analyze parametric sweep" ] }, { "cell_type": "markdown", "id": "b1b26778", "metadata": {}, "source": [ "To speed up the analysis, the time step is increased in the transient setup.\n", "This can be done by modifying the ``TimeStep`` property of the transient setup.\n", "Note: In a real case scenario, the time step should be: ``1/freq_e/360``.\n", "To simulate a real case scenario, please comment out the following line." ] }, { "cell_type": "code", "execution_count": null, "id": "6abcf5b7", "metadata": {}, "outputs": [], "source": [ "m2d.setups[0].props[\"TimeStep\"] = \"1/freq_e/45\"\n", "param_sweep.analyze(cores=NUM_CORES)" ] }, { "cell_type": "markdown", "id": "8a0b3da2", "metadata": {}, "source": [ "## Post-processing\n", "\n", "Create reports to get torque and loss results for all variations.\n", "Create reports with all variations and with one variable at a time held constant.\n", "This helps to visualize the influence of each variable on the torque and losses.\n", "For the first torque report the ``din`` variable is held constant at 78mm." ] }, { "cell_type": "code", "execution_count": null, "id": "090e97c1", "metadata": {}, "outputs": [], "source": [ "report_torque_din_costant = m2d.post.create_report(\n", " expressions=\"Moving1.Torque\",\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"78mm\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"All\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " plot_type=\"Rectangular Plot\",\n", " plot_name=\"torque_din_costant\",\n", ")" ] }, { "cell_type": "markdown", "id": "63603566", "metadata": {}, "source": [ "The second torque report has the ``mat_index`` variable held constant at 0.\n", "In this case the material used for the magnets is ``\"XG196/96_2DSF1.000_X\"``." ] }, { "cell_type": "code", "execution_count": null, "id": "803386ef", "metadata": {}, "outputs": [], "source": [ "report_torque_mat_costant = m2d.post.create_report(\n", " expressions=\"Moving1.Torque\",\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"All\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"0\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " plot_type=\"Rectangular Plot\",\n", " plot_name=\"torque_mat_costant\",\n", ")" ] }, { "cell_type": "markdown", "id": "1602ccce", "metadata": {}, "source": [ "The same approach is used to create reports for solid and core losses." ] }, { "cell_type": "code", "execution_count": null, "id": "6f8cfd2a", "metadata": {}, "outputs": [], "source": [ "report_solid_loss_din_costant = m2d.post.create_report(\n", " expressions=\"SolidLoss\",\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"78mm\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"All\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " plot_type=\"Rectangular Plot\",\n", " plot_name=\"solid_loss_din_costant\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "1aef13be", "metadata": {}, "outputs": [], "source": [ "report_solid_loss_mat_costant = m2d.post.create_report(\n", " expressions=\"SolidLoss\",\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"All\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"0\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " plot_type=\"Rectangular Plot\",\n", " plot_name=\"solid_loss_mat_costant\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "06b0592a", "metadata": {}, "outputs": [], "source": [ "report_core_loss_din_costant = m2d.post.create_report(\n", " expressions=\"CoreLoss\",\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"78mm\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"All\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " plot_type=\"Rectangular Plot\",\n", " plot_name=\"core_loss_din_costant\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "b120d305", "metadata": {}, "outputs": [], "source": [ "report_core_loss_mat_costant = m2d.post.create_report(\n", " expressions=\"CoreLoss\",\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"All\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"0\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " plot_type=\"Rectangular Plot\",\n", " plot_name=\"core_loss_mat_costant\",\n", ")" ] }, { "cell_type": "markdown", "id": "fe143de3", "metadata": {}, "source": [ "Get torque and loss solution data for all variations." ] }, { "cell_type": "code", "execution_count": null, "id": "df2569e3", "metadata": {}, "outputs": [], "source": [ "torque_data = m2d.post.get_solution_data(\n", " expressions=[\"Moving1.Torque\"],\n", " setup_sweep_name=m2d.nominal_sweep,\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"All\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"All\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " report_category=\"Standard\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "3f9efb9c", "metadata": {}, "outputs": [], "source": [ "solid_loss_data = m2d.post.get_solution_data(\n", " expressions=[\"SolidLoss\"],\n", " setup_sweep_name=m2d.nominal_sweep,\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"All\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"All\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " report_category=\"Standard\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "d4c4ac74", "metadata": {}, "outputs": [], "source": [ "core_loss_data = m2d.post.get_solution_data(\n", " expressions=[\"CoreLoss\"],\n", " setup_sweep_name=m2d.nominal_sweep,\n", " domain=\"Sweep\",\n", " variations={\n", " \"bridge\": \"All\",\n", " \"din\": \"All\",\n", " \"Ipeak\": \"All\",\n", " \"phase_advance\": \"All\",\n", " \"mat_index\": \"All\",\n", " },\n", " primary_sweep_variable=\"Time\",\n", " report_category=\"Standard\",\n", ")" ] }, { "cell_type": "markdown", "id": "38d8c7d5", "metadata": {}, "source": [ "Calculate torque and loss average values for each variation and write data in a .csv file." ] }, { "cell_type": "code", "execution_count": null, "id": "95016900", "metadata": {}, "outputs": [], "source": [ "csv_data = []\n", "for var in core_loss_data.variations:\n", " torque_data.active_variation = var\n", " core_loss_data.active_variation = var\n", " solid_loss_data.active_variation = var\n", "\n", " torque_values = torque_data.get_expression_data(formula=\"magnitude\")[1]\n", " core_loss_values = core_loss_data.get_expression_data(formula=\"magnitude\")[1]\n", " solid_loss_values = solid_loss_data.get_expression_data(formula=\"magnitude\")[1]\n", "\n", " torque_data_average = sum(torque_values) / len(torque_values)\n", " core_loss_average = sum(core_loss_values) / len(core_loss_values)\n", " solid_loss_average = sum(solid_loss_values) / len(solid_loss_values)\n", "\n", " csv_data.append(\n", " {\n", " \"active_variation\": str(torque_data.active_variation),\n", " \"average_torque\": str(torque_data_average),\n", " \"average_core_loss\": str(core_loss_average),\n", " \"average_solid_loss\": str(solid_loss_average),\n", " }\n", " )\n", "\n", " with open(\n", " os.path.join(temp_folder.name, \"motor_optimization.csv\"), \"w\", newline=\"\"\n", " ) as csvfile:\n", " fields = [\n", " \"active_variation\",\n", " \"average_torque\",\n", " \"average_core_loss\",\n", " \"average_solid_loss\",\n", " ]\n", " writer = csv.DictWriter(csvfile, fieldnames=fields)\n", " writer.writeheader()\n", " writer.writerows(csv_data)" ] }, { "cell_type": "markdown", "id": "8cab497a", "metadata": {}, "source": [ "## Release AEDT" ] }, { "cell_type": "code", "execution_count": null, "id": "848222d5", "metadata": {}, "outputs": [], "source": [ "m2d.save_project()\n", "m2d.release_desktop()\n", "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", "time.sleep(3)" ] }, { "cell_type": "markdown", "id": "14207334", "metadata": {}, "source": [ "## Clean up\n", "\n", "All project files are saved in the folder ``temp_folder.name``.\n", "If you've run this example as a Jupyter notebook, you\n", "can retrieve those project files. The following cell\n", "removes all temporary files, including the project folder." ] }, { "cell_type": "code", "execution_count": null, "id": "0df7e945", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }