{ "cells": [ { "cell_type": "markdown", "id": "8575c5b1", "metadata": {}, "source": [ "# Asymmetric conductor analysis\n", "\n", "This example uses PyAEDT to set up the TEAM 7 problem for an asymmetric\n", "conductor with a hole and solve it using the Maxwell 3D eddy current solver.\n", "For more information on this problem, see this\n", "[paper](https://www.compumag.org/wp/wp-content/uploads/2018/06/problem7.pdf).\n", "\n", "Keywords: **Maxwell 3D**, **Asymmetric conductor**." ] }, { "cell_type": "markdown", "id": "6862de0f", "metadata": {}, "source": [ "## Prerequisites\n", "\n", "### Perform imports" ] }, { "cell_type": "code", "execution_count": null, "id": "659648d1", "metadata": {}, "outputs": [], "source": [ "import os\n", "import tempfile\n", "import time\n", "from math import sqrt\n", "\n", "from ansys.aedt.core import Maxwell3d\n", "from ansys.aedt.core.generic.constants import SolutionsMaxwell3D\n", "from ansys.aedt.core.generic.file_utils import write_csv\n" ] }, { "cell_type": "markdown", "id": "861da7e0", "metadata": {}, "source": [ "### Define constants\n", "Constants help ensure consistency and avoid repetition throughout the example." ] }, { "cell_type": "code", "execution_count": null, "id": "b7dbec94", "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": "94351428", "metadata": {}, "source": [ "### Create temporary directory\n", "\n", "Create a temporary working directory.\n", "The name of the working folder is stored in ``temp_folder.name``.\n", "\n", "> **Note:** The final cell in the notebook cleans up the temporary folder. If you want to\n", "> retrieve the AEDT project and data, do so before executing the final cell in the notebook." ] }, { "cell_type": "code", "execution_count": null, "id": "be68a7ea", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "fb003131", "metadata": {}, "source": [ "### Launch Maxwell 3D\n", "\n", "Create an instance of the ``Maxwell3d`` class named ``m3d`` by providing\n", "the project and design names, the solver, and the version." ] }, { "cell_type": "code", "execution_count": null, "id": "352abf1c", "metadata": {}, "outputs": [], "source": [ "project_name = os.path.join(temp_folder.name, \"COMPUMAG2.aedt\")\n", "m3d = Maxwell3d(\n", " project=project_name,\n", " design=\"TEAM_7_Asymmetric_Conductor\",\n", " solution_type=SolutionsMaxwell3D.ACMagnetic,\n", " version=AEDT_VERSION,\n", " non_graphical=NG_MODE,\n", " new_desktop=True,\n", ")\n", "m3d.modeler.model_units = \"mm\"" ] }, { "cell_type": "markdown", "id": "03ba9cdb", "metadata": {}, "source": [ "## Model Preparation\n", "\n", "### Define the Maxwell 3D analysis setup\n", "\n", "Add a Maxwell 3D setup with frequency points at 50 Hz, and 200Hz.\n", "Otherwise, the default PyAEDT setup values are used. Second-order shape functions improve\n", "the smoothness of the induced currents in the plate." ] }, { "cell_type": "code", "execution_count": null, "id": "8b25d4b9", "metadata": {}, "outputs": [], "source": [ "\n", "setup = m3d.create_setup(name=\"Setup1\")\n", "setup.props[\"Frequency\"] = \"200Hz\"\n", "setup.props[\"HasSweepSetup\"] = True\n", "setup.add_eddy_current_sweep(\n", " sweep_type=\"SinglePoints\",\n", " start_frequency=50,\n", " units=\"Hz\",\n", " clear=True,\n", ")\n", "setup.props[\"UseHighOrderShapeFunc\"] = True\n", "setup.props[\"PercentError\"] = 0.4" ] }, { "cell_type": "markdown", "id": "e4df3c17", "metadata": {}, "source": [ "### Define coil dimensions\n", "\n", "Define coil dimensions as shown on the TEAM7 drawing of the coil." ] }, { "cell_type": "code", "execution_count": null, "id": "e2f8481b", "metadata": {}, "outputs": [], "source": [ "coil_external = 150 + 25 + 25\n", "coil_internal = 150\n", "coil_r1 = 25\n", "coil_r2 = 50\n", "coil_thk = coil_r2 - coil_r1\n", "coil_height = 100\n", "coil_centre = [294 - 25 - 150 / 2, 25 + 150 / 2, 19 + 30 + 100 / 2]" ] }, { "cell_type": "markdown", "id": "b28adbe7", "metadata": {}, "source": [ "### Define expressions to evaluate solution data\n", "Use expressions to construct the three dimensions needed to describe the midpoints of\n", "the coil." ] }, { "cell_type": "code", "execution_count": null, "id": "8a1a9f1c", "metadata": {}, "outputs": [], "source": [ "dim1 = coil_internal / 2 + (coil_external - coil_internal) / 4\n", "dim2 = coil_internal / 2 - coil_r1\n", "dim3 = dim2 + sqrt(((coil_r1 + (coil_r2 - coil_r1) / 2) ** 2) / 2)" ] }, { "cell_type": "markdown", "id": "5f748272", "metadata": {}, "source": [ "### Draw the coil\n", "Use coordinates to draw a polyline along which to sweep the coil cross sections." ] }, { "cell_type": "code", "execution_count": null, "id": "1ed2e775", "metadata": {}, "outputs": [], "source": [ "P1 = [dim1, -dim2, 0]\n", "P2 = [dim1, dim2, 0]\n", "P3 = [dim3, dim3, 0]\n", "P4 = [dim2, dim1, 0]" ] }, { "cell_type": "markdown", "id": "65451527", "metadata": {}, "source": [ "Create a coordinate system to use as a reference for the coil." ] }, { "cell_type": "code", "execution_count": null, "id": "a63fb9ab", "metadata": {}, "outputs": [], "source": [ "m3d.modeler.create_coordinate_system(origin=coil_centre, mode=\"view\", view=\"XY\", name=\"Coil_CS\")" ] }, { "cell_type": "markdown", "id": "d17643f3", "metadata": {}, "source": [ "Create a polyline. One quarter of the coil is modeled by sweeping a 2D sheet along a polyline." ] }, { "cell_type": "code", "execution_count": null, "id": "17b79ff4", "metadata": {}, "outputs": [], "source": [ "quarter_coil_centroid = m3d.modeler.create_polyline(points=[P1, P2, P3, P4], segment_type=[\"Line\", \"Arc\"], name=\"Coil\")\n", "quarter_coil_centroid.set_crosssection_properties(section=\"Rectangle\", width=coil_thk, height=coil_height)" ] }, { "cell_type": "markdown", "id": "a78b95d4", "metadata": {}, "source": [ "Duplicate and unite the polyline to create the full coil." ] }, { "cell_type": "code", "execution_count": null, "id": "18c1f9c1", "metadata": {}, "outputs": [], "source": [ "m3d.modeler.duplicate_around_axis(\n", " assignment=\"Coil\",\n", " axis=\"Global\",\n", " angle=90,\n", " clones=4,\n", " create_new_objects=True,\n", " is_3d_comp=False,\n", ")\n", "m3d.modeler.unite(\"Coil, Coil_1, Coil_2\")\n", "m3d.modeler.unite(\"Coil, Coil_3\")\n", "m3d.modeler.fit_all()" ] }, { "cell_type": "markdown", "id": "e171b882", "metadata": {}, "source": [ "### Assign material and enable the field solution inside the copper coil\n", "\n", "Assign the material ``Copper`` from the Maxwell internal library to the coil and\n", "allow a solution inside the coil." ] }, { "cell_type": "code", "execution_count": null, "id": "b17bb581", "metadata": {}, "outputs": [], "source": [ "m3d.assign_material(assignment=\"Coil\", material=\"Copper\")\n", "m3d.solve_inside(\"Coil\")" ] }, { "cell_type": "markdown", "id": "19e6e5a6", "metadata": {}, "source": [ "### Create terminal\n", "\n", "Create a terminal for the coil from a cross-section that is split and one half deleted." ] }, { "cell_type": "code", "execution_count": null, "id": "c4e0d880", "metadata": {}, "outputs": [], "source": [ "m3d.modeler.section(assignment=\"Coil\", plane=\"YZ\")\n", "m3d.modeler.separate_bodies(assignment=\"Coil_Section1\")\n", "m3d.modeler.delete(assignment=\"Coil_Section1_Separate1\")" ] }, { "cell_type": "markdown", "id": "47900718", "metadata": {}, "source": [ "### Add variable for coil excitation\n", "\n", "Use a parameter to define the coil current.\n", "The units in this case are Ampere$\\times$Turns, disabling solid forces current density to be uniform across coil\n", "cross section, as per a wound coil." ] }, { "cell_type": "code", "execution_count": null, "id": "144b2dce", "metadata": {}, "outputs": [], "source": [ "Coil_Excitation = 2742\n", "m3d[\"Coil_Excitation\"] = str(Coil_Excitation) + \"A\"\n", "m3d.assign_current(assignment=\"Coil_Section1\", amplitude=\"Coil_Excitation\", solid=False)\n", "m3d.modeler.set_working_coordinate_system(\"Global\")" ] }, { "cell_type": "markdown", "id": "7c447819", "metadata": {}, "source": [ "### Add material\n", "\n", "Add a material named ``team3_aluminium``." ] }, { "cell_type": "code", "execution_count": null, "id": "7a303b73", "metadata": {}, "outputs": [], "source": [ "mat = m3d.materials.add_material(\"team7_aluminium\")\n", "mat.conductivity = 3.526e7" ] }, { "cell_type": "markdown", "id": "c6001de3", "metadata": {}, "source": [ "### Create the aluminium plate with a hole\n", "\n", "Draw the aluminium plate with a hole by subtracting two cuboids." ] }, { "cell_type": "code", "execution_count": null, "id": "521cbf1b", "metadata": {}, "outputs": [], "source": [ "plate = m3d.modeler.create_box(origin=[0, 0, 0], sizes=[294, 294, 19], name=\"Plate\", material=\"team7_aluminium\")\n", "m3d.modeler.fit_all()\n", "hole = m3d.modeler.create_box(origin=[18, 18, 0], sizes=[108, 108, 19], name=\"Hole\")\n", "m3d.modeler.subtract(blank_list=\"Plate\", tool_list=[\"Hole\"], keep_originals=False)" ] }, { "cell_type": "markdown", "id": "c575059f", "metadata": {}, "source": [ "### Draw background region\n", "\n", "The background air region defines the full volumetric solution domain." ] }, { "cell_type": "code", "execution_count": null, "id": "36c1404c", "metadata": {}, "outputs": [], "source": [ "m3d.modeler.create_air_region(x_pos=100, y_pos=100, z_pos=100, x_neg=100, y_neg=100, z_neg=100)" ] }, { "cell_type": "markdown", "id": "f9de223d", "metadata": {}, "source": [ "### Adjust eddy and displacement effects for plate and coil\n", "\n", "Disable displacement effects for the plate and coil and disable eddy effects in the stranded coil.\n", "Eddy effects remain enabled in the Plate." ] }, { "cell_type": "code", "execution_count": null, "id": "286c055d", "metadata": {}, "outputs": [], "source": [ "m3d.eddy_effects_on(\n", " assignment=[\"Coil\"],\n", " enable_eddy_effects=False,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "fa6be00b", "metadata": {}, "outputs": [], "source": [ "m3d.eddy_effects_on(\n", " assignment=[\"Plate\"],\n", " enable_displacement_current=False,\n", ")" ] }, { "cell_type": "markdown", "id": "4a114846", "metadata": {}, "source": [ "### Create expression for $B_z$ in Gauss\n", "\n", "Create an expression for the $z$-component of $\\bf{B}$ in Gauss using PyAEDT advanced fields calculator." ] }, { "cell_type": "code", "execution_count": null, "id": "419b2a3a", "metadata": {}, "outputs": [], "source": [ "bz = {\n", " \"name\": \"Bz\",\n", " \"description\": \"Z component of B in Gauss\",\n", " \"design_type\": [\"Maxwell 3D\"],\n", " \"fields_type\": [\"Fields\"],\n", " \"primary_sweep\": \"Distance\",\n", " \"assignment\": \"\",\n", " \"assignment_type\": [\"Line\"],\n", " \"operations\": [\n", " \"NameOfExpression('')\",\n", " \"Operation('ScalarZ')\",\n", " \"Scalar_Function(FuncValue='Phase')\",\n", " \"Operation('AtPhase')\",\n", " \"Scalar_Constant(10000)\",\n", " \"Operation('*')\",\n", " \"Operation('Smooth')\",\n", " ],\n", " \"report\": [\"Field_3D\"],\n", "}\n", "m3d.post.fields_calculator.add_expression(bz, None)" ] }, { "cell_type": "markdown", "id": "5a7c0c9b", "metadata": {}, "source": [ "### Draw two lines along which to plot $B_z$\n", "\n", "Draw two lines along which to plot Bz. The following code also adds a small cylinder\n", "to refine the mesh locally around each line." ] }, { "cell_type": "code", "execution_count": null, "id": "2d8f5b67", "metadata": {}, "outputs": [], "source": [ "lines = [\"Line_A1_B1\", \"Line_A2_B2\"]\n", "mesh_diameter = \"2mm\"\n", "\n", "line_points_1 = [[\"0mm\", \"72mm\", \"34mm\"], [\"288mm\", \"72mm\", \"34mm\"]]\n", "polyline = m3d.modeler.create_polyline(points=line_points_1, name=lines[0])\n", "l1_mesh = m3d.modeler.create_polyline(points=line_points_1, name=lines[0] + \"mesh\")\n", "l1_mesh.set_crosssection_properties(section=\"Circle\", width=mesh_diameter)\n", "\n", "line_points_2 = [[\"0mm\", \"144mm\", \"34mm\"], [\"288mm\", \"144mm\", \"34mm\"]]\n", "polyline2 = m3d.modeler.create_polyline(points=line_points_2, name=lines[1])\n", "l2_mesh = m3d.modeler.create_polyline(points=line_points_2, name=lines[1] + \"mesh\")\n", "l2_mesh.set_crosssection_properties(section=\"Circle\", width=mesh_diameter)" ] }, { "cell_type": "markdown", "id": "e76a90b6", "metadata": {}, "source": [ "Published measurement results are included with this script via the following list.\n", "Test results are used to create text files for import into a rectangular plot\n", "and to overlay simulation results." ] }, { "cell_type": "code", "execution_count": null, "id": "bb859347", "metadata": {}, "outputs": [], "source": [ "project_dir = temp_folder.name\n", "test_data_header = [\"Distance [mm]\", \"Bz [Tesla]\"]\n", "\n", "test_line = [\n", " 0,\n", " 18,\n", " 36,\n", " 54,\n", " 72,\n", " 90,\n", " 108,\n", " 126,\n", " 144,\n", " 162,\n", " 180,\n", " 198,\n", " 216,\n", " 234,\n", " 252,\n", " 270,\n", " 288,\n", "]\n", "test_data = {\n", " \"A1_B1\": {\n", " 50: {\n", " 0: [\n", " 4.90,\n", " -17.88,\n", " -22.13,\n", " -20.19,\n", " -15.67,\n", " 0.36,\n", " 43.64,\n", " 78.11,\n", " 71.55,\n", " 60.44,\n", " 53.91,\n", " 52.62,\n", " 53.81,\n", " 56.91,\n", " 59.24,\n", " 52.78,\n", " 27.61,\n", " ],\n", " 90: [\n", " -1.16,\n", " 2.84,\n", " 4.15,\n", " 4.00,\n", " 3.07,\n", " 2.31,\n", " 1.89,\n", " 4.97,\n", " 12.61,\n", " 14.15,\n", " 13.04,\n", " 12.40,\n", " 12.05,\n", " 12.27,\n", " 12.66,\n", " 9.96,\n", " 2.36,\n", " ],\n", " },\n", " 200: {\n", " 0: [\n", " -3.63,\n", " -18.46,\n", " -23.62,\n", " -21.59,\n", " -16.09,\n", " 0.23,\n", " 44.35,\n", " 75.53,\n", " 63.42,\n", " 53.20,\n", " 48.66,\n", " 47.31,\n", " 48.31,\n", " 51.26,\n", " 53.61,\n", " 46.11,\n", " 24.96,\n", " ],\n", " 90: [\n", " -1.38,\n", " 1.20,\n", " 2.15,\n", " 1.63,\n", " 1.10,\n", " 0.27,\n", " -2.28,\n", " -1.40,\n", " 4.17,\n", " 3.94,\n", " 4.86,\n", " 4.09,\n", " 3.69,\n", " 4.60,\n", " 3.48,\n", " 4.10,\n", " 0.98,\n", " ],\n", " },\n", " },\n", " \"A2_B2\": {\n", " 50: {\n", " 0: [\n", " -1.83,\n", " -8.50,\n", " -13.60,\n", " -15.21,\n", " -14.48,\n", " -5.62,\n", " 28.77,\n", " 60.34,\n", " 61.84,\n", " 56.64,\n", " 53.40,\n", " 52.36,\n", " 53.93,\n", " 56.82,\n", " 59.48,\n", " 52.08,\n", " 26.56,\n", " ],\n", " 90: [\n", " -1.63,\n", " -0.60,\n", " -0.43,\n", " 0.11,\n", " 1.26,\n", " 3.40,\n", " 6.53,\n", " 10.25,\n", " 11.83,\n", " 11.83,\n", " 11.01,\n", " 10.58,\n", " 10.80,\n", " 10.54,\n", " 10.62,\n", " 9.03,\n", " 1.79,\n", " ],\n", " },\n", " 200: {\n", " 0: [\n", " -0.86,\n", " -7.00,\n", " -11.58,\n", " -13.36,\n", " -13.77,\n", " -6.74,\n", " 24.63,\n", " 53.19,\n", " 54.89,\n", " 50.72,\n", " 48.03,\n", " 47.13,\n", " 48.25,\n", " 51.35,\n", " 53.35,\n", " 45.37,\n", " 24.01,\n", " ],\n", " 90: [\n", " -1.35,\n", " -0.71,\n", " -0.81,\n", " -0.67,\n", " 0.15,\n", " 1.39,\n", " 2.67,\n", " 3.00,\n", " 4.01,\n", " 3.80,\n", " 4.00,\n", " 3.02,\n", " 2.20,\n", " 2.78,\n", " 1.58,\n", " 1.37,\n", " 0.93,\n", " ],\n", " },\n", " },\n", "}\n" ] }, { "cell_type": "code", "execution_count": null, "id": "298f1d57", "metadata": {}, "outputs": [], "source": [ "# ### Write dataset values to a CSV file\n", "test_line_with_header = [test_data_header[0]] + test_line" ] }, { "cell_type": "code", "execution_count": null, "id": "26c8f6ee", "metadata": {}, "outputs": [], "source": [ "for line_name, freq_dict in test_data.items():\n", " for freq_value, phase_dict in freq_dict.items():\n", " for freq_angle, field_values in phase_dict.items():\n", "\n", " values_with_header = [test_data_header[1]] + field_values\n", " ziplist = zip(test_line_with_header, values_with_header)\n", "\n", " file_label = \"Bz \" + str(line_name) + \" \" + str(freq_value) + \" \" + str(freq_angle)\n", " file_path = os.path.join(project_dir, str(file_label) + \".csv\")\n", " write_csv(output_file=file_path, list_data=ziplist)" ] }, { "cell_type": "markdown", "id": "81081ed8", "metadata": {}, "source": [ "### Create rectangular plots and import test data into report\n", "\n", "Create rectangular plots, using text file encoding to control their formatting.\n", "Import test data into the correct plot and overlay with the simulation results." ] }, { "cell_type": "code", "execution_count": null, "id": "42cdacb2", "metadata": {}, "outputs": [], "source": [ "for line_name, freq_dict in test_data.items():\n", " for freq_value, phase_dict in freq_dict.items():\n", " plot_name = \"Bz Along line \" + line_name + \" at \" + str(freq_value) + \"Hz\"\n", " variations = {\n", " \"Distance\": [\"All\"],\n", " \"Freq\": [str(freq_value) + \"Hz\"],\n", " \"Phase\": [str(phase_deg) + \"deg\" for phase_deg in sorted(phase_dict.keys())],\n", " \"Coil_Excitation\": [\"All\"],\n", " }\n", "\n", " report = m3d.post.create_report(\n", " plot_name=plot_name,\n", " report_category=\"Fields\",\n", " context=\"Line_\" + str(line_name),\n", " primary_sweep_variable=\"Distance\",\n", " variations=variations,\n", " expressions=\"Bz\",\n", " )\n", " for freq_angle in sorted(phase_dict.keys()):\n", " file_label = \"Bz \" + str(line_name) + \" \" + str(freq_value) + \" \" + str(freq_angle)\n", " file_path = os.path.join(project_dir, str(file_label) + \".csv\")\n", " report.import_traces(input_file=file_path, plot_name=plot_name)" ] }, { "cell_type": "markdown", "id": "68403671", "metadata": {}, "source": [ "Analyze project." ] }, { "cell_type": "code", "execution_count": null, "id": "a47d59f7", "metadata": {}, "outputs": [], "source": [ "m3d.analyze(cores=NUM_CORES)" ] }, { "cell_type": "markdown", "id": "59e21031", "metadata": {}, "source": [ "### Create plots of induced current and flux density on surface of plate\n", "\n", "Create two plots of the induced current (``Mag_J``) and the flux density (``Mag_B``) on the\n", "surface of the plate." ] }, { "cell_type": "code", "execution_count": null, "id": "7a3bafc9", "metadata": {}, "outputs": [], "source": [ "surf_list = m3d.modeler.get_object_faces(assignment=\"Plate\")\n", "intrinsic_dict = {\"Freq\": \"200Hz\", \"Phase\": \"0deg\"}\n", "m3d.post.create_fieldplot_surface(\n", " assignment=surf_list,\n", " quantity=\"Mag_J\",\n", " intrinsics=intrinsic_dict,\n", " plot_name=\"Mag_J\",\n", ")\n", "m3d.post.create_fieldplot_surface(\n", " assignment=surf_list,\n", " quantity=\"Mag_B\",\n", " intrinsics=intrinsic_dict,\n", " plot_name=\"Mag_B\",\n", ")\n", "m3d.post.create_fieldplot_surface(assignment=surf_list, quantity=\"Mesh\", intrinsics=intrinsic_dict, plot_name=\"Mesh\")" ] }, { "cell_type": "markdown", "id": "9907679f", "metadata": {}, "source": [ "## Finish\n", "\n", "### Save the project" ] }, { "cell_type": "code", "execution_count": null, "id": "287d138a", "metadata": {}, "outputs": [], "source": [ "m3d.save_project()\n", "m3d.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": "fdc62ecc", "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": "46bc7f7a", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }