{ "cells": [ { "cell_type": "markdown", "id": "a344b504", "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": "894dc370", "metadata": {}, "source": [ "## Perform imports and define constants\n", "\n", "Perform required imports." ] }, { "cell_type": "code", "execution_count": null, "id": "d2458eab", "metadata": {}, "outputs": [], "source": [ "import os\n", "import tempfile\n", "import time" ] }, { "cell_type": "code", "execution_count": null, "id": "398fc727", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from ansys.aedt.core import Maxwell3d\n", "from ansys.aedt.core.generic.general_methods import write_csv" ] }, { "cell_type": "markdown", "id": "2e82003d", "metadata": {}, "source": [ "Define constants." ] }, { "cell_type": "code", "execution_count": null, "id": "5f360466", "metadata": {}, "outputs": [], "source": [ "AEDT_VERSION = \"2024.2\"\n", "NUM_CORES = 4\n", "NG_MODE = False # Open AEDT UI when it is launched." ] }, { "cell_type": "markdown", "id": "93afc6ea", "metadata": {}, "source": [ "## Create temporary directory\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": "b670bb41", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "20de6f95", "metadata": {}, "source": [ "## Launch AEDT and 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": "ebe89fc3", "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=\"EddyCurrent\",\n", " version=AEDT_VERSION,\n", " non_graphical=NG_MODE,\n", " new_desktop=True,\n", ")\n", "m3d.modeler.model_units = \"mm\"" ] }, { "cell_type": "markdown", "id": "032f054d", "metadata": {}, "source": [ "## Add Maxwell 3D setup\n", "\n", "Add a Maxwell 3D setup with frequency points at DC, 50 Hz, and 200Hz.\n", "Otherwise, the default PyAEDT setup values are used. To approximate a DC field in the\n", "eddy current solver, use a low frequency value. Second-order shape functions improve\n", "the smoothness of the induced currents in the plate." ] }, { "cell_type": "code", "execution_count": null, "id": "9b04a5a2", "metadata": {}, "outputs": [], "source": [ "dc_freq = 0.1\n", "stop_freq = 50\n", "\n", "setup = m3d.create_setup(name=\"Setup1\")\n", "setup.props[\"Frequency\"] = \"200Hz\"\n", "setup.props[\"HasSweepSetup\"] = True\n", "setup.add_eddy_current_sweep(\n", " range_type=\"LinearStep\",\n", " start=dc_freq,\n", " end=stop_freq,\n", " count=stop_freq - dc_freq,\n", " clear=True,\n", ")\n", "setup.props[\"UseHighOrderShapeFunc\"] = True\n", "setup.props[\"PercentError\"] = 0.4" ] }, { "cell_type": "markdown", "id": "451b221c", "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": "78a98455", "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": "9fac7589", "metadata": {}, "source": [ "Use expressions to construct the three dimensions needed to describe the midpoints of\n", "the coil." ] }, { "cell_type": "code", "execution_count": null, "id": "4c65126f", "metadata": {}, "outputs": [], "source": [ "dim1 = coil_internal / 2 + (coil_external - coil_internal) / 4\n", "dim2 = coil_internal / 2 - coil_r1\n", "dim3 = dim2 + np.sqrt(((coil_r1 + (coil_r2 - coil_r1) / 2) ** 2) / 2)" ] }, { "cell_type": "markdown", "id": "885fb8ab", "metadata": {}, "source": [ "Use coordinates to draw a polyline along which to sweep the coil cross sections." ] }, { "cell_type": "code", "execution_count": null, "id": "73839104", "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": "33d253e6", "metadata": {}, "source": [ "## Create coordinate system for positioning coil" ] }, { "cell_type": "code", "execution_count": null, "id": "f66f75bb", "metadata": {}, "outputs": [], "source": [ "m3d.modeler.create_coordinate_system(\n", " origin=coil_centre, mode=\"view\", view=\"XY\", name=\"Coil_CS\"\n", ")" ] }, { "cell_type": "markdown", "id": "a07d2882", "metadata": {}, "source": [ "## Create polyline\n", "\n", "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": "d14717ce", "metadata": {}, "outputs": [], "source": [ "test = m3d.modeler.create_polyline(\n", " points=[P1, P2, P3, P4], segment_type=[\"Line\", \"Arc\"], name=\"Coil\"\n", ")\n", "test.set_crosssection_properties(type=\"Rectangle\", width=coil_thk, height=coil_height)" ] }, { "cell_type": "markdown", "id": "aed6bf83", "metadata": {}, "source": [ "## Duplicate and unite polyline to create full coil" ] }, { "cell_type": "code", "execution_count": null, "id": "8800ce5c", "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": "fc81d4e6", "metadata": {}, "source": [ "## Assign material and if solution is allowed inside coil\n", "\n", "Assign the material ``Cooper`` from the Maxwell internal library to the coil and\n", "allow a solution inside the coil." ] }, { "cell_type": "code", "execution_count": null, "id": "9b83ed9d", "metadata": {}, "outputs": [], "source": [ "m3d.assign_material(assignment=\"Coil\", material=\"Copper\")\n", "m3d.solve_inside(\"Coil\")" ] }, { "cell_type": "markdown", "id": "78471525", "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": "aa619d57", "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": "e5707411", "metadata": {}, "source": [ "## Add variable for coil excitation\n", "\n", "Add a design variable for coil excitation. The NB units here are AmpereTurns." ] }, { "cell_type": "code", "execution_count": null, "id": "6f5d3e43", "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": "505e926c", "metadata": {}, "source": [ "## Add material\n", "\n", "Add a material named ``team3_aluminium``." ] }, { "cell_type": "code", "execution_count": null, "id": "664fcabd", "metadata": {}, "outputs": [], "source": [ "mat = m3d.materials.add_material(\"team7_aluminium\")\n", "mat.conductivity = 3.526e7" ] }, { "cell_type": "markdown", "id": "79db0816", "metadata": {}, "source": [ "## Model aluminium plate with a hole\n", "\n", "Model the aluminium plate with a hole by subtracting two rectangular cuboids." ] }, { "cell_type": "code", "execution_count": null, "id": "5f11bb57", "metadata": {}, "outputs": [], "source": [ "plate = m3d.modeler.create_box(\n", " origin=[0, 0, 0], sizes=[294, 294, 19], name=\"Plate\", material=\"team7_aluminium\"\n", ")\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": "b5aba3cf", "metadata": {}, "source": [ "## Draw background region\n", "\n", "Draw a background region that uses the default properties for an air region." ] }, { "cell_type": "code", "execution_count": null, "id": "9f0c3cb4", "metadata": {}, "outputs": [], "source": [ "m3d.modeler.create_air_region(\n", " x_pos=100, y_pos=100, z_pos=100, x_neg=100, y_neg=100, z_neg=100\n", ")" ] }, { "cell_type": "markdown", "id": "847b9918", "metadata": {}, "source": [ "## Adjust eddy effects for plate and coil\n", "\n", "Adjust the eddy effects for the plate and coil by turning off displacement currents\n", "for all parts. The setting for the eddy effect is ignored for the stranded conductor type\n", "used in the coil." ] }, { "cell_type": "code", "execution_count": null, "id": "10c6faac", "metadata": {}, "outputs": [], "source": [ "m3d.eddy_effects_on(assignment=\"Plate\")\n", "m3d.eddy_effects_on(\n", " assignment=[\"Coil\", \"Region\", \"Line_A1_B1mesh\", \"Line_A2_B2mesh\"],\n", " enable_eddy_effects=False,\n", " enable_displacement_current=False,\n", ")" ] }, { "cell_type": "markdown", "id": "9aa8d12a", "metadata": {}, "source": [ "## Create expression for Z component of B in Gauss\n", "\n", "Create an expression for the Z component of B in Gauss using PyAEDT advanced fields calculator." ] }, { "cell_type": "code", "execution_count": null, "id": "1eb82a63", "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": "484074cb", "metadata": {}, "source": [ "## Draw two lines along which to plot Bz\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": "b39dd558", "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(type=\"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(type=\"Circle\", width=mesh_diameter)" ] }, { "cell_type": "markdown", "id": "eeb2b96f", "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": "d2b8d656", "metadata": {}, "outputs": [], "source": [ "project_dir = temp_folder.name\n", "dataset = [\n", " \"Bz A1_B1 000 0\",\n", " \"Bz A1_B1 050 0\",\n", " \"Bz A1_B1 050 90\",\n", " \"Bz A1_B1 200 0\",\n", " \"Bz A1_B1 200 90\",\n", " \"Bz A2_B2 050 0\",\n", " \"Bz A2_B2 050 90\",\n", " \"Bz A2_B2 200 0\",\n", " \"Bz A2_B2 200 90\",\n", "]\n", "header = [\"Distance [mm]\", \"Bz [Tesla]\"]\n", "\n", "line_length = [\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", "data = [\n", " [\n", " -6.667,\n", " -7.764,\n", " -8.707,\n", " -8.812,\n", " -5.870,\n", " 8.713,\n", " 50.40,\n", " 88.47,\n", " 100.9,\n", " 104.0,\n", " 104.8,\n", " 104.9,\n", " 104.6,\n", " 103.1,\n", " 97.32,\n", " 75.19,\n", " 29.04,\n", " ],\n", " [\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", " [\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", " -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", " [\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", " -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", " [\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", " -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", " [\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", "]" ] }, { "cell_type": "markdown", "id": "c522bcf9", "metadata": {}, "source": [ "## Write dataset values to a CSV file\n", "\n", "Dataset details are used to encode test parameters in the text files.\n", "For example, ``Bz A1_B1 050 0`` is the Z component of flux density ``B``\n", "along line ``A1_B1`` at 50 Hz and 0 deg." ] }, { "cell_type": "code", "execution_count": null, "id": "9606bec7", "metadata": {}, "outputs": [], "source": [ "line_length.insert(0, header[0])\n", "for i in range(len(dataset)):\n", " data[i].insert(0, header[1])\n", " ziplist = zip(line_length, data[i])\n", " file_path = os.path.join(temp_folder.name, str(dataset[i]) + \".csv\")\n", " write_csv(output_file=file_path, list_data=ziplist)" ] }, { "cell_type": "markdown", "id": "6b2170e5", "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.\n", "Variations for a DC plot must have a different frequency and phase than the other plots." ] }, { "cell_type": "code", "execution_count": null, "id": "72a5a6c1", "metadata": {}, "outputs": [], "source": [ "for item in range(len(dataset)):\n", " if item % 2 == 0:\n", " t = dataset[item]\n", " plot_name = t[0:3] + \"Along the Line\" + t[2:9] + \", \" + t[9:12] + \"Hz\"\n", " if t[9:12] == \"000\":\n", " variations = {\n", " \"Distance\": [\"All\"],\n", " \"Freq\": [str(dc_freq) + \"Hz\"],\n", " \"Phase\": [\"0deg\"],\n", " \"Coil_Excitation\": [\"All\"],\n", " }\n", " else:\n", " variations = {\n", " \"Distance\": [\"All\"],\n", " \"Freq\": [t[9:12] + \"Hz\"],\n", " \"Phase\": [\"0deg\", \"90deg\"],\n", " \"Coil_Excitation\": [\"All\"],\n", " }\n", " report = m3d.post.create_report(\n", " plot_name=plot_name,\n", " report_category=\"Fields\",\n", " context=\"Line_\" + t[3:8],\n", " primary_sweep_variable=\"Distance\",\n", " variations=variations,\n", " expressions=t[0:2],\n", " )\n", " file_path = os.path.join(temp_folder.name, str(dataset[i]) + \".csv\")\n", " report.import_traces(input_file=file_path, plot_name=plot_name)" ] }, { "cell_type": "markdown", "id": "e1d7522d", "metadata": {}, "source": [ "Analyze project." ] }, { "cell_type": "code", "execution_count": null, "id": "7a4aa4f2", "metadata": {}, "outputs": [], "source": [ "m3d.analyze(cores=NUM_CORES)" ] }, { "cell_type": "markdown", "id": "995a21ae", "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": "e6ab44e5", "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(\n", " assignment=surf_list, quantity=\"Mesh\", intrinsics=intrinsic_dict, plot_name=\"Mesh\"\n", ")" ] }, { "cell_type": "markdown", "id": "e31eaca9", "metadata": {}, "source": [ "## Release AEDT" ] }, { "cell_type": "code", "execution_count": null, "id": "372b17a3", "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": "df341074", "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": "eea417b2", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }