Download this example

Download this example as a Jupyter Notebook or as a Python script.


Asymmetric conductor analysis#

This example uses PyAEDT to set up the TEAM 7 problem for an asymmetric conductor with a hole and solve it using the Maxwell 3D eddy current solver. For more information on this problem, see this paper.

Keywords: Maxwell 3D, Asymmetric conductor.

Prerequisites#

Perform imports#

[1]:
import os
import tempfile
import time
from math import sqrt

from ansys.aedt.core import Maxwell3d
from ansys.aedt.core.generic.constants import SolutionsMaxwell3D
from ansys.aedt.core.generic.file_utils import write_csv

Define constants#

Constants help ensure consistency and avoid repetition throughout the example.

[2]:
AEDT_VERSION = "2025.2"
NUM_CORES = 4
NG_MODE = False  # Open AEDT UI when it is launched.

Create temporary directory#

Create a temporary working directory. The name of the working folder is stored in temp_folder.name.

Note: The final cell in the notebook cleans up the temporary folder. If you want to retrieve the AEDT project and data, do so before executing the final cell in the notebook.

[3]:
temp_folder = tempfile.TemporaryDirectory(suffix=".ansys")

Launch Maxwell 3D#

Create an instance of the Maxwell3d class named m3d by providing the project and design names, the solver, and the version.

[4]:
project_name = os.path.join(temp_folder.name, "COMPUMAG2.aedt")
m3d = Maxwell3d(
    project=project_name,
    design="TEAM_7_Asymmetric_Conductor",
    solution_type=SolutionsMaxwell3D.ACMagnetic,
    version=AEDT_VERSION,
    non_graphical=NG_MODE,
    new_desktop=True,
)
m3d.modeler.model_units = "mm"
PyAEDT INFO: Python version 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)].
PyAEDT INFO: PyAEDT version 0.26.dev0.
PyAEDT INFO: Initializing new Desktop session.
PyAEDT INFO: AEDT version 2025.2.
PyAEDT INFO: New AEDT session is starting on gRPC port 51298.
PyAEDT INFO: Starting new AEDT gRPC session on port 51298.
PyAEDT INFO: Launching AEDT server with gRPC transport mode: wnua
PyAEDT INFO: Electronics Desktop started on gRPC port 51298 after 11.1 seconds.
PyAEDT INFO: AEDT installation Path C:\Program Files\ANSYS Inc\v252\AnsysEM
PyAEDT INFO: Connected to AEDT gRPC session on port 51298.
PyAEDT WARNING: Service Pack is not detected. PyAEDT is currently connecting in Insecure Mode.
PyAEDT WARNING: Please download and install latest Service Pack to use connect to AEDT in Secure Mode.
PyAEDT INFO: Project COMPUMAG2 has been created.
PyAEDT INFO: Added design 'TEAM_7_Asymmetric_Conductor' of type Maxwell 3D.
PyAEDT INFO: AEDT objects correctly read
PyAEDT INFO: Modeler class has been initialized! Elapsed time: 0m 0sec

Model Preparation#

Define the Maxwell 3D analysis setup#

Add a Maxwell 3D setup with frequency points at 50 Hz, and 200Hz. Otherwise, the default PyAEDT setup values are used. Second-order shape functions improve the smoothness of the induced currents in the plate.

[5]:

setup = m3d.create_setup(name="Setup1") setup.props["Frequency"] = "200Hz" setup.props["HasSweepSetup"] = True setup.add_eddy_current_sweep( sweep_type="SinglePoints", start_frequency=50, units="Hz", clear=True, ) setup.props["UseHighOrderShapeFunc"] = True setup.props["PercentError"] = 0.4
PyAEDT INFO: Parsing C:\Users\ansys\AppData\Local\Temp\tmp3egap50h.ansys\COMPUMAG2.aedt.
PyAEDT INFO: File C:\Users\ansys\AppData\Local\Temp\tmp3egap50h.ansys\COMPUMAG2.aedt correctly loaded. Elapsed time: 0m 0sec
PyAEDT INFO: aedt file load time 0.0161435604095459

Define coil dimensions#

Define coil dimensions as shown on the TEAM7 drawing of the coil.

[6]:
coil_external = 150 + 25 + 25
coil_internal = 150
coil_r1 = 25
coil_r2 = 50
coil_thk = coil_r2 - coil_r1
coil_height = 100
coil_centre = [294 - 25 - 150 / 2, 25 + 150 / 2, 19 + 30 + 100 / 2]

Define expressions to evaluate solution data#

Use expressions to construct the three dimensions needed to describe the midpoints of the coil.

[7]:
dim1 = coil_internal / 2 + (coil_external - coil_internal) / 4
dim2 = coil_internal / 2 - coil_r1
dim3 = dim2 + sqrt(((coil_r1 + (coil_r2 - coil_r1) / 2) ** 2) / 2)

Draw the coil#

Use coordinates to draw a polyline along which to sweep the coil cross sections.

[8]:
P1 = [dim1, -dim2, 0]
P2 = [dim1, dim2, 0]
P3 = [dim3, dim3, 0]
P4 = [dim2, dim1, 0]

Create a coordinate system to use as a reference for the coil.

[9]:
m3d.modeler.create_coordinate_system(origin=coil_centre, mode="view", view="XY", name="Coil_CS")
[9]:
Coil_CS

Create a polyline. One quarter of the coil is modeled by sweeping a 2D sheet along a polyline.

[10]:
quarter_coil_centroid = m3d.modeler.create_polyline(points=[P1, P2, P3, P4], segment_type=["Line", "Arc"], name="Coil")
quarter_coil_centroid.set_crosssection_properties(section="Rectangle", width=coil_thk, height=coil_height)
PyAEDT INFO: Materials class has been initialized! Elapsed time: 0m 0sec
[10]:
True

Duplicate and unite the polyline to create the full coil.

[11]:
m3d.modeler.duplicate_around_axis(
    assignment="Coil",
    axis="Global",
    angle=90,
    clones=4,
    create_new_objects=True,
    is_3d_comp=False,
)
m3d.modeler.unite("Coil, Coil_1, Coil_2")
m3d.modeler.unite("Coil, Coil_3")
m3d.modeler.fit_all()
PyAEDT INFO: Parsing design objects. This operation can take time
PyAEDT INFO: Refreshing bodies from Object Info
PyAEDT INFO: Bodies Info Refreshed Elapsed time: 0m 0sec
PyAEDT INFO: 3D Modeler objects parsed. Elapsed time: 0m 0sec
PyAEDT INFO: Union of 20 objects has been executed.
PyAEDT INFO: Parsing design objects. This operation can take time
PyAEDT INFO: Refreshing bodies from Object Info
PyAEDT INFO: Bodies Info Refreshed Elapsed time: 0m 0sec
PyAEDT INFO: 3D Modeler objects parsed. Elapsed time: 0m 0sec
PyAEDT INFO: Union of 12 objects has been executed.

Assign material and enable the field solution inside the copper coil#

Assign the material Copper from the Maxwell internal library to the coil and allow a solution inside the coil.

[12]:
m3d.assign_material(assignment="Coil", material="Copper")
m3d.solve_inside("Coil")
[12]:
True

Create terminal#

Create a terminal for the coil from a cross-section that is split and one half deleted.

[13]:
m3d.modeler.section(assignment="Coil", plane="YZ")
m3d.modeler.separate_bodies(assignment="Coil_Section1")
m3d.modeler.delete(assignment="Coil_Section1_Separate1")
PyAEDT INFO: Parsing design objects. This operation can take time
PyAEDT INFO: Refreshing bodies from Object Info
PyAEDT INFO: Bodies Info Refreshed Elapsed time: 0m 0sec
PyAEDT INFO: 3D Modeler objects parsed. Elapsed time: 0m 0sec
PyAEDT INFO: Deleted 1 Objects: Coil_Section1_Separate1.
[13]:
True

Add variable for coil excitation#

Use a parameter to define the coil current. The units in this case are Ampere\(\times\)Turns, disabling solid forces current density to be uniform across coil cross section, as per a wound coil.

[14]:
Coil_Excitation = 2742
m3d["Coil_Excitation"] = str(Coil_Excitation) + "A"
m3d.assign_current(assignment="Coil_Section1", amplitude="Coil_Excitation", solid=False)
m3d.modeler.set_working_coordinate_system("Global")
PyAEDT INFO: Boundary Current Current_LRMINZ has been created.
[14]:
True

Add material#

Add a material named team3_aluminium.

[15]:
mat = m3d.materials.add_material("team7_aluminium")
mat.conductivity = 3.526e7
PyAEDT INFO: Adding new material to the Project Library: team7_aluminium
PyAEDT INFO: Material has been added in Desktop.

Create the aluminium plate with a hole#

Draw the aluminium plate with a hole by subtracting two cuboids.

[16]:
plate = m3d.modeler.create_box(origin=[0, 0, 0], sizes=[294, 294, 19], name="Plate", material="team7_aluminium")
m3d.modeler.fit_all()
hole = m3d.modeler.create_box(origin=[18, 18, 0], sizes=[108, 108, 19], name="Hole")
m3d.modeler.subtract(blank_list="Plate", tool_list=["Hole"], keep_originals=False)
PyAEDT INFO: Parsing design objects. This operation can take time
PyAEDT INFO: Refreshing bodies from Object Info
PyAEDT INFO: Bodies Info Refreshed Elapsed time: 0m 0sec
PyAEDT INFO: 3D Modeler objects parsed. Elapsed time: 0m 0sec
[16]:
True

Draw background region#

The background air region defines the full volumetric solution domain.

[17]:
m3d.modeler.create_air_region(x_pos=100, y_pos=100, z_pos=100, x_neg=100, y_neg=100, z_neg=100)
[17]:
Region

Adjust eddy and displacement effects for plate and coil#

Disable displacement effects for the plate and coil and disable eddy effects in the stranded coil. Eddy effects remain enabled in the Plate.

[18]:
m3d.eddy_effects_on(
    assignment=["Coil"],
    enable_eddy_effects=False,
)
[18]:
True
[19]:
m3d.eddy_effects_on(
    assignment=["Plate"],
    enable_displacement_current=False,
)
[19]:
True

Create expression for \(B_z\) in Gauss#

Create an expression for the \(z\)-component of \(\bf{B}\) in Gauss using PyAEDT advanced fields calculator.

[20]:
bz = {
    "name": "Bz",
    "description": "Z component of B in Gauss",
    "design_type": ["Maxwell 3D"],
    "fields_type": ["Fields"],
    "primary_sweep": "Distance",
    "assignment": "",
    "assignment_type": ["Line"],
    "operations": [
        "NameOfExpression('<Bx,By,Bz>')",
        "Operation('ScalarZ')",
        "Scalar_Function(FuncValue='Phase')",
        "Operation('AtPhase')",
        "Scalar_Constant(10000)",
        "Operation('*')",
        "Operation('Smooth')",
    ],
    "report": ["Field_3D"],
}
m3d.post.fields_calculator.add_expression(bz, None)
PyAEDT INFO: PostProcessor class has been initialized! Elapsed time: 0m 0sec
PyAEDT INFO: PostProcessor class has been initialized! Elapsed time: 0m 0sec
PyAEDT INFO: Post class has been initialized! Elapsed time: 0m 0sec
[20]:
'Bz'

Draw two lines along which to plot \(B_z\)#

Draw two lines along which to plot Bz. The following code also adds a small cylinder to refine the mesh locally around each line.

[21]:
lines = ["Line_A1_B1", "Line_A2_B2"]
mesh_diameter = "2mm"

line_points_1 = [["0mm", "72mm", "34mm"], ["288mm", "72mm", "34mm"]]
polyline = m3d.modeler.create_polyline(points=line_points_1, name=lines[0])
l1_mesh = m3d.modeler.create_polyline(points=line_points_1, name=lines[0] + "mesh")
l1_mesh.set_crosssection_properties(section="Circle", width=mesh_diameter)

line_points_2 = [["0mm", "144mm", "34mm"], ["288mm", "144mm", "34mm"]]
polyline2 = m3d.modeler.create_polyline(points=line_points_2, name=lines[1])
l2_mesh = m3d.modeler.create_polyline(points=line_points_2, name=lines[1] + "mesh")
l2_mesh.set_crosssection_properties(section="Circle", width=mesh_diameter)
[21]:
True

Published measurement results are included with this script via the following list. Test results are used to create text files for import into a rectangular plot and to overlay simulation results.

[22]:
project_dir = temp_folder.name
test_data_header = ["Distance [mm]", "Bz [Tesla]"]

test_line = [
    0,
    18,
    36,
    54,
    72,
    90,
    108,
    126,
    144,
    162,
    180,
    198,
    216,
    234,
    252,
    270,
    288,
]
test_data = {
    "A1_B1": {
        50: {
            0: [
                4.90,
                -17.88,
                -22.13,
                -20.19,
                -15.67,
                0.36,
                43.64,
                78.11,
                71.55,
                60.44,
                53.91,
                52.62,
                53.81,
                56.91,
                59.24,
                52.78,
                27.61,
            ],
            90: [
                -1.16,
                2.84,
                4.15,
                4.00,
                3.07,
                2.31,
                1.89,
                4.97,
                12.61,
                14.15,
                13.04,
                12.40,
                12.05,
                12.27,
                12.66,
                9.96,
                2.36,
            ],
        },
        200: {
            0: [
                -3.63,
                -18.46,
                -23.62,
                -21.59,
                -16.09,
                0.23,
                44.35,
                75.53,
                63.42,
                53.20,
                48.66,
                47.31,
                48.31,
                51.26,
                53.61,
                46.11,
                24.96,
            ],
            90: [
                -1.38,
                1.20,
                2.15,
                1.63,
                1.10,
                0.27,
                -2.28,
                -1.40,
                4.17,
                3.94,
                4.86,
                4.09,
                3.69,
                4.60,
                3.48,
                4.10,
                0.98,
            ],
        },
    },
    "A2_B2": {
        50: {
            0: [
                -1.83,
                -8.50,
                -13.60,
                -15.21,
                -14.48,
                -5.62,
                28.77,
                60.34,
                61.84,
                56.64,
                53.40,
                52.36,
                53.93,
                56.82,
                59.48,
                52.08,
                26.56,
            ],
            90: [
                -1.63,
                -0.60,
                -0.43,
                0.11,
                1.26,
                3.40,
                6.53,
                10.25,
                11.83,
                11.83,
                11.01,
                10.58,
                10.80,
                10.54,
                10.62,
                9.03,
                1.79,
            ],
        },
        200: {
            0: [
                -0.86,
                -7.00,
                -11.58,
                -13.36,
                -13.77,
                -6.74,
                24.63,
                53.19,
                54.89,
                50.72,
                48.03,
                47.13,
                48.25,
                51.35,
                53.35,
                45.37,
                24.01,
            ],
            90: [
                -1.35,
                -0.71,
                -0.81,
                -0.67,
                0.15,
                1.39,
                2.67,
                3.00,
                4.01,
                3.80,
                4.00,
                3.02,
                2.20,
                2.78,
                1.58,
                1.37,
                0.93,
            ],
        },
    },
}

[23]:
# ### Write dataset values to a CSV file
test_line_with_header = [test_data_header[0]] + test_line
[24]:
for line_name, freq_dict in test_data.items():
    for freq_value, phase_dict in freq_dict.items():
        for freq_angle, field_values in phase_dict.items():

            values_with_header = [test_data_header[1]] + field_values
            ziplist = zip(test_line_with_header, values_with_header)

            file_label = "Bz " + str(line_name) + " " + str(freq_value) + " " + str(freq_angle)
            file_path = os.path.join(project_dir, str(file_label) + ".csv")
            write_csv(output_file=file_path, list_data=ziplist)

Create rectangular plots and import test data into report#

Create rectangular plots, using text file encoding to control their formatting. Import test data into the correct plot and overlay with the simulation results.

[25]:
for line_name, freq_dict in test_data.items():
    for freq_value, phase_dict in freq_dict.items():
        plot_name = "Bz Along line " + line_name + " at " + str(freq_value) + "Hz"
        variations = {
            "Distance": ["All"],
            "Freq": [str(freq_value) + "Hz"],
            "Phase": [str(phase_deg) + "deg" for phase_deg in sorted(phase_dict.keys())],
            "Coil_Excitation": ["All"],
        }

        report = m3d.post.create_report(
            plot_name=plot_name,
            report_category="Fields",
            context="Line_" + str(line_name),
            primary_sweep_variable="Distance",
            variations=variations,
            expressions="Bz",
        )
        for freq_angle in sorted(phase_dict.keys()):
            file_label = "Bz " + str(line_name) + " " + str(freq_value) + " " + str(freq_angle)
            file_path = os.path.join(project_dir, str(file_label) + ".csv")
            report.import_traces(input_file=file_path, plot_name=plot_name)

Analyze project.

[26]:
m3d.analyze(cores=NUM_CORES)
PyAEDT INFO: Project COMPUMAG2 Saved correctly
PyAEDT INFO: Key Desktop/ActiveDSOConfigurations/Maxwell 3D correctly changed.
PyAEDT INFO: Solving all design setups. Analysis started...
PyAEDT INFO: Design setup None solved correctly in 0.0h 4.0m 7.0s
PyAEDT INFO: Key Desktop/ActiveDSOConfigurations/Maxwell 3D correctly changed.
[26]:
True

Create plots of induced current and flux density on surface of plate#

Create two plots of the induced current (Mag_J) and the flux density (Mag_B) on the surface of the plate.

[27]:
surf_list = m3d.modeler.get_object_faces(assignment="Plate")
intrinsic_dict = {"Freq": "200Hz", "Phase": "0deg"}
m3d.post.create_fieldplot_surface(
    assignment=surf_list,
    quantity="Mag_J",
    intrinsics=intrinsic_dict,
    plot_name="Mag_J",
)
m3d.post.create_fieldplot_surface(
    assignment=surf_list,
    quantity="Mag_B",
    intrinsics=intrinsic_dict,
    plot_name="Mag_B",
)
m3d.post.create_fieldplot_surface(assignment=surf_list, quantity="Mesh", intrinsics=intrinsic_dict, plot_name="Mesh")
PyAEDT INFO: Active Design set to TEAM_7_Asymmetric_Conductor
PyAEDT INFO: Active Design set to TEAM_7_Asymmetric_Conductor
PyAEDT INFO: Active Design set to TEAM_7_Asymmetric_Conductor
[27]:
Class: ansys.aedt.core.visualization.post.field_data.FieldPlot

Finish#

Save the project#

[28]:
m3d.save_project()
m3d.release_desktop()
# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.
time.sleep(3)
PyAEDT INFO: Project COMPUMAG2 Saved correctly
PyAEDT INFO: Desktop has been released and closed.

Clean up#

All project files are saved in the folder temp_folder.name. If you’ve run this example as a Jupyter notebook, you can retrieve those project files. The following cell removes all temporary files, including the project folder.

[29]:
temp_folder.cleanup()

Download this example

Download this example as a Jupyter Notebook or as a Python script.