{ "cells": [ { "cell_type": "markdown", "id": "e3e8798a", "metadata": {}, "source": [ "# PM synchronous motor transient analysis\n", "\n", "This example shows how to use PyAEDT to create a Maxwell 2D transient analysis for\n", "an interior permanent magnet (PM) electric motor.\n", "\n", "Model creation, setup and the solution process as well as visualization of the results are fully#\n", "automated. Only the motor cross-section is considered and 8-fold rotational symmetry is used to reduce the computational effort.\n", "\n", "Keywords: **Maxwell 2D**, **transient**, **motor**." ] }, { "cell_type": "markdown", "id": "cb94bd7f", "metadata": {}, "source": [ "## Prerequisites\n", "\n", "### Perform imports" ] }, { "cell_type": "code", "execution_count": null, "id": "606a8095", "metadata": {}, "outputs": [], "source": [ "import csv\n", "import tempfile\n", "import time\n", "from operator import attrgetter\n", "from pathlib import Path\n", "\n", "import ansys.aedt.core\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "\n", "from ansys.aedt.core.examples.downloads import download_file" ] }, { "cell_type": "markdown", "id": "06b32c4b", "metadata": {}, "source": [ "### Define constants\n", "Constants help ensure consistency and avoid repetition throughout the example." ] }, { "cell_type": "code", "execution_count": null, "id": "a7e684cb", "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": "abd489ad", "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": "f996fbb7", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "4d741bf9", "metadata": {}, "source": [ "## Model Preparation\n", "\n", "### Launch Maxwell 2D\n", "\n", "Launch AEDT and Maxwell 2D after first setting up the project and design names,\n", "the solver, and the version. The following code also creates an instance of the\n", "``Maxwell2d`` class named ``m2d``." ] }, { "cell_type": "code", "execution_count": null, "id": "183892d8", "metadata": {}, "outputs": [], "source": [ "project_name = Path(temp_folder.name) / \"PM_Motor.aedt\"\n", "m2d = ansys.aedt.core.Maxwell2d(\n", " project=project_name,\n", " version=AEDT_VERSION,\n", " design=\"Sinusoidal\",\n", " solution_type=\"TransientXY\",\n", "# new_desktop=True,\n", " non_graphical=NG_MODE,\n", ")\n", "m2d.modeler.model_units = \"mm\" # Specify model units" ] }, { "cell_type": "markdown", "id": "c408e077", "metadata": {}, "source": [ "### Define parameters\n", "\n", "Initialize parameters to define the stator, rotor, and shaft\n", "geometric properties.\n", "The parameter names are consistent with those\n", "used in \n", "[RMxprt](https://ansyshelp.ansys.com/public/account/secured?returnurl=/Views/Secured/Electronics/v252/en/Subsystems/Maxwell/Maxwell.htm%23Maxwell/GettingStartedwithRMxprt.htm?TocPath=Maxwell%2520Help%257CGetting%2520Started%2520with%2520RMxprt%257C_____0).\n", "\n", "Rotor geometric parameters:" ] }, { "cell_type": "code", "execution_count": null, "id": "c4db8059", "metadata": {}, "outputs": [], "source": [ "geom_params = {\n", " \"DiaGap\": \"132mm\",\n", " \"DiaStatorYoke\": \"198mm\",\n", " \"DiaStatorInner\": \"132mm\",\n", " \"DiaRotorLam\": \"130mm\",\n", " \"DiaShaft\": \"44.45mm\",\n", " \"DiaOuter\": \"198mm\",\n", " \"Airgap\": \"1mm\",\n", " \"SlotNumber\": \"48\",\n", " \"SlotType\": \"3\",\n", "}" ] }, { "cell_type": "markdown", "id": "eb67a752", "metadata": {}, "source": [ "Stator winding parameters:" ] }, { "cell_type": "code", "execution_count": null, "id": "874eca73", "metadata": {}, "outputs": [], "source": [ "wind_params = {\n", " \"Layers\": \"1\",\n", " \"ParallelPaths\": \"2\",\n", " \"R_Phase\": \"7.5mOhm\",\n", " \"WdgExt_F\": \"5mm\",\n", " \"SpanExt\": \"30mm\",\n", " \"SegAngle\": \"0.25\",\n", " \"CoilPitch\": \"5\", # coil pitch in slots\n", " \"Coil_SetBack\": \"3.605732823mm\",\n", " \"SlotWidth\": \"2.814mm\", # RMxprt Bs0\n", " \"Coil_Edge_Short\": \"3.769235435mm\",\n", " \"Coil_Edge_Long\": \"15.37828521mm\",\n", "}" ] }, { "cell_type": "markdown", "id": "ff799975", "metadata": {}, "source": [ "Additional model parameters:" ] }, { "cell_type": "code", "execution_count": null, "id": "a49269e7", "metadata": {}, "outputs": [], "source": [ "mod_params = {\n", " \"NumPoles\": \"8\", # Number of poles\n", " \"Model_Length\": \"80mm\", # Motor length in the axial direction.\n", " \"SymmetryFactor\": \"8\", # Symmetry allows reduction of the model size.\n", " \"Magnetic_Axial_Length\": \"150mm\",\n", " \"Stator_Lam_Length\": \"0mm\",\n", " \"StatorSkewAngle\": \"0deg\",\n", " \"NumTorquePointsPerCycle\": \"30\", # Number of points to sample torque during simulation.\n", " \"mapping_angle\": \"0.125*4deg\",\n", " \"num_m\": \"16\",\n", " \"Section_Angle\": \"360deg/SymmetryFactor\", # Used to apply symmetry boundaries.\n", "}" ] }, { "cell_type": "markdown", "id": "7ce4cd47", "metadata": {}, "source": [ "#### Stator current and initial rotor position\n", "\n", "The motor will be driven by a sinusoidal\n", "current source that will apply values defined in the ``oper_params``.\n", "The sources will be assigned to stator\n", "windings [later in this example](#define-stator-winding-source).\n", "\n", "Sinusoidal current:\n", "$$ I_x = I_\\text{peak} \\cos\\left(2\\pi f t + \\theta_i - \\phi_x \\right) $$\n", "\n", "where $x \\in \\{A, B, C\\}$ is the electrical phase.\n", "- $I_x\\rightarrow$ ``\"IPeak\"`` Amplitude of the current source for each winding.\n", "- $f \\rightarrow$ ``\"ElectricFrequency\"`` Frequency of the current source.\n", "- $\\theta_i$ ``\"Theta_i\"`` Initial rotor angle at $t=0$.\n", "- $\\phi_x$ is the phase angle. $x=A\\rightarrow 0^\\circ, x=B\\rightarrow120^\\circ, \n", " x=C\\rightarrow 240^\\circ$." ] }, { "cell_type": "code", "execution_count": null, "id": "5ae617d1", "metadata": {}, "outputs": [], "source": [ "oper_params = {\n", " \"InitialPositionMD\": \"180deg/4\",\n", " \"IPeak\": \"480A\",\n", " \"MachineRPM\": \"3000rpm\",\n", " \"ElectricFrequency\": \"MachineRPM/60rpm*NumPoles/2*1Hz\",\n", " \"ElectricPeriod\": \"1/ElectricFrequency\",\n", " \"BandTicksinModel\": \"360deg/NumPoles/mapping_angle\",\n", " \"TimeStep\": \"ElectricPeriod/(2*BandTicksinModel)\",\n", " \"StopTime\": \"ElectricPeriod\",\n", " \"Theta_i\": \"135deg\",\n", "}" ] }, { "cell_type": "markdown", "id": "e457281e", "metadata": {}, "source": [ "### Update the Maxwell 2D model\n", "\n", "Pass parameter names and values to the Maxwell 2D model." ] }, { "cell_type": "code", "execution_count": null, "id": "03b700c6", "metadata": {}, "outputs": [], "source": [ "for name, value in geom_params.items():\n", " m2d[name] = value\n", "for name, value in wind_params.items():\n", " m2d[name] = value\n", "for name, value in mod_params.items():\n", " m2d[name] = value\n", "for name, value in oper_params.items():\n", " m2d[name] = value" ] }, { "cell_type": "markdown", "id": "49d17c73", "metadata": {}, "source": [ "### Define materials and their properties.\n", "\n", "First, download the $B$-$H$ curves for the nonlinear magnetic materials from the [example-data](https://github.com/ansys/example-data/tree/main/pyaedt) repository.\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "e566f244", "metadata": {}, "outputs": [], "source": [ "data_folder = Path(download_file(r'pyaedt/nissan', local_path=temp_folder.name))" ] }, { "cell_type": "markdown", "id": "46e3ab99", "metadata": {}, "source": [ "#### Annealed copper at 65o C" ] }, { "cell_type": "code", "execution_count": null, "id": "04fb7835", "metadata": {}, "outputs": [], "source": [ "mat_coils = m2d.materials.add_material(\"Copper (Annealed)_65C\")\n", "mat_coils.update()\n", "mat_coils.conductivity = \"49288048.9198\"\n", "mat_coils.permeability = \"1\"" ] }, { "cell_type": "markdown", "id": "77cffb46", "metadata": {}, "source": [ "#### Nonlinear magnetic materials\n", "\n", "Define material properties. \n", "\n", "The nonlinear $B$-$H$ curves\n", "were retrieved\n", "from the [example-data](https://github.com/ansys/example-data/tree/main/pyaedt/nissan) repository\n", "using the ``download_file()`` method.\n", "\n", "The method ``bh_list()`` helps simplify assignment of data from the text file to the\n", "material permeability." ] }, { "cell_type": "code", "execution_count": null, "id": "7c7cc330", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "def bh_list(filepath):\n", " with open(filepath) as f:\n", " reader = csv.reader(f, delimiter=\"\\t\") # Ignore header\n", " next(reader)\n", " return [[float(row[0]), float(row[1])] for row in reader] # Return a list of B,H values" ] }, { "cell_type": "markdown", "id": "57127d52", "metadata": {}, "source": [ "#### Define the magnetic material properties.\n", "\n", "The following image\n", "shows how the BH curve can be viewed in the AEDT user interface\n", "after the $B$-$H$ curve has been assigned.\n", "\n", "\n", "\n", "Define the material ``\"Arnold_Magnetics_N30UH_80C\"``. " ] }, { "cell_type": "code", "execution_count": null, "id": "d3d72a6e", "metadata": {}, "outputs": [], "source": [ "mat_PM = m2d.materials.add_material(name=\"Arnold_Magnetics_N30UH_80C_new\")\n", "mat_PM.update()\n", "mat_PM.conductivity = \"555555.5556\"\n", "mat_PM.set_magnetic_coercivity(value=-800146.66287534, x=1, y=0, z=0)\n", "mat_PM.mass_density = \"7500\"\n", "mat_PM.permeability = bh_list(data_folder / 'BH_Arnold_Magnetics_N30UH_80C.tab')" ] }, { "cell_type": "markdown", "id": "bda33ad3", "metadata": {}, "source": [ "Define the laminate material, ``\"30DH_20C_smooth\"``." ] }, { "cell_type": "code", "execution_count": null, "id": "720952e1", "metadata": {}, "outputs": [], "source": [ "mat_lam = m2d.materials.add_material(\"30DH_20C_smooth\")\n", "mat_lam.update()\n", "mat_lam.conductivity = \"1694915.25424\"\n", "kh = 71.7180985413\n", "kc = 0.25092214579\n", "ke = 12.1625774023\n", "kdc = 0.001\n", "eq_depth = 0.001\n", "mat_lam.set_electrical_steel_coreloss(kh, kc, ke, kdc, eq_depth)\n", "mat_lam.mass_density = \"7650\"\n", "mat_lam.permeability = bh_list(data_folder / '30DH_20C_smooth.tab')" ] }, { "cell_type": "markdown", "id": "d062a00b", "metadata": {}, "source": [ "## Create the stator\n", "\n", "Create the geometry for the built-in\n", "user-defined primitive (UDP). A list of lists is\n", "created with the proper UDP parameters.\n", "\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "8ade3a8e", "metadata": {}, "outputs": [], "source": [ "udp_par_list_stator = [\n", " [\"DiaGap\", \"DiaGap\"],\n", " [\"DiaYoke\", \"DiaStatorYoke\"],\n", " [\"Length\", \"Stator_Lam_Length\"],\n", " [\"Skew\", \"StatorSkewAngle\"],\n", " [\"Slots\", \"SlotNumber\"],\n", " [\"SlotType\", \"SlotType\"],\n", " [\"Hs0\", \"1.2mm\"],\n", " [\"Hs01\", \"0mm\"],\n", " [\"Hs1\", \"0.4834227384999mm\"],\n", " [\"Hs2\", \"17.287669825502mm\"],\n", " [\"Bs0\", \"2.814mm\"],\n", " [\"Bs1\", \"4.71154109036mm\"],\n", " [\"Bs2\", \"6.9777285790998mm\"],\n", " [\"Rs\", \"2mm\"],\n", " [\"FilletType\", \"1\"],\n", " [\"HalfSlot\", \"0\"],\n", " [\"VentHoles\", \"0\"],\n", " [\"HoleDiaIn\", \"0mm\"],\n", " [\"HoleDiaOut\", \"0mm\"],\n", " [\"HoleLocIn\", \"0mm\"],\n", " [\"HoleLocOut\", \"0mm\"],\n", " [\"VentDucts\", \"0\"],\n", " [\"DuctWidth\", \"0mm\"],\n", " [\"DuctPitch\", \"0mm\"],\n", " [\"SegAngle\", \"0deg\"],\n", " [\"LenRegion\", \"Model_Length\"],\n", " [\"InfoCore\", \"0\"],\n", "]\n", "\n", "stator = m2d.modeler.create_udp(\n", " dll=\"RMxprt/VentSlotCore.dll\",\n", " parameters=udp_par_list_stator,\n", " library=\"syslib\",\n", " name=\"my_stator\",\n", ")" ] }, { "cell_type": "markdown", "id": "470c3c91", "metadata": {}, "source": [ "Assign material and simulation properties to the\n", "stator. Additionally, the rendered color and ``\"solve_inside\"``\n", "are set. The latter tells Maxwell to solve the full eddy-current\n", "solution inside the laminate conductors." ] }, { "cell_type": "code", "execution_count": null, "id": "1f9c12bb", "metadata": {}, "outputs": [], "source": [ "m2d.assign_material(assignment=stator, material=\"30DH_20C_smooth\")\n", "stator.name = \"Stator\"\n", "stator.color = (0, 0, 255) # rgb\n", "stator.solve_inside = True" ] }, { "cell_type": "markdown", "id": "3fb962c6", "metadata": { "lines_to_next_cell": 2 }, "source": [ "### Create outer and inner permanent magnets\n", "\n", "Draw permanent magnets." ] }, { "cell_type": "code", "execution_count": null, "id": "e4169271", "metadata": {}, "outputs": [], "source": [ "IM1_points = [\n", " [56.70957112, 3.104886585, 0],\n", " [40.25081875, 16.67243502, 0],\n", " [38.59701538, 14.66621111, 0],\n", " [55.05576774, 1.098662669, 0],\n", "]\n", "OM1_points = [\n", " [54.37758185, 22.52393189, 0],\n", " [59.69688156, 9.68200639, 0],\n", " [63.26490432, 11.15992981, 0],\n", " [57.94560461, 24.00185531, 0],\n", "]\n", "IPM1 = m2d.modeler.create_polyline(\n", " points=IM1_points,\n", " cover_surface=True,\n", " name=\"PM_I1\",\n", " material=\"Arnold_Magnetics_N30UH_80C_new\",\n", ")\n", "IPM1.color = (0, 128, 64)\n", "IPM1.solve_inside = True\n", "OPM1 = m2d.modeler.create_polyline(\n", " points=OM1_points,\n", " cover_surface=True,\n", " name=\"PM_O1\",\n", " material=\"Arnold_Magnetics_N30UH_80C_new\",\n", ")\n", "OPM1.color = (0, 128, 64)\n", "OPM1.solve_inside = True" ] }, { "cell_type": "markdown", "id": "d3ad3264", "metadata": {}, "source": [ "#### Define the orientation for PM magnetization\n", "\n", "The magnetization of the permanent\n", "magnets will be oriented along the $x$-direction of\n", "a local coordinate system associated with each\n", "magnet.\n", "\n", "The method ``create_cs_magnets()`` will be used to\n", "create the \n", "coordinate system at the center of each magnet." ] }, { "cell_type": "code", "execution_count": null, "id": "8ee83785", "metadata": {}, "outputs": [], "source": [ "def create_magnet_cs(pm, cs_name, point_direction):\n", " \"\"\"\n", " Parameters\n", " ----------\n", " pm : Polyline\n", " Permanent magnet 2D object.\n", " cs_name : str\n", " The name to be assigned to the coordinate system.\n", " point_direction : str\n", " \"inner\" B-field oriented toward the motor shaft.\n", " \"outer\" B-field oriented away from the shaft.\n", " \"\"\"\n", "\n", " edges = sorted(pm.edges, key=attrgetter(\"length\"), reverse=True)\n", "\n", " if point_direction == \"outer\":\n", " my_axis_pos = edges[0]\n", " elif point_direction == \"inner\":\n", " my_axis_pos = edges[1]\n", "\n", " m2d.modeler.create_face_coordinate_system(\n", " face=pm.faces[0],\n", " origin=pm.faces[0],\n", " axis_position=my_axis_pos,\n", " axis=\"X\",\n", " name=cs_name,\n", " )\n", " pm.part_coordinate_system = cs_name\n", " m2d.modeler.set_working_coordinate_system(\"Global\")" ] }, { "cell_type": "markdown", "id": "f024cee8", "metadata": {}, "source": [ "Create the coordinate system for PMs in the face center." ] }, { "cell_type": "code", "execution_count": null, "id": "82f6fcd5", "metadata": {}, "outputs": [], "source": [ "create_magnet_cs(IPM1, \"CS_\" + IPM1.name, \"outer\")\n", "create_magnet_cs(OPM1, \"CS_\" + OPM1.name, \"outer\")" ] }, { "cell_type": "markdown", "id": "42db4c55", "metadata": {}, "source": [ "### Duplicate and mirror PMs\n", "\n", "Duplicate and mirror the magnets. Material definitions and the\n", "local coordinate systems are duplicated as well." ] }, { "cell_type": "code", "execution_count": null, "id": "088f6748", "metadata": {}, "outputs": [], "source": [ "m2d.modeler.duplicate_and_mirror(\n", " assignment=[IPM1, OPM1],\n", " origin=[0, 0, 0],\n", " vector=[\n", " \"cos((360deg/SymmetryFactor/2)+90deg)\",\n", " \"sin((360deg/SymmetryFactor/2)+90deg)\",\n", " 0,\n", " ],\n", ")\n", "id_PMs = m2d.modeler.get_objects_w_string(string_name=\"PM\", case_sensitive=True)" ] }, { "cell_type": "markdown", "id": "6d7b1678", "metadata": {}, "source": [ "The permanent magnets are shown below.\n", "\n", "\n", "\n", "### Create coils" ] }, { "cell_type": "code", "execution_count": null, "id": "774eb4d1", "metadata": {}, "outputs": [], "source": [ "coil = m2d.modeler.create_rectangle(\n", " origin=[\"DiaRotorLam/2+Airgap+Coil_SetBack\", \"-Coil_Edge_Short/2\", 0],\n", " sizes=[\"Coil_Edge_Long\", \"Coil_Edge_Short\", 0],\n", " name=\"Coil\",\n", " material=\"Copper (Annealed)_65C\",\n", ")\n", "coil.color = (255, 128, 0)\n", "m2d.modeler.rotate(assignment=coil, axis=\"Z\", angle=\"360deg/SlotNumber/2\")\n", "coil.duplicate_around_axis(\n", " axis=\"Z\", angle=\"360deg/SlotNumber\", clones=\"CoilPitch+1\", create_new_objects=True\n", ")\n", "id_coils = m2d.modeler.get_objects_w_string(string_name=\"Coil\", case_sensitive=True)" ] }, { "cell_type": "markdown", "id": "634d3826", "metadata": {}, "source": [ "### Create the shaft and surrounding region" ] }, { "cell_type": "code", "execution_count": null, "id": "2288c5de", "metadata": {}, "outputs": [], "source": [ "region = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"DiaOuter/2\",\n", " num_sides=\"SegAngle\",\n", " is_covered=True,\n", " name=\"Region\",\n", ")\n", "shaft = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"DiaShaft/2\",\n", " num_sides=\"SegAngle\",\n", " is_covered=True,\n", " name=\"Shaft\",\n", ")" ] }, { "cell_type": "markdown", "id": "bf7adef7", "metadata": {}, "source": [ "### Create band objects\n", "\n", "The band objects are required to assign the rotational motion of the machine.\n", "Everything outside the outer band object is stationary, while objects inside\n", "the band (i.e. the rotor and magnets) rotate.\n", "\n", "Create the inner band, outer band, and outer band.\n", "\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "43548413", "metadata": {}, "outputs": [], "source": [ "bandIN = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"(DiaGap - (1.5 * Airgap))/2\",\n", " num_sides=\"mapping_angle\",\n", " is_covered=True,\n", " name=\"Inner_Band\",\n", ")\n", "bandMID = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"(DiaGap - (1.0 * Airgap))/2\",\n", " num_sides=\"mapping_angle\",\n", " is_covered=True,\n", " name=\"Band\",\n", ")\n", "bandOUT= m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"(DiaGap - (0.5 * Airgap))/2\",\n", " num_sides=\"mapping_angle\",\n", " is_covered=True,\n", " name=\"Outer_Band\",\n", ")" ] }, { "cell_type": "markdown", "id": "38f567bf", "metadata": {}, "source": [ "### Assign \"vacuum\" material\n", "\n", "The band objects, region and shaft will all be assigned the\n", "material \"vacuum\". " ] }, { "cell_type": "code", "execution_count": null, "id": "cce888fa", "metadata": {}, "outputs": [], "source": [ "vacuum_obj = [\n", " shaft,\n", " region,\n", " bandIN,\n", " bandMID,\n", " bandOUT,\n", "] # put shaft first\n", "for item in vacuum_obj:\n", " item.color = (128, 255, 255)" ] }, { "cell_type": "markdown", "id": "34e1d029", "metadata": {}, "source": [ "### Create rotor\n", "\n", "\n", "\n", "Create the rotor with holes and pockets for the \n", "permanent magnets." ] }, { "cell_type": "code", "execution_count": null, "id": "ca9ec041", "metadata": {}, "outputs": [], "source": [ "rotor = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"DiaRotorLam/2\",\n", " num_sides=0,\n", " name=\"Rotor\",\n", " material=\"30DH_20C_smooth\",\n", ")\n", "\n", "rotor.color = (0, 128, 255)\n", "rotor.solve_inside = True\n", "m2d.modeler.subtract(blank_list=rotor, tool_list=shaft, keep_originals=True)\n", "void_small_1 = m2d.modeler.create_circle(\n", " origin=[62, 0, 0], radius=\"2.55mm\", num_sides=0, name=\"void1\", material=\"vacuum\"\n", ")\n", "void_small_1.solve_inside = True\n", "\n", "m2d.modeler.duplicate_around_axis(\n", " assignment=void_small_1,\n", " axis=\"Z\",\n", " angle=\"360deg/SymmetryFactor\",\n", " clones=2,\n", " create_new_objects=False,\n", ")\n", "\n", "void_big_1 = m2d.modeler.create_circle(\n", " origin=[29.5643, 12.234389332712, 0],\n", " radius=\"9.88mm/2\",\n", " num_sides=0,\n", " name=\"void_big\",\n", " material=\"vacuum\",\n", ")\n", "void_big_1.solve_inside = True\n", "\n", "m2d.modeler.subtract(\n", " blank_list=rotor,\n", " tool_list=[void_small_1, void_big_1],\n", " keep_originals=False,\n", ")\n", "\n", "slot_IM1_points = [\n", " [37.5302872, 15.54555396, 0],\n", " [55.05576774, 1.098662669, 0],\n", " [57.33637589, 1.25, 0],\n", " [57.28982158, 2.626565019, 0],\n", " [40.25081875, 16.67243502, 0],\n", "]\n", "slot_OM1_points = [\n", " [54.37758185, 22.52393189, 0],\n", " [59.69688156, 9.68200639, 0],\n", " [63.53825619, 10.5, 0],\n", " [57.94560461, 24.00185531, 0],\n", "]\n", "slot_IM = m2d.modeler.create_polyline(\n", " points=slot_IM1_points, cover_surface=True, name=\"slot_IM1\", material=\"vacuum\"\n", ")\n", "slot_IM.solve_inside = True\n", "slot_OM = m2d.modeler.create_polyline(\n", " points=slot_OM1_points, cover_surface=True, name=\"slot_OM1\", material=\"vacuum\"\n", ")\n", "slot_OM.solve_inside = True\n", "\n", "m2d.modeler.duplicate_and_mirror(\n", " assignment=[slot_IM, slot_OM],\n", " origin=[0, 0, 0],\n", " vector=[\n", " \"cos((360deg/SymmetryFactor/2)+90deg)\",\n", " \"sin((360deg/SymmetryFactor/2)+90deg)\",\n", " 0,\n", " ],\n", ")\n", "\n", "id_holes = m2d.modeler.get_objects_w_string(string_name=\"slot_\", case_sensitive=True)\n", "m2d.modeler.subtract(rotor, id_holes, keep_originals=True)" ] }, { "cell_type": "markdown", "id": "72ade138", "metadata": {}, "source": [ "### Apply symmetry\n", "\n", "\n", "\n", "Create a section of the machine for which electrical and\n", "geometric symmetry apply." ] }, { "cell_type": "code", "execution_count": null, "id": "840d7fa6", "metadata": {}, "outputs": [], "source": [ "object_list = [stator, rotor] + vacuum_obj\n", "m2d.modeler.create_coordinate_system(\n", " origin=[0, 0, 0],\n", " reference_cs=\"Global\",\n", " name=\"Section\",\n", " mode=\"axis\",\n", " x_pointing=[\"cos(360deg/SymmetryFactor)\", \"sin(360deg/SymmetryFactor)\", 0],\n", " y_pointing=[\"-sin(360deg/SymmetryFactor)\", \"cos(360deg/SymmetryFactor)\", 0],\n", ")\n", "\n", "m2d.modeler.set_working_coordinate_system(\"Section\")\n", "m2d.modeler.split(assignment=object_list, plane=\"ZX\", sides=\"NegativeOnly\")\n", "m2d.modeler.set_working_coordinate_system(\"Global\")\n", "m2d.modeler.split(assignment=object_list, plane=\"ZX\", sides=\"PositiveOnly\")" ] }, { "cell_type": "markdown", "id": "919a4ab1", "metadata": {}, "source": [ "Create linked boundary conditions to apply\n", "electrical symmetry.\n", "Edges of the region object are selected based on their position.\n", "The edge selection point on the region object lies in the \n", "air-gap." ] }, { "cell_type": "code", "execution_count": null, "id": "741eff18", "metadata": {}, "outputs": [], "source": [ "pos_1 = \"((DiaGap - (1.0 * Airgap))/4)\"\n", "id_bc_1 = m2d.modeler.get_edgeid_from_position(\n", " position=[pos_1, 0, 0], assignment=\"Region\"\n", ")\n", "id_bc_2 = m2d.modeler.get_edgeid_from_position(\n", " position=[\n", " pos_1 + \"*cos((360deg/SymmetryFactor))\",\n", " pos_1 + \"*sin((360deg/SymmetryFactor))\",\n", " 0,\n", " ],\n", " assignment=\"Region\",\n", ")\n", "m2d.assign_master_slave(\n", " independent=id_bc_1,\n", " dependent=id_bc_2,\n", " reverse_master=False,\n", " reverse_slave=True,\n", " same_as_master=False,\n", " boundary=\"Matching\",\n", ")" ] }, { "cell_type": "markdown", "id": "8b2c3b81", "metadata": {}, "source": [ "### Assign outer boundary condition\n", "\n", "Assign the boundary condition for the magnetic \n", "vector potnetial, $A_z=0$ on the \n", "outer perimeter of the motor." ] }, { "cell_type": "code", "execution_count": null, "id": "065d4e10", "metadata": {}, "outputs": [], "source": [ "pos_2 = \"(DiaOuter/2)\"\n", "id_bc_az = m2d.modeler.get_edgeid_from_position(\n", " position=[\n", " pos_2 + \"*cos((360deg/SymmetryFactor/2))\",\n", " pos_2 + \"*sin((360deg/SymmetryFactor)/2)\",\n", " 0,\n", " ],\n", " assignment=\"Region\",\n", ")\n", "m2d.assign_vector_potential(\n", " assignment=id_bc_az, vector_value=0, boundary=\"VectorPotentialZero\"\n", ")" ] }, { "cell_type": "markdown", "id": "7bad0593", "metadata": {}, "source": [ "### Define stator winding current sources\n", "\n", "\n", "\n", "The stator windings will be driven with a 3-phase sinusoidal current whose amplitude and frequency\n", "were defined earlier parameters that were defined earlier in this example. The windigs have 6 conductors each.\n", "The following function can be used define the windings and assign excitations:" ] }, { "cell_type": "code", "execution_count": null, "id": "04369168", "metadata": {}, "outputs": [], "source": [ "def assign_winding(name=\"A\", phase=\"\", obj_p=None, obj_n=None, nconductors=6):\n", " \"\"\"\n", " Parameters\n", " ----------\n", " phase : str, Optinonal\n", " Current source phase. For example, \"120deg\"\n", " obj_p : str\n", " The name of the winding object for positive current injection.\n", " obj_n : str\n", " The name of the winding object where current returns.\n", " nconductors : int\n", " Number of strands per winding.\n", " name : str\n", " String to use for naming sources and windings.\n", " \n", " \"\"\"\n", " phase_str = f\"+ Theta_i - {phase}\"\n", " ph_current = f\"IPeak * cos(2*pi*ElectricFrequency*time {phase_str})\"\n", " phase_name = f\"Phase_{name}\"\n", " pos_coil_name = f\"Phase_{name}_pos\"\n", " neg_coil_name = f\"Phase_{name}_neg\"\n", " m2d.assign_coil(\n", " assignment=[obj_p],\n", " conductors_number=nconductors,\n", " polarity=\"Positive\",\n", " name=pos_coil_name,\n", " )\n", " m2d.assign_coil(\n", " assignment=[obj_n],\n", " conductors_number=nconductors,\n", " polarity=\"Negative\",\n", " name=neg_coil_name,\n", " )\n", " m2d.assign_winding(\n", " assignment=None,\n", " winding_type=\"Current\",\n", " is_solid=False,\n", " current=ph_current,\n", " parallel_branches=1,\n", " name=phase_name,\n", " )\n", " m2d.add_winding_coils(\n", " assignment=phase_name, coils=[pos_coil_name, neg_coil_name]\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "6d973afb", "metadata": {}, "outputs": [], "source": [ "assign_winding(\"A\", \"0deg\", \"Coil\", \"Coil_5\")\n", "assign_winding(\"B\", \"120deg\", \"Coil_3\", \"Coil_4\")\n", "assign_winding(\"C\", \"240deg\", \"Coil_1\", \"Coil_2\")" ] }, { "cell_type": "markdown", "id": "69b9e00a", "metadata": {}, "source": [ "Set the $J_z=0$ on the permanent magnets." ] }, { "cell_type": "code", "execution_count": null, "id": "d06225d8", "metadata": {}, "outputs": [], "source": [ "PM_list = id_PMs\n", "for item in PM_list:\n", " m2d.assign_current(assignment=item, amplitude=0, solid=True, name=item + \"_I0\")" ] }, { "cell_type": "markdown", "id": "2fbcea3a", "metadata": {}, "source": [ "### Create mesh operations\n", "Mesh operations are used to refine the finite element mesh and\n", "ensure accuracy of the solution. This example uses a relatively coarse\n", "mesh so the simulation runs quickly. Accuracy can be improved\n", "by increasing mesh density (reducing ``maximum_length``)." ] }, { "cell_type": "code", "execution_count": null, "id": "484c8f16", "metadata": {}, "outputs": [], "source": [ "m2d.mesh.assign_length_mesh( # Coils\n", " assignment=id_coils,\n", " inside_selection=True,\n", " maximum_length=3,\n", " maximum_elements=None,\n", " name=\"coils\",\n", ")\n", "m2d.mesh.assign_length_mesh( # Stator\n", " assignment=stator,\n", " inside_selection=True,\n", " maximum_length=3,\n", " maximum_elements=None,\n", " name=\"stator\",\n", ")\n", "m2d.mesh.assign_length_mesh( # Rotor\n", " assignment=rotor,\n", " inside_selection=True,\n", " maximum_length=3,\n", " maximum_elements=None,\n", " name=\"rotor\",\n", ")" ] }, { "cell_type": "markdown", "id": "52b07725", "metadata": {}, "source": [ "Enable core loss calculation" ] }, { "cell_type": "code", "execution_count": null, "id": "5037be69", "metadata": {}, "outputs": [], "source": [ "core_loss_list = [\"Rotor\", \"Stator\"]\n", "m2d.set_core_losses(core_loss_list, core_loss_on_field=True)" ] }, { "cell_type": "markdown", "id": "6ee4d187", "metadata": {}, "source": [ "Enable calcuation of the time-dependent inductance" ] }, { "cell_type": "code", "execution_count": null, "id": "dd2b784b", "metadata": {}, "outputs": [], "source": [ "m2d.change_inductance_computation(\n", " compute_transient_inductance=True, incremental_matrix=False\n", ")" ] }, { "cell_type": "markdown", "id": "499dd162", "metadata": {}, "source": [ "Specify the length of the motor.\n", "\n", "The motor length along with rotor mass are used to calculate the interia for the transient\n", "simulation." ] }, { "cell_type": "code", "execution_count": null, "id": "14de96d3", "metadata": {}, "outputs": [], "source": [ "m2d.model_depth = \"Magnetic_Axial_Length\"" ] }, { "cell_type": "markdown", "id": "9beb1b40", "metadata": {}, "source": [ "### Specify the symmetry multiplier" ] }, { "cell_type": "code", "execution_count": null, "id": "92192654", "metadata": {}, "outputs": [], "source": [ "m2d.change_symmetry_multiplier(\"SymmetryFactor\")" ] }, { "cell_type": "markdown", "id": "41baf170", "metadata": {}, "source": [ "### Assign motion setup to object\n", "\n", "Assign a motion setup to a ``Band`` object named ``RotatingBand_mid``." ] }, { "cell_type": "code", "execution_count": null, "id": "881cc234", "metadata": {}, "outputs": [], "source": [ "m2d.assign_rotate_motion(\n", " assignment=\"Band\",\n", " coordinate_system=\"Global\",\n", " axis=\"Z\",\n", " positive_movement=True,\n", " start_position=\"InitialPositionMD\",\n", " angular_velocity=\"MachineRPM\",\n", ")" ] }, { "cell_type": "markdown", "id": "771ef941", "metadata": {}, "source": [ "### Create simulation setup" ] }, { "cell_type": "code", "execution_count": null, "id": "ec71d505", "metadata": {}, "outputs": [], "source": [ "setup_name = \"MySetupAuto\"\n", "setup = m2d.create_setup(name=setup_name)\n", "setup.props[\"StopTime\"] = \"StopTime\"\n", "setup.props[\"TimeStep\"] = \"TimeStep\"\n", "setup.props[\"SaveFieldsType\"] = \"None\"\n", "setup.props[\"OutputPerObjectCoreLoss\"] = True\n", "setup.props[\"OutputPerObjectSolidLoss\"] = True\n", "setup.props[\"OutputError\"] = True\n", "setup.update()\n", "m2d.validate_simple() # Validate the model\n", "\n", "model = m2d.plot(show=False)\n", "model.plot(Path(temp_folder.name) / \"Image.jpg\")" ] }, { "cell_type": "markdown", "id": "b4aff759", "metadata": {}, "source": [ "### Initialize definitions for output variables\n", "\n", "Initialize the definitions for the output variables.\n", "These are used later to generate reports." ] }, { "cell_type": "code", "execution_count": null, "id": "d7ef159c", "metadata": {}, "outputs": [], "source": [ "output_vars = {\n", " \"Current_A\": \"InputCurrent(Phase_A)\",\n", " \"Current_B\": \"InputCurrent(Phase_B)\",\n", " \"Current_C\": \"InputCurrent(Phase_C)\",\n", " \"Flux_A\": \"FluxLinkage(Phase_A)\",\n", " \"Flux_B\": \"FluxLinkage(Phase_B)\",\n", " \"Flux_C\": \"FluxLinkage(Phase_C)\",\n", " \"pos\": \"(Moving1.Position -InitialPositionMD) *NumPoles/2\",\n", " \"cos0\": \"cos(pos)\",\n", " \"cos1\": \"cos(pos-2*PI/3)\",\n", " \"cos2\": \"cos(pos-4*PI/3)\",\n", " \"sin0\": \"sin(pos)\",\n", " \"sin1\": \"sin(pos-2*PI/3)\",\n", " \"sin2\": \"sin(pos-4*PI/3)\",\n", " \"Flux_d\": \"2/3*(Flux_A*cos0+Flux_B*cos1+Flux_C*cos2)\",\n", " \"Flux_q\": \"-2/3*(Flux_A*sin0+Flux_B*sin1+Flux_C*sin2)\",\n", " \"I_d\": \"2/3*(Current_A*cos0 + Current_B*cos1 + Current_C*cos2)\",\n", " \"I_q\": \"-2/3*(Current_A*sin0 + Current_B*sin1 + Current_C*sin2)\",\n", " \"Irms\": \"sqrt(I_d^2+I_q^2)/sqrt(2)\",\n", " \"ArmatureOhmicLoss_DC\": \"Irms^2*R_phase\",\n", " \"Lad\": \"L(Phase_A,Phase_A)*cos0 + L(Phase_A,Phase_B)*cos1 + L(Phase_A,Phase_C)*cos2\",\n", " \"Laq\": \"L(Phase_A,Phase_A)*sin0 + L(Phase_A,Phase_B)*sin1 + L(Phase_A,Phase_C)*sin2\",\n", " \"Lbd\": \"L(Phase_B,Phase_A)*cos0 + L(Phase_B,Phase_B)*cos1 + L(Phase_B,Phase_C)*cos2\",\n", " \"Lbq\": \"L(Phase_B,Phase_A)*sin0 + L(Phase_B,Phase_B)*sin1 + L(Phase_B,Phase_C)*sin2\",\n", " \"Lcd\": \"L(Phase_C,Phase_A)*cos0 + L(Phase_C,Phase_B)*cos1 + L(Phase_C,Phase_C)*cos2\",\n", " \"Lcq\": \"L(Phase_C,Phase_A)*sin0 + L(Phase_C,Phase_B)*sin1 + L(Phase_C,Phase_C)*sin2\",\n", " \"L_d\": \"(Lad*cos0 + Lbd*cos1 + Lcd*cos2) * 2/3\",\n", " \"L_q\": \"(Laq*sin0 + Lbq*sin1 + Lcq*sin2) * 2/3\",\n", " \"OutputPower\": \"Moving1.Speed*Moving1.Torque\",\n", " \"Ui_A\": \"InducedVoltage(Phase_A)\",\n", " \"Ui_B\": \"InducedVoltage(Phase_B)\",\n", " \"Ui_C\": \"InducedVoltage(Phase_C)\",\n", " \"Ui_d\": \"2/3*(Ui_A*cos0 + Ui_B*cos1 + Ui_C*cos2)\",\n", " \"Ui_q\": \"-2/3*(Ui_A*sin0 + Ui_B*sin1 + Ui_C*sin2)\",\n", " \"U_A\": \"Ui_A+R_Phase*Current_A\",\n", " \"U_B\": \"Ui_B+R_Phase*Current_B\",\n", " \"U_C\": \"Ui_C+R_Phase*Current_C\",\n", " \"U_d\": \"2/3*(U_A*cos0 + U_B*cos1 + U_C*cos2)\",\n", " \"U_q\": \"-2/3*(U_A*sin0 + U_B*sin1 + U_C*sin2)\",\n", "}" ] }, { "cell_type": "markdown", "id": "bf831610", "metadata": {}, "source": [ "### Create output variables for postprocessing" ] }, { "cell_type": "code", "execution_count": null, "id": "0979edb6", "metadata": {}, "outputs": [], "source": [ "for k, v in output_vars.items():\n", " m2d.create_output_variable(k, v)" ] }, { "cell_type": "markdown", "id": "d8dace1d", "metadata": {}, "source": [ "### Create reports\n", "\n", "Define common keyword arguments shared by all time-domain reports, then create each\n", "report by specifying only its expressions and plot name. This avoids repeating the\n", "same arguments for every ``create_report`` call." ] }, { "cell_type": "code", "execution_count": null, "id": "281aa767", "metadata": {}, "outputs": [], "source": [ "report_kwargs = dict(\n", " setup_sweep_name=m2d.nominal_sweep,\n", " domain=\"Sweep\",\n", " primary_sweep_variable=\"Time\",\n", " plot_type=\"Rectangular Plot\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "f6e3c026", "metadata": {}, "outputs": [], "source": [ "reports = [\n", " (\"Moving1.Torque\", \"TorquePlots\"),\n", " ([\"U_A\", \"U_B\", \"U_C\", \"Ui_A\", \"Ui_B\", \"Ui_C\"], \"PhaseVoltages\"),\n", " ([\"CoreLoss\", \"SolidLoss\", \"ArmatureOhmicLoss_DC\"], \"Losses\"),\n", " ([\"InputCurrent(Phase_A)\", \"InputCurrent(Phase_B)\", \"InputCurrent(Phase_C)\"], \"PhaseCurrents\"),\n", " ([\"FluxLinkage(Phase_A)\", \"FluxLinkage(Phase_B)\", \"FluxLinkage(Phase_C)\"], \"PhaseFluxes\"),\n", " ([\"I_d\", \"I_q\"], \"Currents_dq\"),\n", " ([\"Flux_d\", \"Flux_q\"], \"Fluxes_dq\"),\n", " ([\"Ui_d\", \"Ui_q\"], \"InducedVoltages_dq\"),\n", " ([\"U_d\", \"U_q\"], \"Voltages_dq\"),\n", " ([\"L(Phase_A,Phase_A)\", \"L(Phase_B,Phase_B)\", \"L(Phase_C,Phase_C)\",\n", " \"L(Phase_A,Phase_B)\", \"L(Phase_A,Phase_C)\", \"L(Phase_B,Phase_C)\"], \"PhaseInductances\"),\n", " ([\"L_d\", \"L_q\"], \"Inductances_dq\"),\n", " ([\"CoreLoss\", \"CoreLoss(Stator)\", \"CoreLoss(Rotor)\"], \"CoreLosses\"),\n", " ([\"EddyCurrentLoss\", \"EddyCurrentLoss(Stator)\", \"EddyCurrentLoss(Rotor)\"], \"EddyCurrentLosses (Core)\"),\n", " ([\"ExcessLoss\", \"ExcessLoss(Stator)\", \"ExcessLoss(Rotor)\"], \"ExcessLosses (Core)\"),\n", " ([\"HysteresisLoss\", \"HysteresisLoss(Stator)\", \"HysteresisLoss(Rotor)\"], \"HysteresisLosses (Core)\"),\n", " ([\"SolidLoss\", \"SolidLoss(IPM1)\", \"SolidLoss(IPM1_1)\", \"SolidLoss(OPM1)\", \"SolidLoss(OPM1_1)\"], \"SolidLoss\"),\n", "]" ] }, { "cell_type": "code", "execution_count": null, "id": "1e4e9747", "metadata": {}, "outputs": [], "source": [ "for expressions, plot_name in reports:\n", " m2d.post.create_report(expressions=expressions, plot_name=plot_name, **report_kwargs)" ] }, { "cell_type": "markdown", "id": "900a7d85", "metadata": {}, "source": [ "### Analyze and save project" ] }, { "cell_type": "code", "execution_count": null, "id": "b1d39cfc", "metadata": {}, "outputs": [], "source": [ "m2d.save_project()\n", "m2d.analyze_setup(setup_name, use_auto_settings=False, cores=NUM_CORES)" ] }, { "cell_type": "markdown", "id": "62f5f857", "metadata": {}, "source": [ "### Create flux lines plot on region\n", "\n", "Create a flux lines plot on a region. The ``object_list`` is\n", "formerly created when the section is applied." ] }, { "cell_type": "code", "execution_count": null, "id": "092a264c", "metadata": {}, "outputs": [], "source": [ "faces_reg = m2d.modeler.get_object_faces(object_list[1].name) # Region\n", "plot1 = m2d.post.create_fieldplot_surface(\n", " assignment=faces_reg,\n", " quantity=\"Flux_Lines\",\n", " intrinsics={\"Time\": m2d.variable_manager.variables[\"StopTime\"].evaluated_value},\n", " plot_name=\"Flux_Lines\",\n", ")" ] }, { "cell_type": "markdown", "id": "4175bd05", "metadata": {}, "source": [ "### Export a field plot to an image file\n", "\n", "Export the flux lines plot to an image file using Python PyVista." ] }, { "cell_type": "code", "execution_count": null, "id": "2701b7c9", "metadata": {}, "outputs": [], "source": [ "m2d.post.plot_field_from_fieldplot(plot1.name, show=False)" ] }, { "cell_type": "markdown", "id": "a9f09114", "metadata": {}, "source": [ "### Get solution data\n", "\n", "Retrieve shaft torque as a function of time. ``get_expression_data`` returns\n", "the time axis (in ns) and the torque values as numpy arrays in a single call." ] }, { "cell_type": "code", "execution_count": null, "id": "91242717", "metadata": {}, "outputs": [], "source": [ "solutions = m2d.post.get_solution_data(\n", " expressions=\"Moving1.Torque\",\n", " setup_sweep_name=m2d.nominal_sweep,\n", " primary_sweep_variable=\"Time\",\n", " domain=\"Sweep\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "aef7d54b", "metadata": {}, "outputs": [], "source": [ "time_ns, torque = solutions.get_expression_data(formula=\"real\")\n", "avg_torque = np.mean(torque)" ] }, { "cell_type": "markdown", "id": "93e263a1", "metadata": {}, "source": [ "### Export a report to a file\n", "\n", "Export 2D plot data to a CSV file." ] }, { "cell_type": "code", "execution_count": null, "id": "80bab8da", "metadata": {}, "outputs": [], "source": [ "m2d.post.export_report_to_file(\n", " output_dir=temp_folder.name, plot_name=\"TorquePlots\", extension=\".csv\"\n", ")" ] }, { "cell_type": "markdown", "id": "bab904ad", "metadata": {}, "source": [ "### Plot torque over the second quarter of the electric period\n", "\n", "Extract and plot torque values from ``ElectricPeriod/4`` to ``ElectricPeriod/2``.\n", "The electric period is retrieved from the design variables in seconds and\n", "converted to nanoseconds to match the time axis units returned by ``get_expression_data``." ] }, { "cell_type": "code", "execution_count": null, "id": "7367bc57", "metadata": {}, "outputs": [], "source": [ "ep_ns = m2d.variable_manager.design_variables[\"ElectricPeriod\"].numeric_value * 1e9\n", "mask = (time_ns >= ep_ns / 4) & (time_ns <= ep_ns / 2)" ] }, { "cell_type": "code", "execution_count": null, "id": "e1ee9142", "metadata": {}, "outputs": [], "source": [ "fig, ax = plt.subplots()\n", "ax.plot(time_ns[mask], torque[mask], marker=\"o\")\n", "ax.set_xlabel(\"Time (ns)\")\n", "ax.set_ylabel(\"Torque (N·m)\")\n", "ax.set_title(\"Torque vs Time (Quarter to Half Period)\")" ] }, { "cell_type": "markdown", "id": "64f095b1", "metadata": {}, "source": [ "Uncomment the following line to display the matplotlib plot:\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "9f2f5bd2", "metadata": {}, "source": [ "## Finish\n", "\n", "### Save the project" ] }, { "cell_type": "code", "execution_count": null, "id": "7b7ffa73", "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": "aa1a7d05", "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": "32055b9e", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }