[S0066] Create a 2D geometry of an I-shaped IPM outer rotor

This script creates a geometry for the geometry library included in JMAG Geometry Editor.
Creating an analysis model in JMAG Geometry Editor makes it easy to modify the dimensions of the base geometry later for use in parametric studies or optimization. If a fillet feature might require adjustment, creating it as a region fillet makes it easier to modify its dimensions later.
This script creates the 2D shape of an I-shaped IPM outer rotor.
Create a 2D geometry of an I-shaped IPM outer rotor

Preconditions

  • Create a 1/4 model of an 8-pole rotor.
  • Assume mirror symmetry about a line at 22.5 degrees, with the same geometry repeated at 45-degree intervals.
  • The number of poles is defined by an equation; while periodicity updates automatically if the value is changed, the model is fixed as a 1/4 model.
    Dimensions are also fixed and do not scale according to the number of poles.

Script Function

  • Register the number of poles and rotor dimensions as equations.
  • Create a sketch on the XY plane and set it to editable status.
  • Create the outlines of the rotor core, magnet, and slit for half a pole pitch using arcs and lines and apply constraints.
  • Create a region for the rotor core and set its name and color.
  • Create a region for the magnet and set its name and color.
  • Apply fillets to the slit corners of the rotor core region.
  • Create a mirror copy and a circular pattern of the rotor core region to create a 1/4 model.
  • Create a mirror copy and a circular pattern of the magnet region to create a 1/4 model.
    The periodic angle for the circular pattern is calculated based on the number of slots.
    The number of instances in the circular pattern is set to 1/4 of the number of slots.
# Copyright (c) 2026 JSOL CORPORATION
#
# This script is released under the MIT License.
# See the full license text at:
# https://www.jmag-international.com/scriptlibrary/jmag_script_library_mit/

app = designer.GetApplication()
geomApp = app.CreateGeometryEditor()
geomDoc = geomApp.GetDocument()

# Dimensional parameters
Poles = 8
MagnetClearance = 0.6
SlitBridgeThickness = 0.6
RotorOuterDiameter = 125
RotorInnerDiameter = 102
SlitCornerRadius = 0.5
MagnetThickness = 2.3
MagnetWidth = 24.7
SlitLength1 = 0.5
SlitLength2 = 1.6
SlitAngle1 = 120
SlitAngle2 = 120

# Equation names
EqPoles = u"POLES"
EqMagnetClearance = u"DMAG"
EqSlitBridgeThickness = u"DSLIT"
EqRotorOuterDiameter = u"RD1"
EqRotorInnerDiameter = u"RD2"
EqSlitCornerRadius = u"RF"
EqMagnetThickness = u"RT1"
EqMagnetWidth = u"RW1"
EqSlitLength1 = u"RW2"
EqSlitLength2 = u"RW3"
EqSlitAngle1 = u"RW4"
EqSlitAngle2 = u"RW5"


def setupEquation(equation, expression, equationType):
    """Configure the type and expression of an equation in DesignTable."""
    # The argument of SetType
    # 0: Value
    # 1: Expression
    equation.SetType(equationType)
    equation.SetExpression(str(expression))


def createRotorEquations():
    """Register the equations used for the rotor geometry in DesignTable."""
    designTable = geomDoc.GetDesignTable()
    equationSettings = [
        (EqPoles, Poles, 0),
        (EqMagnetClearance, MagnetClearance, 0),
        (EqSlitBridgeThickness, SlitBridgeThickness, 0),
        (EqRotorOuterDiameter, RotorOuterDiameter, 0),
        (EqRotorInnerDiameter, RotorInnerDiameter, 0),
        (EqSlitCornerRadius, SlitCornerRadius, 0),
        (EqMagnetThickness, MagnetThickness, 0),
        (EqMagnetWidth, MagnetWidth, 0),
        (EqSlitLength1, SlitLength1, 0),
        (EqSlitLength2, SlitLength2, 0),
        (EqSlitAngle1, SlitAngle1, 0),
        (EqSlitAngle2, SlitAngle2, 0),
    ]
    designTable.EditStart()
    for equationName, expression, equationType in equationSettings:
        designTable.AddEquation(equationName)
        equation = designTable.GetEquation(equationName)
        setupEquation(equation, expression, equationType)
    designTable.EditEnd()


def createReference(item):
    """Create a ReferenceObject from a geometry item."""
    return geomDoc.CreateReferenceFromItem(item)


def addItemsToReferenceList(feature, propertyName, itemList):
    """Add geometry items to a stringlist-type property."""
    for item in itemList:
        feature.AddPropertyByReference(propertyName, createReference(item))


def createRegionFromItems(sketch, itemList):
    """Create regions in the sketch from all items in itemList."""
    selection = geomDoc.GetSelection()
    selection.Clear()
    for item in itemList:
        selection.Add(item)
    sketch.CreateRegions()
    selection.Clear()


def getRegionItemByOrder(sketch, createdOrder):
    """Get the region object in the specified creation order."""
    currentCount = 0
    for i in range(sketch.NumItems()):
        item = sketch.GetItem(i)
        if item.GetScriptTypeName() == u"RegionItem":
            if currentCount == createdOrder - 1:
                return item
            currentCount += 1
    return sketch


def calculateDirectionByAngle(sketch, angle):
    """Get a unit vector in the specified angle from the X-axis as a Point object."""
    dummyLine = sketch.CreateLineByLengthAngle(0, 0, 1, angle)
    endVertex = dummyLine.GetEndVertex()
    direction = geomApp.CreatePoint(endVertex.GetX(), endVertex.GetY(), 0)
    selection = geomDoc.GetSelection()
    selection.Clear()
    selection.Add(dummyLine)
    selection.Delete()
    selection.Clear()
    return direction


def addPointAndVector(point, vector, length):
    """Get a point moved from the specified point by a specified distance along a vector as a Point object."""
    x = point.GetX() + vector.GetX() * length
    y = point.GetY() + vector.GetY() * length
    return geomApp.CreatePoint(x, y, 0)


def calculatePointOnRadialLine(radius, direction):
    """Get the intersection of an origin-centered circle and a line through the origin in the specified direction as a Point object."""
    x = radius * direction.GetX()
    y = radius * direction.GetY()
    return geomApp.CreatePoint(x, y, 0)


def calculateRayCircleIntersection(startPoint, direction, radius):
    """Get the nearer intersection of a ray from the specified point and an origin-centered circle as a Point object."""
    dot = startPoint.GetX() * direction.GetX() + startPoint.GetY() * direction.GetY()
    squaredRadiusFromOrigin = startPoint.GetX() ** 2 + startPoint.GetY() ** 2
    discriminant = dot ** 2 - (squaredRadiusFromOrigin - radius ** 2)
    root = discriminant ** 0.5
    distance1 = -dot - root
    distance2 = -dot + root
    positiveDistances = [distance for distance in [distance1, distance2] if distance >= 0]
    distance = min(positiveDistances)
    return addPointAndVector(startPoint, direction, distance)


def createArc(sketch, startPoint, endPoint):
    """Create an arc centered at the origin between the specified start and end points."""
    return sketch.CreateArc(0, 0, startPoint.GetX(), startPoint.GetY(), endPoint.GetX(), endPoint.GetY())


def createLine(sketch, startPoint, endPoint):
    """Create a line between the specified start and end points."""
    return sketch.CreateLine(startPoint.GetX(), startPoint.GetY(), endPoint.GetX(), endPoint.GetY())


def createDiameterConstraint(sketch, arc, expression):
    """Create a diameter constraint for an arc and set its equation."""
    constraint = sketch.CreateMonoConstraint(u"radius", createReference(arc))
    # The argument of SetType
    # 0: Radius
    # 1: Diameter
    constraint.SetType(1)
    constraint.SetProperty(u"Diameter", expression)


def createDistanceConstraint(sketch, firstItem, secondItem, expression, useDoubleWidth=False):
    """Create a distance constraint between two geometry items and set its equation."""
    constraint = sketch.CreateBiConstraint(u"distance", createReference(firstItem), createReference(secondItem))
    constraint.SetProperty(u"Distance", expression)
    if useDoubleWidth:
        constraint.SetProperty(u"UseDoubleWidth", True)


def createAngleConstraint(sketch, firstItem, secondItem, expression):
    """Create an angle constraint between two lines and set its equation."""
    constraint = sketch.CreateBiConstraint(u"angle", createReference(firstItem), createReference(secondItem))
    constraint.SetProperty(u"Angle", expression)


def createSlitCornerFillet(sketch, slitBridgeArc, slitOuterReturnLine):
    """Create a fillet at the connection between the slit and bridge arc."""
    selection = geomDoc.GetSelection()
    selection.Clear()
    selection.Add(slitBridgeArc)
    selection.Add(slitOuterReturnLine)
    geomDoc.GetSketchManager().CreateFillet(SlitCornerRadius)
    selection.Clear()
    filletArc = sketch.GetItem(sketch.NumItems() - 1)
    radiusConstraint = sketch.CreateMonoConstraint(u"radius", createReference(filletArc))
    radiusConstraint.SetProperty(u"Radius", EqSlitCornerRadius)
    sketch.CreateBiConstraint(u"tangency", createReference(filletArc), createReference(slitBridgeArc))
    sketch.CreateBiConstraint(u"tangency", createReference(filletArc), createReference(slitOuterReturnLine))
    return filletArc


def setRegionAppearance(region, name, color):
    """Set the name and display color of a region."""
    region.SetName(name)
    region.SetProperty(u"Color", color)
    region.SetProperty(u"UseParentColor", 0)


def createRotorBaseShape(sketch):
    """Create the base geometry and constraints for a half-pole pitch of the I-shaped outer rotor IPM motor."""
    rotorOuterRadius = RotorOuterDiameter / 2.0
    rotorInnerRadius = RotorInnerDiameter / 2.0
    slitBridgeRadius = rotorInnerRadius + SlitBridgeThickness
    magnetInnerPosition = rotorInnerRadius + MagnetClearance
    magnetOuterPosition = magnetInnerPosition + MagnetThickness
    halfMagnetWidth = MagnetWidth / 2.0
    halfPoleAngle = 360.0 / Poles / 2.0

    radialDirection = calculateDirectionByAngle(sketch, halfPoleAngle)
    tangentDirection = calculateDirectionByAngle(sketch, halfPoleAngle - 90.0)
    slitInnerReturnDirection = calculateDirectionByAngle(sketch, halfPoleAngle - 90.0 - SlitAngle1)
    # Set the direction vector from the outer slit corner toward the bridge circle.
    slitOuterToBridgeDirection = calculateDirectionByAngle(sketch, halfPoleAngle - 90.0 - (180.0 - SlitAngle2))

    # Create and fix the origin.
    originVertex = sketch.CreateVertex(0, 0)
    sketch.CreateMonoConstraint(u"fixture", createReference(originVertex))

    # Calculate the vertex positions of each contour.
    pointInnerOnXAxis = geomApp.CreatePoint(rotorInnerRadius, 0, 0)
    pointOuterOnXAxis = geomApp.CreatePoint(rotorOuterRadius, 0, 0)
    pointInnerOnSymmetry = calculatePointOnRadialLine(rotorInnerRadius, radialDirection)
    pointOuterOnSymmetry = calculatePointOnRadialLine(rotorOuterRadius, radialDirection)
    pointMagnetInnerOnSymmetry = calculatePointOnRadialLine(magnetInnerPosition, radialDirection)
    pointMagnetOuterOnSymmetry = calculatePointOnRadialLine(magnetOuterPosition, radialDirection)
    pointMagnetInnerEnd = addPointAndVector(pointMagnetInnerOnSymmetry, tangentDirection, halfMagnetWidth)
    pointMagnetOuterEnd = addPointAndVector(pointMagnetOuterOnSymmetry, tangentDirection, halfMagnetWidth)
    pointSlitInnerCorner = addPointAndVector(pointMagnetInnerEnd, tangentDirection, SlitLength1)
    pointSlitOuterCorner = addPointAndVector(pointMagnetOuterEnd, tangentDirection, SlitLength2)
    pointSlitInnerOnBridge = calculateRayCircleIntersection(pointSlitInnerCorner, slitInnerReturnDirection, slitBridgeRadius)
    pointSlitOuterOnBridge = calculateRayCircleIntersection(pointSlitOuterCorner, slitOuterToBridgeDirection, slitBridgeRadius)

    # Create the rotor inner and outer arcs.
    rotorInnerArc = createArc(sketch, pointInnerOnXAxis, pointInnerOnSymmetry)
    createDiameterConstraint(sketch, rotorInnerArc, EqRotorInnerDiameter)
    rotorOuterArc = createArc(sketch, pointOuterOnXAxis, pointOuterOnSymmetry)
    createDiameterConstraint(sketch, rotorOuterArc, EqRotorOuterDiameter)

    # Create the rotor core boundary on the X-axis.
    radialLineOnXAxis = createLine(sketch, pointInnerOnXAxis, pointOuterOnXAxis)
    sketch.CreateMonoConstraint(u"horizontality", createReference(radialLineOnXAxis))
    sketch.CreateBiConstraint(u"coincident", createReference(radialLineOnXAxis), createReference(originVertex))

    # Create the rotor core and magnet boundaries on the pole-center side.
    innerSymmetryLine = createLine(sketch, pointInnerOnSymmetry, pointMagnetInnerOnSymmetry)
    sketch.CreateBiConstraint(u"coincident", createReference(innerSymmetryLine), createReference(originVertex))
    magnetSymmetryLine = createLine(sketch, pointMagnetInnerOnSymmetry, pointMagnetOuterOnSymmetry)
    sketch.CreateBiConstraint(u"coincident", createReference(magnetSymmetryLine), createReference(originVertex))
    coreSymmetryLine = createLine(sketch, pointMagnetOuterOnSymmetry, pointOuterOnSymmetry)
    sketch.CreateBiConstraint(u"coincident", createReference(coreSymmetryLine), createReference(originVertex))
    createAngleConstraint(sketch, radialLineOnXAxis, coreSymmetryLine, u"360/{0}/2".format(EqPoles))

    # Create the magnet outline.
    magnetInnerEdge = createLine(sketch, pointMagnetInnerOnSymmetry, pointMagnetInnerEnd)
    sketch.CreateBiConstraint(u"perpendicularity", createReference(magnetInnerEdge), createReference(magnetSymmetryLine))
    magnetOuterEdge = createLine(sketch, pointMagnetOuterOnSymmetry, pointMagnetOuterEnd)
    magnetEndLine = createLine(sketch, pointMagnetInnerEnd, pointMagnetOuterEnd)

    # Create the slit outline from the magnet end to the bridge.
    slitInnerExtensionLine = createLine(sketch, pointMagnetInnerEnd, pointSlitInnerCorner)
    sketch.CreateBiConstraint(u"coincident", createReference(slitInnerExtensionLine), createReference(magnetInnerEdge))
    slitInnerReturnLine = createLine(sketch, pointSlitInnerCorner, pointSlitInnerOnBridge)
    slitOuterExtensionLine = createLine(sketch, pointMagnetOuterEnd, pointSlitOuterCorner)
    sketch.CreateBiConstraint(u"coincident", createReference(slitOuterExtensionLine), createReference(magnetOuterEdge))
    slitOuterReturnLine = createLine(sketch, pointSlitOuterCorner, pointSlitOuterOnBridge)
    slitBridgeArc = createArc(sketch, pointSlitOuterOnBridge, pointSlitInnerOnBridge)

    # Constrain the arcs concentrically and set the bridge thickness.
    sketch.CreateBiConstraint(u"concentricity", createReference(rotorInnerArc), createReference(rotorOuterArc))
    sketch.CreateBiConstraint(u"concentricity", createReference(rotorInnerArc), createReference(slitBridgeArc))
    createDistanceConstraint(sketch, rotorInnerArc, slitBridgeArc, EqSlitBridgeThickness)

    # Set the magnet position and dimensions.
    createDistanceConstraint(sketch, rotorInnerArc.GetEndVertex(), magnetSymmetryLine.GetStartVertex(), EqMagnetClearance)
    createDistanceConstraint(sketch, magnetInnerEdge, magnetOuterEdge, EqMagnetThickness)
    createDistanceConstraint(sketch, magnetEndLine, magnetSymmetryLine, EqMagnetWidth, useDoubleWidth=True)

    # Set the slit lengths and angles.
    createDistanceConstraint(sketch, slitInnerExtensionLine.GetStartVertex(), slitInnerExtensionLine.GetEndVertex(), EqSlitLength1)
    createDistanceConstraint(sketch, slitOuterExtensionLine.GetStartVertex(), slitOuterExtensionLine.GetEndVertex(), EqSlitLength2)
    createAngleConstraint(sketch, slitInnerReturnLine, slitInnerExtensionLine, EqSlitAngle1)
    createAngleConstraint(sketch, slitOuterExtensionLine, slitOuterReturnLine, EqSlitAngle2)

    # Create a fillet at the connection between the slit and bridge arc.
    filletArc = createSlitCornerFillet(sketch, slitBridgeArc, slitOuterReturnLine)

    # Collect the contours that form the rotor core and magnet regions.
    rotorCoreEdgeList = [
        radialLineOnXAxis,
        rotorOuterArc,
        coreSymmetryLine,
        magnetOuterEdge,
        slitOuterExtensionLine,
        slitOuterReturnLine,
        filletArc,
        slitBridgeArc,
        slitInnerReturnLine,
        slitInnerExtensionLine,
        magnetInnerEdge,
        innerSymmetryLine,
        rotorInnerArc,
    ]
    magnetEdgeList = [
        magnetSymmetryLine,
        magnetOuterEdge,
        magnetEndLine,
        magnetInnerEdge,
    ]
    # Get the three target vertices to apply fillets to the slit corners.
    slitRegionFilletVertexList = [
        slitInnerExtensionLine.GetEndVertex(),
        slitInnerReturnLine.GetEndVertex(),
        slitOuterExtensionLine.GetEndVertex(),
    ]
    return rotorCoreEdgeList, magnetEdgeList, coreSymmetryLine, magnetSymmetryLine, slitRegionFilletVertexList


def createSlitRegionFillet(sketch, targetVertexList):
    """Set fillets at the three slit corners of the rotor core region."""
    regionFillet = sketch.CreateRegionFillet()
    regionFillet.SetName(u"SlitCornerRegionFillet")
    addItemsToReferenceList(regionFillet, u"Target", targetVertexList)
    regionFillet.SetProperty(u"Radius", EqSlitCornerRadius)


def createRotorCorePattern(sketch, rotorCoreRegion, coreSymmetryLine):
    """Mirror-copy the rotor core region and circularly pattern it to create a 90deg partial model."""
    # Mirror-copy the half-pole-pitch region to create one pole.
    coreMirror = sketch.CreateRegionMirrorCopy()
    coreMirror.SetName(u"CoreMirror1Pole")
    coreMirror.SetMerge(True)
    addItemsToReferenceList(coreMirror, u"Region", [rotorCoreRegion])
    coreMirror.SetProperty(u"OverlappedAreaError", True)
    coreMirror.SetSymmetry(createReference(coreSymmetryLine))

    # Circularly pattern the one-pole geometry for the number of poles in the 90deg partial model.
    corePattern = sketch.CreateRegionCircularPattern()
    corePattern.SetName(u"CoreCircularPattern")
    corePattern.SetMerge(True)
    addItemsToReferenceList(corePattern, u"Region", [rotorCoreRegion])
    addItemsToReferenceList(corePattern, u"Feature", [coreMirror])
    corePattern.SetProperty(u"CenterType", u"DefaultOrigin")
    corePattern.SetProperty(u"Angle", u"360/{0}".format(EqPoles))
    corePattern.SetProperty(u"Instance", u"{0}/4".format(EqPoles))


def createMagnetPattern(sketch, magnetRegion, magnetSymmetryLine):
    """Mirror-copy the magnet region and circularly pattern it to create a 90deg partial model."""
    # Mirror-copy the half-pole-pitch region to create the magnet geometry for one pole.
    magnetMirror = sketch.CreateRegionMirrorCopy()
    magnetMirror.SetName(u"MagnetMirror1Pole")
    magnetMirror.SetMerge(True)
    addItemsToReferenceList(magnetMirror, u"Region", [magnetRegion])
    magnetMirror.SetSymmetry(createReference(magnetSymmetryLine))

    # Circularly pattern the one-pole magnet geometry for the number of poles in the 90deg partial model.
    magnetPattern = sketch.CreateRegionCircularPattern()
    magnetPattern.SetName(u"MagnetCircularPattern")
    addItemsToReferenceList(magnetPattern, u"Region", [magnetRegion])
    addItemsToReferenceList(magnetPattern, u"Feature", [magnetMirror])
    magnetPattern.SetProperty(u"CenterType", u"DefaultOrigin")
    magnetPattern.SetProperty(u"Angle", u"360/{0}".format(EqPoles))
    magnetPattern.SetProperty(u"Instance", u"{0}/4".format(EqPoles))


def drawRotor(sketch):
    """Create the 2D geometry of the I-shaped outer rotor IPM motor in the sketch."""
    rotorCoreEdgeList, magnetEdgeList, coreSymmetryLine, magnetSymmetryLine, slitRegionFilletVertexList = createRotorBaseShape(sketch)

    regionOrder = 0

    # Create the rotor core region and set its name and display color.
    createRegionFromItems(sketch, rotorCoreEdgeList)
    regionOrder += 1
    rotorCoreRegion = getRegionItemByOrder(sketch, regionOrder)
    if rotorCoreRegion.GetScriptTypeName() == u"RegionItem":
        setRegionAppearance(rotorCoreRegion, u"Core", u"gray")

    # Create the magnet region and set its name and display color.
    createRegionFromItems(sketch, magnetEdgeList)
    regionOrder += 1
    magnetRegion = getRegionItemByOrder(sketch, regionOrder)
    if magnetRegion.GetScriptTypeName() == u"RegionItem":
        setRegionAppearance(magnetRegion, u"Magnet", u"red")

    createSlitRegionFillet(sketch, slitRegionFilletVertexList)
    createRotorCorePattern(sketch, rotorCoreRegion, coreSymmetryLine)
    createMagnetPattern(sketch, magnetRegion, magnetSymmetryLine)


def drawInSketch(sketch):
    """Open the sketch in editable status and create the geometry."""
    sketch.OpenSketch()
    drawRotor(sketch)
    sketch.CloseSketch()


def main():
    """Create the 2D geometry of the I-shaped outer rotor IPM motor."""
    createRotorEquations()
    assm = geomDoc.GetAssembly()
    refXYPlane = assm.GetPlaneXY()
    rotorSketch = assm.CreateSketch(refXYPlane)
    drawInSketch(rotorSketch)
    rotorSketch.SetProperty(u"Name", u"Rotor")


main()

Download Python source code

How to use script file

Use the JMAG Script Library after reading and agreeing to the following terms of use.

Search Filter
  • All Categories

An engineer's diary
JMAG-Express Online