[S0065] Create a 2D geometry of a stator with tapered slots

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. To facilitate this, it is advantageous to define dimensions, constraint values, or the variables used to calculate them as equations when creating geometry.
This script creates a 2D shape of a tapered-slot stator used in an inner-rotor motor.
Create a 2D geometry of a stator with tapered slots

Preconditions

  • Create a 1/4 model of a 24-slot stator.
  • Assume mirror symmetry about a line at 7.5 degrees, with the same geometry repeated at 15-degree intervals.
  • The number of slots is defined by an equation; while periodicity adjusts accordingly if the value is changed, the model is fixed as a 1/4 model.

Script Function

  • Register the number of slots and stator dimensions as equations.
  • Create a sketch on the XY plane and set it to editable status.
  • Create the outlines of the stator core and slot for half a slot pitch using arcs and lines and apply constraints.
  • Create a region for the slot and set its name and color.
  • Create a mirror copy and a circular pattern of the slot region to create a 1/4 model.
  • Create a region for the stator core and set its name and color.
  • Create a mirror copy and a circular pattern of the stator core region to create a 1/4 model.
# 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
Slots = 24
StatorOuterDiameter = 204
StatorInnerDiameter = 102
ToothTipThickness = 1.6
SlotWidth1 = 6.0
SlotWidth2 = 3.6
SlotDepthFromOuter = 25.5

# Equation names
EqSlots = u"SLOTS"
EqStatorOuterDiameter = u"SD1"
EqStatorInnerDiameter = u"SD2"
EqToothTipThickness = u"ST"
EqSlotWidth1 = u"SW1"
EqSlotWidth2 = u"SW2"
EqSlotDepthFromOuter = u"SW4"


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


def createStatorEquations():
    """Register equations used for the stator geometry in DesignTable."""
    designTable = geomDoc.GetDesignTable()
    equationSettings = [
        (EqSlots, Slots, 0),
        (EqStatorOuterDiameter, StatorOuterDiameter, 0),
        (EqStatorInnerDiameter, StatorInnerDiameter, 0),
        (EqToothTipThickness, ToothTipThickness, 0),
        (EqSlotWidth1, SlotWidth1, 0),
        (EqSlotWidth2, SlotWidth2, 0),
        (EqSlotDepthFromOuter, SlotDepthFromOuter, 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 property."""
    for item in itemList:
        feature.AddPropertyByReference(propertyName, createReference(item))


def createRegionFromItems(sketch, itemList):
    """Create a region on 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 at 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 direction 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 calculatePointOnCircle(radius, y):
    """Get a point on a circle centered at the origin for the specified Y coordinate as a Point object."""
    x = (radius * radius - y * y) ** 0.5
    return geomApp.CreatePoint(x, y, 0)


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


def calculatePointOnOffsetLineAndCircle(radius, offset, direction):
    """Get the intersection of a circle and a line offset clockwise from the specified direction."""
    lengthOnDirection = (radius * radius - offset * offset) ** 0.5
    x = direction.GetX() * lengthOnDirection + direction.GetY() * offset
    y = direction.GetY() * lengthOnDirection - direction.GetX() * offset
    return geomApp.CreatePoint(x, y, 0)


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))
    # 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 geometry items and set its equation."""
    constraint = sketch.CreateBiConstraint(u"angle", createReference(firstItem), createReference(secondItem))
    constraint.SetProperty(u"Angle", expression)


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 createStatorBaseShape(sketch):
    """Create the stator base geometry and constraints for half a slot pitch."""
    statorOuterRadius = StatorOuterDiameter / 2.0
    statorInnerRadius = StatorInnerDiameter / 2.0
    toothTipOuterRadius = statorInnerRadius + ToothTipThickness
    slotBottomRadius = statorOuterRadius - SlotDepthFromOuter
    halfSlotAngle = 360.0 / Slots / 2.0
    halfSlotWidth1 = SlotWidth1 / 2.0
    halfSlotWidth2 = SlotWidth2 / 2.0
    slotCenterDirection = calculateDirectionByAngle(sketch, halfSlotAngle)

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

    # Calculate the vertex positions of each boundary.
    pointInnerOnXAxis = geomApp.CreatePoint(statorInnerRadius, 0, 0)
    pointOuterOnXAxis = geomApp.CreatePoint(statorOuterRadius, 0, 0)
    pointInnerAtSlotOpening = calculatePointOnOffsetLineAndCircle(statorInnerRadius, halfSlotWidth2, slotCenterDirection)
    pointToothTipAtSlotOpening = calculatePointOnOffsetLineAndCircle(toothTipOuterRadius, halfSlotWidth2, slotCenterDirection)
    pointToothTipAtToothSide = calculatePointOnCircle(toothTipOuterRadius, halfSlotWidth1)
    pointSlotBottomAtToothSide = calculatePointOnCircle(slotBottomRadius, halfSlotWidth1)
    pointInnerAtSlotCenter = calculatePointOnRadialLine(statorInnerRadius, slotCenterDirection)
    pointToothTipAtSlotCenter = calculatePointOnRadialLine(toothTipOuterRadius, slotCenterDirection)
    pointSlotBottomAtSlotCenter = calculatePointOnRadialLine(slotBottomRadius, slotCenterDirection)
    pointOuterAtSlotCenter = calculatePointOnRadialLine(statorOuterRadius, slotCenterDirection)

    # Create arcs for the stator inner and outer diameters.
    innerArcForCore = createArc(sketch, pointInnerOnXAxis, pointInnerAtSlotOpening)
    createDiameterConstraint(sketch, innerArcForCore, EqStatorInnerDiameter)
    outerArc = createArc(sketch, pointOuterOnXAxis, pointOuterAtSlotCenter)
    createDiameterConstraint(sketch, outerArc, EqStatorOuterDiameter)

    # Create arcs for the tooth tip and slot bottom.
    toothTipArcForCore = createArc(sketch, pointToothTipAtToothSide, pointToothTipAtSlotOpening)
    toothTipArcForSlot = createArc(sketch, pointToothTipAtSlotOpening, pointToothTipAtSlotCenter)
    slotBottomArc = createArc(sketch, pointSlotBottomAtToothSide, pointSlotBottomAtSlotCenter)

    # Create the slot opening and tooth side.
    slotOpeningLine = createLine(sketch, pointInnerAtSlotOpening, pointToothTipAtSlotOpening)
    toothSideLine = createLine(sketch, pointToothTipAtToothSide, pointSlotBottomAtToothSide)
    sketch.CreateMonoConstraint(u"horizontality", createReference(toothSideLine))

    # Create the boundaries on the slot-center side.
    slotCenterOpeningLine = createLine(sketch, pointInnerAtSlotCenter, pointToothTipAtSlotCenter)
    sketch.CreateBiConstraint(u"coincident", createReference(slotCenterOpeningLine), createReference(originVertex))
    slotCenterSlotLine = createLine(sketch, pointToothTipAtSlotCenter, pointSlotBottomAtSlotCenter)
    sketch.CreateBiConstraint(u"coincident", createReference(slotCenterOpeningLine), createReference(slotCenterSlotLine))
    slotCenterOuterLine = createLine(sketch, pointSlotBottomAtSlotCenter, pointOuterAtSlotCenter)
    sketch.CreateBiConstraint(u"coincident", createReference(slotCenterSlotLine), createReference(slotCenterOuterLine))

    # Create the stator-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))

    # Constrain the arcs to be concentric and set the stator dimensions.
    for arc in [toothTipArcForCore, toothTipArcForSlot, slotBottomArc, outerArc]:
        sketch.CreateBiConstraint(u"concentricity", createReference(innerArcForCore), createReference(arc))
    createDistanceConstraint(sketch, innerArcForCore, toothTipArcForCore, EqToothTipThickness)
    createDistanceConstraint(sketch, slotBottomArc, outerArc, EqSlotDepthFromOuter)
    createDistanceConstraint(sketch, toothSideLine, radialLineOnXAxis, EqSlotWidth1, useDoubleWidth=True)
    # Define the slot-opening width by the distance to the symmetry axis over the same radial range as the opening.
    createDistanceConstraint(sketch, slotOpeningLine, slotCenterOpeningLine, EqSlotWidth2, useDoubleWidth=True)
    createAngleConstraint(sketch, radialLineOnXAxis, slotCenterOuterLine, u"360/{0}/2".format(EqSlots))

    # Use the tooth-tip outer arc as the inner-side boundary of the slot region.
    # Include the inner-diameter arc and slot-opening line only in the stator-core region.
    slotEdgeList = [
        toothTipArcForCore,
        toothTipArcForSlot,
        toothSideLine,
        slotBottomArc,
        slotCenterSlotLine,
    ]
    statorCoreEdgeList = [
        innerArcForCore,
        slotOpeningLine,
        toothTipArcForCore,
        toothSideLine,
        slotBottomArc,
        slotCenterOuterLine,
        outerArc,
        radialLineOnXAxis,
    ]
    return slotEdgeList, statorCoreEdgeList, slotCenterSlotLine, slotCenterOuterLine


def createSlotPattern(sketch, slotRegion, slotSymmetryLine):
    """Mirror-copy the slot region and circular-pattern it over the 90 deg partial model."""
    # Mirror-copy the half-slot-pitch region to create one full slot.
    slotMirror = sketch.CreateRegionMirrorCopy()
    slotMirror.SetName(u"SlotMirror1Slot")
    addItemsToReferenceList(slotMirror, u"Region", [slotRegion])
    slotMirror.SetSymmetry(createReference(slotSymmetryLine))

    # Circular-pattern the one-slot geometry for the number of slots in the 90 deg partial model.
    slotPattern = sketch.CreateRegionCircularPattern()
    slotPattern.SetName(u"SlotCircularPattern")
    addItemsToReferenceList(slotPattern, u"Region", [slotRegion])
    addItemsToReferenceList(slotPattern, u"Feature", [slotMirror])
    slotPattern.SetProperty(u"CenterType", u"DefaultOrigin")
    slotPattern.SetProperty(u"Angle", u"360/{0}".format(EqSlots))
    slotPattern.SetProperty(u"Instance", u"{0}/4".format(EqSlots))


def createStatorCorePattern(sketch, statorCoreRegion, coreSymmetryLine):
    """Mirror-copy the stator-core region and circular-pattern it over the 90 deg partial model."""
    # Mirror-copy the half-slot-pitch region to create one full slot.
    statorCoreMirror = sketch.CreateRegionMirrorCopy()
    statorCoreMirror.SetName(u"StatorCoreMirror1Slot")
    statorCoreMirror.SetMerge(True)
    addItemsToReferenceList(statorCoreMirror, u"Region", [statorCoreRegion])
    statorCoreMirror.SetProperty(u"OverlappedAreaError", True)
    statorCoreMirror.SetSymmetry(createReference(coreSymmetryLine))

    # Circular-pattern the one-slot geometry for the number of slots in the 90 deg partial model.
    statorCorePattern = sketch.CreateRegionCircularPattern()
    statorCorePattern.SetName(u"StatorCoreCircularPattern")
    statorCorePattern.SetMerge(True)
    addItemsToReferenceList(statorCorePattern, u"Region", [statorCoreRegion])
    addItemsToReferenceList(statorCorePattern, u"Feature", [statorCoreMirror])
    statorCorePattern.SetProperty(u"CenterType", u"DefaultOrigin")
    statorCorePattern.SetProperty(u"Angle", u"360/{0}".format(EqSlots))
    statorCorePattern.SetProperty(u"Instance", u"{0}/4".format(EqSlots))


def drawStator(sketch):
    """Create a 2D stator geometry with tapered slots on the sketch."""
    slotEdgeList, statorCoreEdgeList, slotSymmetryLine, coreSymmetryLine = createStatorBaseShape(sketch)

    regionOrder = 0

    # Create the slot region and set its name and color.
    createRegionFromItems(sketch, slotEdgeList)
    regionOrder += 1
    slotRegion = getRegionItemByOrder(sketch, regionOrder)
    if slotRegion.GetScriptTypeName() == u"RegionItem":
        setRegionAppearance(slotRegion, u"Slot", u"#a0a0a4")

    # Create the stator-core region and set its name and color.
    createRegionFromItems(sketch, statorCoreEdgeList)
    regionOrder += 1
    statorCoreRegion = getRegionItemByOrder(sketch, regionOrder)
    if statorCoreRegion.GetScriptTypeName() == u"RegionItem":
        setRegionAppearance(statorCoreRegion, u"StatorCore", u"lime")

    createSlotPattern(sketch, slotRegion, slotSymmetryLine)
    createStatorCorePattern(sketch, statorCoreRegion, coreSymmetryLine)


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


def main():
    """Create a 2D stator geometry with tapered slots."""
    createStatorEquations()
    assm = geomDoc.GetAssembly()
    refXYPlane = assm.GetPlaneXY()
    statorSketch = assm.CreateSketch(refXYPlane)
    drawInSketch(statorSketch)


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