Example #1
0
def get_curve_circle_points(x1, xd1, x2, xd2, r1, rd1, r2, rd2, xi, dmag, side, elementsCountAround):
    '''
    :param dmag: Magnitude of derivative on curve.
    :param side: Vector in side direction of first node around.
    Need not be unit or exactly normal to curve at xi.
    :return: x[], d1[] around, d2[] along
    '''
    cx = interpolateCubicHermite(x1, xd1, x2, xd2, xi)
    cxd = interpolateCubicHermiteDerivative(x1, xd1, x2, xd2, xi)
    mag_cxd = magnitude(cxd)
    cxd2 = interpolateCubicHermiteSecondDerivative(x1, xd1, x2, xd2, xi)
    mag_cxd2 = magnitude(cxd2)
    r = interpolateCubicHermite([ r1 ], [ rd1 ], [ r2 ], [ rd2 ], xi)[0]
    rd = interpolateCubicHermiteDerivative([ r1 ], [ rd1 ], [ r2 ], [ rd2 ], xi)[0]
    axis1 = normalize(cxd)
    axis3 = normalize(cross(axis1, side))
    axis2 = cross(axis3, axis1)
    x, d1 = createCirclePoints(cx, mult(axis2, r), mult(axis3, r), elementsCountAround)
    curvatureVector = mult(cxd2, 1.0/(mag_cxd*mag_cxd))
    d2 = []
    radialGrowth = rd/(mag_cxd*r)
    for e in range(elementsCountAround):
        radialVector = sub(x[e], cx)
        dmagFinal = dmag*(1.0 - dot(radialVector, curvatureVector))
        # add curvature and radius change components:
        d2.append(add(mult(cxd, dmagFinal/mag_cxd), mult(radialVector, dmagFinal*radialGrowth)))
    return x, d1, d2
Example #2
0
def interpolateNodesCubicHermite(cache, coordinates, xi, normal_scale, \
        node1, derivative1, scale1, cross_derivative1, cross_scale1, \
        node2, derivative2, scale2, cross_derivative2, cross_scale2):
    """
    Interpolates position and first derivative with cubic Hermite basis.
    Interpolates cross derivative linearly.
    :param cache: Field cache to evaluate in.
    :param coordinates: Coordinates field.
    :param xi: Element coordinate to interpolate at.
    :param normal_scale: Magnitude of normal derivative to return.
    :param node1, node2: Start and end nodes.
    :param derivative1, derivative2: Node value label for derivatives.
    :param scale1, scale2: Real value scaling derivatives, to reverse if needed.
    :param cross_derivative1, cross_derivative2: Node value label for cross derivatives.
    :param cross_scale1, cross_scale2: Real value scaling cross_derivatives, to reverse if needed.
    :return: x, dx_ds, dx_ds_cross, dx_ds_normal
    """
    cache.setNode(node1)
    result, v1 = coordinates.getNodeParameters(cache, -1,
                                               Node.VALUE_LABEL_VALUE, 1, 3)
    result, d1 = coordinates.getNodeParameters(cache, -1, derivative1, 1, 3)
    result, d1c = coordinates.getNodeParameters(cache, -1, cross_derivative1,
                                                1, 3)
    d1 = [scale1 * d for d in d1]
    d1c = [cross_scale1 * d for d in d1c]
    cache.setNode(node2)
    result, v2 = coordinates.getNodeParameters(cache, -1,
                                               Node.VALUE_LABEL_VALUE, 1, 3)
    result, d2 = coordinates.getNodeParameters(cache, -1, derivative2, 1, 3)
    result, d2c = coordinates.getNodeParameters(cache, -1, cross_derivative2,
                                                1, 3)
    d2 = [scale2 * d for d in d2]
    d2c = [cross_scale2 * d for d in d2c]

    arcLength = interp.computeCubicHermiteArcLength(v1, d1, v2, d2, True)
    mag = arcLength / vector.magnitude(d1)
    d1 = [mag * d for d in d1]
    mag = arcLength / vector.magnitude(d2)
    d2 = [mag * d for d in d2]

    xr = 1.0 - xi
    x = interp.interpolateCubicHermite(v1, d1, v2, d2, xi)
    dx_ds = interp.interpolateCubicHermiteDerivative(v1, d1, v2, d2, xi)
    scale = min(xi, xr)
    dx_ds = [scale * d for d in dx_ds]
    dx_ds_cross = [(xr * d1c[c] + xi * d2c[c]) for c in range(3)]

    radialVector = vector.normalise(vector.crossproduct3(dx_ds_cross, dx_ds))
    dx_ds_normal = [normal_scale * d for d in radialVector]

    return x, dx_ds, dx_ds_cross, dx_ds_normal
Example #3
0
def make_tube_bifurcation_points(paCentre, pax, pad2, c1Centre, c1x, c1d2,
                                 c2Centre, c2x, c2d2):
    '''
    Gets first ring of coordinates and derivatives between parent pa and
    children c1, c2, and over the crotch between c1 and c2.
    :return rox, rod1, rod2, cox, cod1, cod2
    '''
    paCount = len(pax)
    c1Count = len(c1x)
    c2Count = len(c2x)
    pac1Count, pac2Count, c1c2Count = get_tube_bifurcation_connection_elements_counts(
        paCount, c1Count, c2Count)
    # convert to number of nodes, includes both 6-way points
    pac1NodeCount = pac1Count + 1
    pac2NodeCount = pac2Count + 1
    c1c2NodeCount = c1c2Count + 1
    paStartIndex = 0
    c1StartIndex = 0
    c2StartIndex = 0
    pac1x = [None] * pac1NodeCount
    pac1d1 = [None] * pac1NodeCount
    pac1d2 = [None] * pac1NodeCount
    for n in range(pac1NodeCount):
        pan = (paStartIndex + n) % paCount
        c1n = (c1StartIndex + n) % c1Count
        x1, d1, x2, d2 = pax[pan], mult(pad2[pan],
                                        2.0), c1x[c1n], mult(c1d2[c1n], 2.0)
        pac1x[n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5)
        pac1d1[n] = [0.0, 0.0, 0.0]
        pac1d2[n] = mult(
            interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5)
    paStartIndex2 = paStartIndex + pac1Count
    c1StartIndex2 = c1StartIndex + pac1Count
    c2StartIndex2 = c2StartIndex + c1c2Count
    pac2x = [None] * pac2NodeCount
    pac2d1 = [None] * pac2NodeCount
    pac2d2 = [None] * pac2NodeCount
    for n in range(pac2NodeCount):
        pan = (paStartIndex2 + n) % paCount
        c2n = (c2StartIndex2 + n) % c2Count
        x1, d1, x2, d2 = pax[pan], mult(pad2[pan],
                                        2.0), c2x[c2n], mult(c2d2[c2n], 2.0)
        pac2x[n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5)
        pac2d1[n] = [0.0, 0.0, 0.0]
        pac2d2[n] = mult(
            interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5)
    c1c2x = [None] * c1c2NodeCount
    c1c2d1 = [None] * c1c2NodeCount
    c1c2d2 = [None] * c1c2NodeCount
    for n in range(c1c2NodeCount):
        c1n = (c1StartIndex2 + n) % c1Count
        c2n = (c2StartIndex2 - n) % c2Count  # note: reversed
        x1, d1, x2, d2 = c2x[c2n], mult(c2d2[c2n],
                                        -2.0), c1x[c1n], mult(c1d2[c1n], 2.0)
        c1c2x[n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5)
        c1c2d1[n] = [0.0, 0.0, 0.0]
        c1c2d2[n] = mult(
            interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5)
    # get hex triple points
    hex1, hex1d1, hex1d2 = get_bifurcation_triple_point(
        pax[paStartIndex], mult(pad2[paStartIndex], -1.0), c1x[c1StartIndex],
        c1d2[c1StartIndex], c2x[c1StartIndex], c2d2[c2StartIndex])
    hex2, hex2d1, hex2d2 = get_bifurcation_triple_point(
        pax[paStartIndex2], mult(pad2[paStartIndex2],
                                 -1.0), c2x[c2StartIndex2],
        c2d2[c2StartIndex2], c1x[c1StartIndex2], c1d2[c1StartIndex2])
    # smooth around loops through hex points to get d1
    loop1x = [hex2] + pac2x[1:-1] + [hex1]
    loop1d1 = [[-d for d in hex2d2]] + pac2d1[1:-1] + [hex1d1]
    loop2x = [hex1] + pac1x[1:-1] + [hex2]
    loop2d1 = [[-d for d in hex1d2]] + pac1d1[1:-1] + [hex2d1]
    loop1d1 = smoothCubicHermiteDerivativesLine(
        loop1x,
        loop1d1,
        fixStartDirection=True,
        fixEndDirection=True,
        magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN)
    loop2d1 = smoothCubicHermiteDerivativesLine(
        loop2x,
        loop2d1,
        fixStartDirection=True,
        fixEndDirection=True,
        magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN)
    # smooth over "crotch" between c1 and c2
    crotchx = [hex2] + c1c2x[1:-1] + [hex1]
    crotchd1 = [add(hex2d1, hex2d2)] + c1c2d1[1:-1] + [[
        (-hex1d1[c] - hex1d2[c]) for c in range(3)
    ]]
    crotchd1 = smoothCubicHermiteDerivativesLine(
        crotchx,
        crotchd1,
        fixStartDerivative=True,
        fixEndDerivative=True,
        magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN)
    rox = [hex1] + pac1x[1:-1] + [hex2] + pac2x[1:-1]
    rod1 = [loop1d1[-1]] + loop2d1[1:] + loop1d1[1:-1]
    rod2 = [[-d for d in loop2d1[0]]
            ] + pac1d2[1:-1] + [[-d for d in loop1d1[0]]] + pac2d2[1:-1]
    cox = crotchx[1:-1]
    cod1 = crotchd1[1:-1]
    cod2 = c1c2d2[1:-1]
    return rox, rod1, rod2, cox, cod1, cod2, paStartIndex, c1StartIndex, c2StartIndex
    def generateBaseMesh(cls, region, options):
        """
        :param region: Zinc region to define model in. Must be empty.
        :param options: Dict containing options. See getDefaultOptions().
        :return: [] empty list of AnnotationGroup
        """
        coordinateDimensions = options['Coordinate dimensions']
        elementsCount1 = options['Number of elements 1']
        elementsCount2 = options['Number of elements 2']
        elementsCountThroughWall = options['Number of elements through wall']
        elementsCountAround = 2*(elementsCount1 + elementsCount2)
        holeRadius = options['Hole diameter']*0.5
        useCrossDerivatives = options['Use cross derivatives']

        fm = region.getFieldmodule()
        fm.beginChange()
        coordinates = findOrCreateFieldCoordinates(fm, components_count=coordinateDimensions)

        nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
        nodetemplate = nodes.createNodetemplate()
        nodetemplate.defineField(coordinates)
        nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1)
        nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1)
        nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1)
        if useCrossDerivatives:
            nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1)

        mesh = fm.findMeshByDimension(2)
        bicubicHermiteBasis = fm.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE)
        eft = mesh.createElementfieldtemplate(bicubicHermiteBasis)
        if not useCrossDerivatives:
            for n in range(4):
                eft.setFunctionNumberOfTerms(n*4 + 4, 0)

        # note I'm cheating here by using element-based scale factors
        # i.e. not shared by neighbouring elements
        eftOuter1 = mesh.createElementfieldtemplate(bicubicHermiteBasis)
        eftOuter2 = mesh.createElementfieldtemplate(bicubicHermiteBasis)
        i = 0
        for eftOuter in [ eftOuter1, eftOuter2 ]:
            i += 1
            eftOuter.setNumberOfLocalScaleFactors(10)
            eft.setScaleFactorType(1, Elementfieldtemplate.SCALE_FACTOR_TYPE_GLOBAL_GENERAL)
            # GRC: allow scale factor identifier for global -1.0 to be prescribed
            eft.setScaleFactorIdentifier(1, 1)
            # Global scale factor 4.0 to subtract lateral derivative term from cross derivative to fix edges
            eft.setScaleFactorType(2, Elementfieldtemplate.SCALE_FACTOR_TYPE_GLOBAL_GENERAL)
            eft.setScaleFactorIdentifier(2, 2)
            nonCrossDerivativesNodes = [0, 1] if useCrossDerivatives else range(4)
            for n in nonCrossDerivativesNodes:
                eftOuter.setFunctionNumberOfTerms(n*4 + 4, 0)
            # nodes 1,2: general map dxi1, dsxi2 from ds1, ds2
            for n in [0, 1]:
                ln = n + 1
                sfo = (n % 2)*4 + 2
                eftOuter.setFunctionNumberOfTerms(n*4 + 2, 2)
                eftOuter.setTermNodeParameter(n*4 + 2, 1, ln, Node.VALUE_LABEL_D_DS1, 1)
                eftOuter.setTermScaling(n*4 + 2, 1, [1 + sfo])
                eftOuter.setTermNodeParameter(n*4 + 2, 2, ln, Node.VALUE_LABEL_D_DS2, 1)
                eftOuter.setTermScaling(n*4 + 2, 2, [2 + sfo])
                eftOuter.setFunctionNumberOfTerms(n*4 + 3, 2)
                eftOuter.setTermNodeParameter(n*4 + 3, 1, ln, Node.VALUE_LABEL_D_DS1, 1)
                eftOuter.setTermScaling(n*4 + 3, 1, [3 + sfo])
                eftOuter.setTermNodeParameter(n*4 + 3, 2, ln, Node.VALUE_LABEL_D_DS2, 1)
                eftOuter.setTermScaling(n*4 + 3, 2, [4 + sfo])
                # map d2_dxi1dxi2 to subtract corner angle terms to fix edge continuity
                eftOuter.setFunctionNumberOfTerms(n*4 + 4, 1)
                if i == 1:
                    eftOuter.setTermNodeParameter(n*4 + 4, 1, ln, Node.VALUE_LABEL_D_DS1, 1)
                    if (n % 2) == 0:
                        eftOuter.setTermScaling(n*4 + 4, 1, [1, 2, 3 + sfo])
                    else:
                        eftOuter.setTermScaling(n*4 + 4, 1, [2, 3 + sfo])
                else:
                    eftOuter.setTermNodeParameter(n*4 + 4, 1, ln, Node.VALUE_LABEL_D_DS2, 1)
                    if (n % 2) == 0:
                        eftOuter.setTermScaling(n*4 + 4, 1, [1, 2, 4 + sfo])
                    else:
                        eftOuter.setTermScaling(n*4 + 4, 1, [2, 4 + sfo])

        elementtemplate = mesh.createElementtemplate()
        elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE)
        result = elementtemplate.defineField(coordinates, -1, eft)

        elementtemplateOuter1 = mesh.createElementtemplate()
        elementtemplateOuter1.setElementShapeType(Element.SHAPE_TYPE_SQUARE)
        result = elementtemplateOuter1.defineField(coordinates, -1, eftOuter1)
        elementtemplateOuter2 = mesh.createElementtemplate()
        elementtemplateOuter2.setElementShapeType(Element.SHAPE_TYPE_SQUARE)
        result = elementtemplateOuter2.defineField(coordinates, -1, eftOuter2)

        cache = fm.createFieldcache()

        # create nodes
        radiansPerElementAround = 2.0*math.pi/elementsCountAround
        wallThicknessMin = (0.5 - holeRadius)
        wallThicknessMax = math.sqrt(0.5) - holeRadius
        wallThicknessPerElement = wallThicknessMin/elementsCountThroughWall
        radius = holeRadius
        inner_x = []
        inner_d1 = []
        inner_d2 = []
        startRadians = math.pi*(-0.5 - elementsCount1/elementsCountAround)
        for n1 in range(elementsCountAround):
            radiansAround = startRadians + n1*radiansPerElementAround
            cosRadiansAround = math.cos(radiansAround)
            sinRadiansAround = math.sin(radiansAround)
            inner_x.append((radius*cosRadiansAround, radius*sinRadiansAround))
            inner_d1.append((radiansPerElementAround*radius*-sinRadiansAround, radiansPerElementAround*radius*cosRadiansAround))
            #inner_d2.append((wallThicknessPerElement*cosRadiansAround, wallThicknessPerElement*sinRadiansAround))
            inner_d2.append((wallThicknessMin*cosRadiansAround, wallThicknessMin*sinRadiansAround))
        outer_x = []
        outer_d1 = []
        outer_d2 = []
        mag = math.sqrt(elementsCount1*elementsCount1 + elementsCount2*elementsCount2)
        outer_dx1_ds1 = 1.0 / elementsCount1
        outer_dx2_ds2 = 1.0 / elementsCount2
        #cornerScale1 = 1.0 / max(elementsCount1 + 1, elementsCount2 + 1)
        #cornerScale1 = 1.0 / min(2, max(elementsCount1, elementsCount2))
        cornerScale1 = 1.0 / max(elementsCount1 + elementsCountThroughWall, elementsCount2 + elementsCountThroughWall)
        sqrt05 = math.sqrt(0.5)
        wallThicknessMax = sqrt05 - holeRadius
        for n in range(elementsCount1):
            x = -0.5 + n/elementsCount1
            outer_x.append((x, -0.5))
            if n == 0:
                rx = x/sqrt05
                ry = -0.5/sqrt05
                scale2 = wallThicknessMax
                outer_d1.append((-ry*cornerScale1, rx*cornerScale1))
                outer_d2.append((rx*scale2, ry*scale2))
            else:
                scale2 = wallThicknessMin
                outer_d1.append((outer_dx1_ds1, 0.0))
                outer_d2.append((0.0, -scale2))
        for n in range(elementsCount2):
            y =  -0.5 + n/elementsCount2
            outer_x.append((0.5, y))
            if n == 0:
                rx = 0.5/sqrt05
                ry = y/sqrt05
                scale2 = wallThicknessMax
                outer_d1.append((-ry*cornerScale1, rx*cornerScale1))
                outer_d2.append((rx*scale2, ry*scale2))
            else:
                scale2 = wallThicknessMin
                outer_d1.append((0.0, outer_dx2_ds2))
                outer_d2.append((scale2, 0.0))
        for n in range(elementsCount1):
            x = 0.5 - n/elementsCount1
            outer_x.append((x, 0.5))
            if n == 0:
                rx = x/sqrt05
                ry = 0.5/sqrt05
                scale2 = wallThicknessMax
                outer_d1.append((-ry*cornerScale1, rx*cornerScale1))
                outer_d2.append((rx*scale2, ry*scale2))
            else:
                scale2 = wallThicknessMin
                outer_d1.append((-outer_dx1_ds1, 0.0))
                outer_d2.append((0.0, scale2))
        for n in range(elementsCount2):
            y =  0.5 - n/elementsCount2
            outer_x.append((-0.5, y))
            if n == 0:
                rx = -0.5/sqrt05
                ry = y/sqrt05
                scale2 = wallThicknessMax
                outer_d1.append((-ry*cornerScale1, rx*cornerScale1))
                outer_d2.append((rx*scale2, ry*scale2))
            else:
                scale2 = wallThicknessMin
                outer_d1.append((0.0, -outer_dx2_ds2))
                outer_d2.append((-scale2, 0.0))

        nodeIdentifier = 1
        x = [ 0.0, 0.0, 0.0 ]
        dx_ds1 = [ 0.0, 0.0, 0.0 ]
        dx_ds2 = [ 0.0, 0.0, 0.0 ]
        outer_dx_ds1 = [ 1.0 / elementsCount1, 0.0, 0.0 ]
        outer_dx_ds2 = [ 0.0, 1.0 / elementsCount2, 0.0 ]
        zero = [ 0.0, 0.0, 0.0 ]
        # outer nodes
        for n1 in range(elementsCountAround):
            x[0] = outer_x[n1][0]
            x[1] = outer_x[n1][1]
            node = nodes.createNode(nodeIdentifier, nodetemplate)
            cache.setNode(node)
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x)
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, outer_dx_ds1)
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, outer_dx_ds2)
            if useCrossDerivatives:
                coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero)
            nodeIdentifier = nodeIdentifier + 1
        # inner nodes
        for n2 in range(elementsCountThroughWall):
            xir = (n2 + 1)/elementsCountThroughWall
            xi = 1.0 - xir
            for n1 in range(elementsCountAround):
                node = nodes.createNode(nodeIdentifier, nodetemplate)
                cache.setNode(node)
                v = interpolateCubicHermite(inner_x[n1], inner_d2[n1], outer_x[n1], outer_d2[n1], xi)
                x[0] = v[0]
                x[1] = v[1]
                dx_ds1[0] = xir*inner_d1[n1][0] + xi*outer_d1[n1][0]
                dx_ds1[1] = xir*inner_d1[n1][1] + xi*outer_d1[n1][1]
                d2 = interpolateCubicHermiteDerivative(inner_x[n1], inner_d2[n1], outer_x[n1], outer_d2[n1], xi)
                dx_ds2[0] = -d2[0]/elementsCountThroughWall
                dx_ds2[1] = -d2[1]/elementsCountThroughWall
                coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x)
                coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dx_ds1)
                coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dx_ds2)
                if useCrossDerivatives:
                    coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero)
                nodeIdentifier = nodeIdentifier + 1

        # create elements
        elementIdentifier = 1
        # first row general maps ds1, ds2 to dxi1, dxi2
        for e1 in range(elementsCountAround):
            en = (e1 + 1)%elementsCountAround
            onX = (e1 % (elementsCount1 + elementsCount2)) < elementsCount1
            elementtemplateOuter = elementtemplateOuter1 if onX else elementtemplateOuter2
            eftOuter = eftOuter1 if onX else eftOuter2
            element = mesh.createElement(elementIdentifier, elementtemplateOuter)
            bni11 = e1 + 1
            bni12 = en + 1
            bni21 = elementsCountAround + e1 + 1
            bni22 = elementsCountAround + en + 1
            nodeIdentifiers = [ bni11, bni12, bni21, bni22 ]
            result = element.setNodesByIdentifier(eftOuter, nodeIdentifiers)
            rev = e1 >= (elementsCount1 + elementsCount2)
            one = -1.0 if rev else 1.0
            vx = one if onX else 0.0
            vy = 0.0 if onX else one
            scaleFactors = [
                -1.0,
                4.0,
                vx, vy,
                -outer_d2[e1][0]/outer_dx_ds1[0]/elementsCountThroughWall, -outer_d2[e1][1]/outer_dx_ds2[1]/elementsCountThroughWall,
                vx, vy,
                -outer_d2[en][0]/outer_dx_ds1[0]/elementsCountThroughWall, -outer_d2[en][1]/outer_dx_ds2[1]/elementsCountThroughWall ]
            element.setScaleFactors(eftOuter, scaleFactors)
            elementIdentifier = elementIdentifier + 1

        # remaining rows
        for e2 in range(1, elementsCountThroughWall):
            for e1 in range(elementsCountAround):
                element = mesh.createElement(elementIdentifier, elementtemplate)
                bni11 = e2*elementsCountAround + e1 + 1
                bni12 = e2*elementsCountAround + (e1 + 1)%elementsCountAround + 1
                bni21 = (e2 + 1)*elementsCountAround + e1 + 1
                bni22 = (e2 + 1)*elementsCountAround + (e1 + 1)%elementsCountAround + 1
                nodeIdentifiers = [ bni11, bni12, bni21, bni22 ]
                result = element.setNodesByIdentifier(eft, nodeIdentifiers)
                elementIdentifier = elementIdentifier + 1

        fm.endChange()
        return []
Example #5
0
def getPlaneProjectionOnCentralPath(x, elementsCountAround, elementsCountAlong,
                                    segmentLength, sx, sd1, sd2, sd12):
    """
    Projects reference point used for warping onto the central path and find coordinates
    and derivatives at projected location.
    :param x: coordinates of nodes.
    :param elementsCountAround: number of elements around.
    :param elementsCountAlong: number of elements along.
    :param segmentLength: Length of segment.
    :param sx: coordinates of equally spaced points on central path.
    :param sd1: tangent of equally spaced points on central path.
    :param sd2: derivative representing cross axis at equally spaced points on central path.
    :param sd12: rate of change of cross axis at equally spaced points on central path.
    :return: coordinates and derivatives on project points and z-coordinates of reference points.
    """

    # Use first node in each group of elements along as reference for warping later
    zRefList = []
    for n2 in range(elementsCountAlong + 1):
        zFirstNodeAlong = x[n2 * elementsCountAround][2]
        zRefList.append(zFirstNodeAlong)

    # Find sx, sd1, sd2 at projection of reference points on central path
    lengthElementAlong = segmentLength / elementsCountAlong

    # Append values from first node on central path
    sxRefList = []
    sd1RefList = []
    sd2RefList = []
    sxRefList.append(sx[0])
    sd1RefList.append(sd1[0])
    sd2RefList.append(sd2[0])

    # Interpolate the ones in between
    for n2 in range(1, elementsCountAlong):
        ei = int(zRefList[n2] // lengthElementAlong + 1)
        xi = (zRefList[n2] - lengthElementAlong *
              (ei - 1)) / lengthElementAlong
        sxRef = interp.interpolateCubicHermite(sx[ei - 1], sd1[ei - 1], sx[ei],
                                               sd1[ei], xi)
        sd1Ref = interp.interpolateCubicHermiteDerivative(
            sx[ei - 1], sd1[ei - 1], sx[ei], sd1[ei], xi)
        sd2Ref = interp.interpolateCubicHermite(sd2[ei - 1], sd12[ei - 1],
                                                sd2[ei], sd12[ei], xi)
        sxRefList.append(sxRef)
        sd1RefList.append(sd1Ref)
        sd2RefList.append(sd2Ref)

    # Append values from last node on central path
    sxRefList.append(sx[-1])
    sd1RefList.append(sd1[-1])
    sd2RefList.append(sd2[-1])

    # Project sd2 to plane orthogonal to sd1
    sd2ProjectedListRef = []

    for n in range(len(sd2RefList)):
        sd1Normalised = vector.normalise(sd1RefList[n])
        dp = vector.dotproduct(sd2RefList[n], sd1Normalised)
        dpScaled = [dp * c for c in sd1Normalised]
        sd2Projected = vector.normalise(
            [sd2RefList[n][c] - dpScaled[c] for c in range(3)])
        sd2ProjectedListRef.append(sd2Projected)

    return sxRefList, sd1RefList, sd2ProjectedListRef, zRefList
Example #6
0
    def generateBaseMesh(cls, region, options):
        """
        Generate the base tricubic Hermite mesh.
        :param region: Zinc region to define model in. Must be empty.
        :param options: Dict containing options. See getDefaultOptions().
        :return: [] empty list of AnnotationGroup
        """
        elementsCountAround = options['Number of elements around']
        elementsCountUp = options['Number of elements up']
        elementsCountRadial = options['Number of elements radial']
        useCrossDerivatives = options['Use cross derivatives']
        radius = 0.5 * options['Diameter']

        fm = region.getFieldmodule()
        fm.beginChange()
        coordinates = findOrCreateFieldCoordinates(fm)

        nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
        nodetemplateApex = nodes.createNodetemplate()
        nodetemplateApex.defineField(coordinates)
        nodetemplateApex.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_VALUE, 1)
        nodetemplateApex.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D_DS1, 1)
        nodetemplateApex.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D_DS2, 1)
        nodetemplateApex.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D_DS3, 1)
        if useCrossDerivatives:
            nodetemplate = nodes.createNodetemplate()
            nodetemplate.defineField(coordinates)
            nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_VALUE, 1)
            nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D_DS1, 1)
            nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D_DS2, 1)
            nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D2_DS1DS2,
                                                  1)
            nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D_DS3, 1)
            nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D2_DS1DS3,
                                                  1)
            nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                                  Node.VALUE_LABEL_D2_DS2DS3,
                                                  1)
            nodetemplate.setValueNumberOfVersions(
                coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1)
        else:
            nodetemplate = nodetemplateApex

        cache = fm.createFieldcache()

        #################
        # Create nodes
        #################

        nodeIdentifier = 1
        radiansPerElementAround = 2.0 * math.pi / elementsCountAround
        radiansPerElementUp = math.pi / elementsCountUp

        x = [0.0, 0.0, 0.0]
        dx_ds1 = [0.0, 0.0, 0.0]
        dx_ds2 = [0.0, 0.0, 0.0]
        dx_ds3 = [0.0, 0.0, 0.0]
        zero = [0.0, 0.0, 0.0]

        cubicArcLengthList = [0.0] * (elementsCountUp + 1)

        # Pre-calculate cubicArcLength along elementsCountUp
        for n2 in range(1, elementsCountUp + 1):
            radiansUp = n2 * radiansPerElementUp
            cosRadiansUp = math.cos(radiansUp)
            sinRadiansUp = math.sin(radiansUp)

            # Calculate cubic hermite arclength linking point on axis to surface on sphere
            v1 = [0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp]
            d1 = [0.0, 1.0, 0.0]
            v2 = [
                radius * math.cos(math.pi / 2.0) * sinRadiansUp,
                radius * math.sin(math.pi / 2.0) * sinRadiansUp,
                -radius * cosRadiansUp
            ]
            d2 = [
                math.cos(math.pi / 2.0) * sinRadiansUp,
                math.sin(math.pi / 2.0) * sinRadiansUp, -cosRadiansUp
            ]
            cubicArcLengthList[n2] = interp.computeCubicHermiteArcLength(
                v1, d1, v2, d2, True)

        # Create node for bottom pole
        node = nodes.createNode(nodeIdentifier, nodetemplate)
        cache.setNode(node)
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1,
                                      [0.0, 0.0, -radius])
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1,
                                      [radius * radiansPerElementUp, 0.0, 0.0])
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1,
                                      [0.0, radius * radiansPerElementUp, 0.0])
        coordinates.setNodeParameters(
            cache, -1, Node.VALUE_LABEL_D_DS3, 1,
            [0.0, 0.0, -radius * 2.0 / elementsCountUp])
        if useCrossDerivatives:
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D2_DS1DS2, 1, zero)
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D2_DS1DS3, 1, zero)
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D2_DS2DS3, 1, zero)
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D3_DS1DS2DS3, 1,
                                          zero)
        nodeIdentifier = nodeIdentifier + 1

        # Create nodes along axis between top and bottom poles
        for n2 in range(1, elementsCountUp):
            node = nodes.createNode(nodeIdentifier, nodetemplate)
            cache.setNode(node)
            coordinates.setNodeParameters(
                cache, -1, Node.VALUE_LABEL_VALUE, 1,
                [0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp])
            coordinates.setNodeParameters(
                cache, -1, Node.VALUE_LABEL_D_DS1, 1,
                [cubicArcLengthList[n2] / elementsCountRadial, 0.0, 0.0])
            coordinates.setNodeParameters(
                cache, -1, Node.VALUE_LABEL_D_DS2, 1,
                [0.0, 0.0, radius * 2.0 / elementsCountUp])
            coordinates.setNodeParameters(
                cache, -1, Node.VALUE_LABEL_D_DS3, 1,
                [0.0, cubicArcLengthList[n2] / elementsCountRadial, 0.0])
            if useCrossDerivatives:
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D2_DS1DS2, 1,
                                              zero)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D2_DS1DS3, 1,
                                              zero)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D2_DS2DS3, 1,
                                              zero)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D3_DS1DS2DS3, 1,
                                              zero)
            nodeIdentifier = nodeIdentifier + 1

        # Create nodes for top pole
        node = nodes.createNode(nodeIdentifier, nodetemplate)
        cache.setNode(node)
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1,
                                      [0.0, 0.0, radius])
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1,
                                      [radius * radiansPerElementUp, 0.0, 0.0])
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1,
                                      [0.0, radius * radiansPerElementUp, 0.0])
        coordinates.setNodeParameters(
            cache, -1, Node.VALUE_LABEL_D_DS3, 1,
            [0.0, 0.0, radius * 2.0 / elementsCountUp])
        if useCrossDerivatives:
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D2_DS1DS2, 1, zero)
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D2_DS1DS3, 1, zero)
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D2_DS2DS3, 1, zero)
            coordinates.setNodeParameters(cache, -1,
                                          Node.VALUE_LABEL_D3_DS1DS2DS3, 1,
                                          zero)
        nodeIdentifier = nodeIdentifier + 1

        # Create other nodes
        for n3 in range(1, elementsCountRadial + 1):
            xi = 1 / elementsCountRadial * n3
            radiansUpArcOriginList = [0.0] * (elementsCountUp)

            # Pre-calculate RC for points on vertical arc running between top and bottom poles
            pt = [0.0, radius * xi, 0.0]
            arcOrigin = (radius * radius - pt[2] * pt[2] -
                         pt[1] * pt[1]) / (-2.0 * pt[1])
            RC = math.sqrt(arcOrigin * arcOrigin + radius * radius)

            radiansUpArcOriginList[0] = math.acos(-radius / RC)

            # Identify nodes on the vertical arc using radiansAround = pi/2
            for n2 in range(1, elementsCountUp):
                radiansUp = n2 * radiansPerElementUp
                cosRadiansUp = math.cos(radiansUp)
                sinRadiansUp = math.sin(radiansUp)

                # Calculate node coordinates on arc using cubic hermite interpolation
                cubicArcLength = cubicArcLengthList[n2]
                v1 = [0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp]
                d1 = [math.cos(math.pi / 2.0), math.sin(math.pi / 2.0), 0.0]
                d1 = vector.normalise(d1)
                d1 = [d * cubicArcLength for d in d1]
                v2 = [
                    radius * math.cos(math.pi / 2.0) * sinRadiansUp,
                    radius * math.sin(math.pi / 2.0) * sinRadiansUp,
                    -radius * cosRadiansUp
                ]
                d2 = [
                    math.cos(math.pi / 2.0) * sinRadiansUp,
                    math.sin(math.pi / 2.0) * sinRadiansUp, -cosRadiansUp
                ]
                d2 = vector.normalise(d2)
                d2 = [d * cubicArcLength for d in d2]
                x = interp.interpolateCubicHermite(v1, d1, v2, d2, xi)

                # Calculate radiansUp for each point wrt arcOrigin
                radiansUpArcOriginList[n2] = math.acos(x[2] / RC)

            for n2 in range(1, elementsCountUp):
                radiansUp = n2 * radiansPerElementUp
                cosRadiansUp = math.cos(radiansUp)
                sinRadiansUp = math.sin(radiansUp)

                for n1 in range(elementsCountAround):
                    radiansAround = n1 * radiansPerElementAround
                    cosRadiansAround = math.cos(radiansAround)
                    sinRadiansAround = math.sin(radiansAround)
                    cubicArcLength = cubicArcLengthList[n2]

                    # Calculate node coordinates on arc using cubic hermite interpolation
                    v1 = [
                        0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp
                    ]
                    d1 = [cosRadiansAround, sinRadiansAround, 0.0]
                    d1 = vector.normalise(d1)
                    d1 = [d * cubicArcLength for d in d1]
                    v2 = [
                        radius * cosRadiansAround * sinRadiansUp,
                        radius * sinRadiansAround * sinRadiansUp,
                        -radius * cosRadiansUp
                    ]
                    d2 = [
                        cosRadiansAround * sinRadiansUp,
                        sinRadiansAround * sinRadiansUp, -cosRadiansUp
                    ]
                    d2 = vector.normalise(d2)
                    d2 = [d * cubicArcLength for d in d2]
                    x = interp.interpolateCubicHermite(v1, d1, v2, d2, xi)

                    # For dx_ds1 - Calculate radius wrt origin where interpolated points lie on
                    orthoRadius = vector.magnitude(x)
                    orthoRadiansUp = math.pi - math.acos(x[2] / orthoRadius)
                    sinOrthoRadiansUp = math.sin(orthoRadiansUp)
                    cosOrthoRadiansUp = math.cos(orthoRadiansUp)

                    # For dx_ds2 - Assign radiansUp from radiansUpArcOriginList and calculate diff between radiansUp as we move up
                    radiansUpArcOrigin = radiansUpArcOriginList[n2]
                    sinRadiansUpArcOrigin = math.sin(radiansUpArcOrigin)
                    cosRadiansUpArcOrigin = math.cos(radiansUpArcOrigin)
                    radiansPerElementUpArcOrigin = radiansUpArcOriginList[
                        n2] - radiansUpArcOriginList[n2 - 1]

                    dx_ds1 = [
                        orthoRadius * -sinRadiansAround * sinOrthoRadiansUp *
                        radiansPerElementAround,
                        orthoRadius * cosRadiansAround * sinOrthoRadiansUp *
                        radiansPerElementAround, 0.0
                    ]

                    dx_ds2 = [
                        RC * cosRadiansAround * cosRadiansUpArcOrigin *
                        radiansPerElementUpArcOrigin, RC * sinRadiansAround *
                        cosRadiansUpArcOrigin * radiansPerElementUpArcOrigin,
                        -RC * sinRadiansUpArcOrigin *
                        radiansPerElementUpArcOrigin
                    ]

                    dx_ds3 = interp.interpolateCubicHermiteDerivative(
                        v1, d1, v2, d2, xi)
                    dx_ds3 = vector.normalise(dx_ds3)
                    dx_ds3 = [
                        d * cubicArcLength / elementsCountRadial
                        for d in dx_ds3
                    ]

                    node = nodes.createNode(nodeIdentifier, nodetemplate)
                    cache.setNode(node)
                    coordinates.setNodeParameters(cache, -1,
                                                  Node.VALUE_LABEL_VALUE, 1, x)
                    coordinates.setNodeParameters(cache, -1,
                                                  Node.VALUE_LABEL_D_DS1, 1,
                                                  dx_ds1)
                    coordinates.setNodeParameters(cache, -1,
                                                  Node.VALUE_LABEL_D_DS2, 1,
                                                  dx_ds2)
                    coordinates.setNodeParameters(cache, -1,
                                                  Node.VALUE_LABEL_D_DS3, 1,
                                                  dx_ds3)
                    if useCrossDerivatives:
                        coordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero)
                        coordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero)
                        coordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero)
                        coordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero)
                    nodeIdentifier = nodeIdentifier + 1

        #################
        # Create elements
        #################

        mesh = fm.findMeshByDimension(3)

        tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives)
        eft = tricubichermite.createEftBasic()

        tricubicHermiteBasis = fm.createElementbasis(
            3, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE)

        # Regular elements
        elementtemplate = mesh.createElementtemplate()
        elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE)
        elementtemplate.defineField(coordinates, -1, eft)

        # Bottom tetrahedon elements
        elementtemplate1 = mesh.createElementtemplate()
        elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE)

        # Axial elements
        elementtemplate2 = mesh.createElementtemplate()
        elementtemplate2.setElementShapeType(Element.SHAPE_TYPE_CUBE)

        # Top tetrahedron elements
        elementtemplate3 = mesh.createElementtemplate()
        elementtemplate3.setElementShapeType(Element.SHAPE_TYPE_CUBE)

        # Bottom pyramid elements
        elementtemplate4 = mesh.createElementtemplate()
        elementtemplate4.setElementShapeType(Element.SHAPE_TYPE_CUBE)

        # Top pyramid elements
        elementtemplate5 = mesh.createElementtemplate()
        elementtemplate5.setElementShapeType(Element.SHAPE_TYPE_CUBE)

        elementIdentifier = 1

        no2 = elementsCountAround
        no3 = elementsCountAround * (elementsCountUp - 1)
        rni = (1 + elementsCountUp) - no3 - no2 + 1  # regular node identifier
        radiansPerElementAround = 2.0 * math.pi / elementsCountAround

        for e3 in range(elementsCountRadial):

            # Create elements on bottom pole
            radiansIncline = math.pi * 0.5 * e3 / elementsCountRadial
            radiansInclineNext = math.pi * 0.5 * (e3 + 1) / elementsCountRadial

            if e3 == 0:
                # Create tetrahedron elements on the bottom pole
                bni1 = elementsCountUp + 2

                for e1 in range(elementsCountAround):
                    va = e1
                    vb = (e1 + 1) % elementsCountAround
                    eft1 = tricubichermite.createEftTetrahedronBottom(
                        va * 100, vb * 100, 10000)
                    elementtemplate1.defineField(coordinates, -1, eft1)
                    element = mesh.createElement(elementIdentifier,
                                                 elementtemplate1)
                    nodeIdentifiers = [1, 2, bni1 + va, bni1 + vb]
                    result1 = element.setNodesByIdentifier(
                        eft1, nodeIdentifiers)
                    # set general linear map coefficients
                    radiansAround = va * radiansPerElementAround
                    radiansAroundNext = vb * radiansPerElementAround
                    scalefactors = [
                        -1.0,
                        math.cos(radiansAround),
                        math.sin(radiansAround), radiansPerElementAround,
                        math.cos(radiansAroundNext),
                        math.sin(radiansAroundNext), radiansPerElementAround,
                        math.cos(radiansAround),
                        math.sin(radiansAround), radiansPerElementAround,
                        math.cos(radiansAroundNext),
                        math.sin(radiansAroundNext), radiansPerElementAround,
                        math.cos(radiansIncline),
                        math.sin(radiansIncline),
                        math.cos(radiansInclineNext),
                        math.sin(radiansInclineNext)
                    ]
                    result2 = element.setScaleFactors(eft1, scalefactors)
                    # print('Tetrahedron Bottom element', elementIdentifier, result1, result2, nodeIdentifiers)
                    elementIdentifier = elementIdentifier + 1

            else:
                # Create pyramid elements on the bottom pole
                bni4 = elementsCountUp + 1 + (e3 - 1) * no3 + 1

                for e1 in range(elementsCountAround):
                    va = e1
                    vb = (e1 + 1) % elementsCountAround
                    eft4 = tricubichermite.createEftPyramidBottom(
                        va * 100, vb * 100, 100000 + e3 * 2)
                    elementtemplate4.defineField(coordinates, -1, eft4)
                    element = mesh.createElement(elementIdentifier,
                                                 elementtemplate4)
                    nodeIdentifiers = [
                        1, bni4 + va, bni4 + vb, bni4 + no3 + va,
                        bni4 + no3 + vb
                    ]
                    result1 = element.setNodesByIdentifier(
                        eft4, nodeIdentifiers)
                    # set general linear map coefficients
                    radiansAround = va * radiansPerElementAround
                    radiansAroundNext = vb * radiansPerElementAround
                    scalefactors = [
                        -1.0,
                        math.cos(radiansAround),
                        math.sin(radiansAround), radiansPerElementAround,
                        math.cos(radiansAroundNext),
                        math.sin(radiansAroundNext), radiansPerElementAround,
                        math.cos(radiansIncline),
                        math.sin(radiansIncline),
                        math.cos(radiansInclineNext),
                        math.sin(radiansInclineNext)
                    ]
                    result2 = element.setScaleFactors(eft4, scalefactors)
                    # print('pyramid bottom element', elementIdentifier, result1, result2, nodeIdentifiers)
                    elementIdentifier = elementIdentifier + 1

            # create regular radial elements
            for e2 in range(1, elementsCountUp - 1):
                if e3 == 0:
                    for e1 in range(elementsCountAround):
                        # create central radial elements: 6 node wedges
                        va = e1
                        vb = (e1 + 1) % elementsCountAround
                        eft2 = tricubichermite.createEftWedgeRadial(
                            va * 100, vb * 100)
                        elementtemplate2.defineField(coordinates, -1, eft2)
                        element = mesh.createElement(elementIdentifier,
                                                     elementtemplate2)
                        bni2 = elementsCountUp + 1 + (e2 - 1) * no2 + 1
                        nodeIdentifiers = [
                            e3 + e2 + 1, e3 + e2 + 2, bni2 + va, bni2 + vb,
                            bni2 + va + elementsCountAround,
                            bni2 + vb + elementsCountAround
                        ]
                        result1 = element.setNodesByIdentifier(
                            eft2, nodeIdentifiers)
                        # set general linear map coefficients
                        radiansAround = va * radiansPerElementAround
                        radiansAroundNext = vb * radiansPerElementAround
                        scalefactors = [
                            -1.0,
                            math.cos(radiansAround),
                            math.sin(radiansAround), radiansPerElementAround,
                            math.cos(radiansAroundNext),
                            math.sin(radiansAroundNext),
                            radiansPerElementAround,
                            math.cos(radiansAround),
                            math.sin(radiansAround), radiansPerElementAround,
                            math.cos(radiansAroundNext),
                            math.sin(radiansAroundNext),
                            radiansPerElementAround
                        ]
                        result2 = element.setScaleFactors(eft2, scalefactors)
                        # print('axis element', elementIdentifier, result1, result2, nodeIdentifiers)
                        elementIdentifier = elementIdentifier + 1
                else:
                    # Regular elements
                    bni = rni + e3 * no3 + e2 * no2

                    for e1 in range(elementsCountAround):
                        element = mesh.createElement(elementIdentifier,
                                                     elementtemplate)
                        na = e1
                        nb = (e1 + 1) % elementsCountAround
                        nodeIdentifiers = [
                            bni + na, bni + nb, bni + no2 + na, bni + no2 + nb,
                            bni + no3 + na, bni + no3 + nb,
                            bni + no3 + no2 + na, bni + no3 + no2 + nb
                        ]
                        result = element.setNodesByIdentifier(
                            eft, nodeIdentifiers)
                        # print('regular element', elementIdentifier, result, nodeIdentifiers)
                        elementIdentifier = elementIdentifier + 1

            # Create elements on top pole
            radiansIncline = math.pi * 0.5 * e3 / elementsCountRadial
            radiansInclineNext = math.pi * 0.5 * (e3 + 1) / elementsCountRadial

            if e3 == 0:
                # # Create tetrahedron elements on the top pole
                bni3 = elementsCountUp + 1 + (elementsCountUp - 2) * no2 + 1

                for e1 in range(elementsCountAround):
                    va = e1
                    vb = (e1 + 1) % elementsCountAround
                    eft3 = tricubichermite.createEftTetrahedronTop(
                        va * 100, vb * 100, 100000)
                    elementtemplate3.defineField(coordinates, -1, eft3)
                    element = mesh.createElement(elementIdentifier,
                                                 elementtemplate3)
                    nodeIdentifiers = [
                        elementsCountUp, elementsCountUp + 1, bni3 + va,
                        bni3 + vb
                    ]
                    result1 = element.setNodesByIdentifier(
                        eft3, nodeIdentifiers)
                    # set general linear map coefficients
                    radiansAround = va * radiansPerElementAround
                    radiansAroundNext = vb * radiansPerElementAround
                    scalefactors = [
                        -1.0,
                        math.cos(radiansAround),
                        math.sin(radiansAround), radiansPerElementAround,
                        math.cos(radiansAroundNext),
                        math.sin(radiansAroundNext), radiansPerElementAround,
                        math.cos(radiansAround),
                        math.sin(radiansAround), radiansPerElementAround,
                        math.cos(radiansAroundNext),
                        math.sin(radiansAroundNext), radiansPerElementAround,
                        math.cos(radiansIncline),
                        math.sin(radiansIncline),
                        math.cos(radiansInclineNext),
                        math.sin(radiansInclineNext)
                    ]
                    result2 = element.setScaleFactors(eft3, scalefactors)
                    # print('Tetrahedron top element', elementIdentifier, result1, result2, nodeIdentifiers)
                    elementIdentifier = elementIdentifier + 1

            else:
                # Create pyramid elements on the top pole
                bni5 = elementsCountUp + 1 + (e3 - 1) * no3 + (
                    elementsCountUp - 2) * no2 + 1

                for e1 in range(elementsCountAround):
                    va = e1
                    vb = (e1 + 1) % elementsCountAround
                    eft5 = tricubichermite.createEftPyramidTop(
                        va * 100, vb * 100, 100000 + e3 * 2)

                    elementtemplate5.defineField(coordinates, -1, eft5)
                    element = mesh.createElement(elementIdentifier,
                                                 elementtemplate5)
                    nodeIdentifiers = [
                        bni5 + va, bni5 + vb, elementsCountUp + 1,
                        bni5 + no3 + va, bni5 + no3 + vb
                    ]
                    result1 = element.setNodesByIdentifier(
                        eft5, nodeIdentifiers)
                    # set general linear map coefficients
                    radiansAround = va * radiansPerElementAround
                    radiansAroundNext = vb * radiansPerElementAround
                    scalefactors = [
                        -1.0,
                        math.cos(radiansAround),
                        math.sin(radiansAround), radiansPerElementAround,
                        math.cos(radiansAroundNext),
                        math.sin(radiansAroundNext), radiansPerElementAround,
                        math.cos(radiansIncline),
                        math.sin(radiansIncline),
                        math.cos(radiansInclineNext),
                        math.sin(radiansInclineNext)
                    ]
                    result2 = element.setScaleFactors(eft5, scalefactors)
                    # print('pyramid top element', elementIdentifier, result1, result2, nodeIdentifiers)
                    elementIdentifier = elementIdentifier + 1

        fm.endChange()
        return []