Exemple #1
0
def get_bifurcation_triple_point(p1x, p1d, p2x, p2d, p3x, p3d):
    '''
    Get coordinates and derivatives of triple point between p1, p2 and p3 with derivatives.
    :param p1x..p3d: Point coordinates and derivatives, numbered anticlockwise around triple point.
    All derivatives point away from triple point.
    Returned d1 points from triple point to p2, d2 points from triple point to p3.
    :return: x, d1, d2
    '''
    trx1 = interpolateCubicHermite(p1x, mult(p1d, -2.0), p2x, mult(p2d, 2.0), 0.5)
    trx2 = interpolateCubicHermite(p2x, mult(p2d, -2.0), p3x, mult(p3d, 2.0), 0.5)
    trx3 = interpolateCubicHermite(p3x, mult(p3d, -2.0), p1x, mult(p1d, 2.0), 0.5)
    trx = [ (trx1[c] + trx2[c] + trx3[c])/3.0 for c in range(3) ]
    td1 = interpolateLagrangeHermiteDerivative(trx, p1x, p1d, 0.0)
    td2 = interpolateLagrangeHermiteDerivative(trx, p2x, p2d, 0.0)
    td3 = interpolateLagrangeHermiteDerivative(trx, p3x, p3d, 0.0)
    n12 = cross(td1, td2)
    n23 = cross(td2, td3)
    n31 = cross(td3, td1)
    norm = normalize([ (n12[c] + n23[c] + n31[c]) for c in range(3) ])
    sd1 = smoothCubicHermiteDerivativesLine([ trx, p1x ], [ normalize(cross(norm, cross(td1, norm))), p1d ], fixStartDirection=True, fixEndDerivative=True)[0]
    sd2 = smoothCubicHermiteDerivativesLine([ trx, p2x ], [ normalize(cross(norm, cross(td2, norm))), p2d ], fixStartDirection=True, fixEndDerivative=True)[0]
    sd3 = smoothCubicHermiteDerivativesLine([ trx, p3x ], [ normalize(cross(norm, cross(td3, norm))), p3d ], fixStartDirection=True, fixEndDerivative=True)[0]
    trd1 = mult(sub(sd2, add(sd3, sd1)), 0.5)
    trd2 = mult(sub(sd3, add(sd1, sd2)), 0.5)
    return trx, trd1, trd2
Exemple #2
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
Exemple #3
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
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 []
Exemple #6
0
def getCylindricalSegmentInnerPoints(elementsCountAround,
                                     elementsCountAlongSegment, segmentLength,
                                     wallThickness, startRadius,
                                     startRadiusDerivative, endRadius,
                                     endRadiusDerivative, startPhase):
    """
    Generates a 3-D cylindrical segment mesh with variable numbers of elements
    around, along the central path, and through wall.
    :param elementsCountAround: Number of elements around.
    :param elementsCountAlongSegment: Number of elements along cylindrical segment.
    :param segmentLength: Length of a cylindrical segment.
    :param wallThickness: Thickness of wall.
    :param startRadius: Inner radius at proximal end.
    :param startRadiusDerivative: Rate of change of inner radius at proximal end.
    :param endRadius: Inner radius at distal end.
    :param endRadiusDerivative: Rate of change of inner radius at distal end.
    :param startPhase: Phase at start.
    :return coordinates, derivatives on inner surface of a cylindrical segment.
    :return transitElementList: stores true if element around is an element that
    transits between a big and small element.
    :return xiList: List of xi for each node around. xi refers to node position
    along the width when cylindrical segment is opened into a flat preparation,
    nominally in [0.0, 1.0].
    :return flatWidthList: List of width around elements for each element
    along cylindrical segment when the segment is opened into a flat preparation.
    :return segmentAxis: Axis of segment.
    :return sRadiusAlongSegment: radius of each element along segment.
    """

    transitElementList = [0] * elementsCountAround

    # create nodes
    segmentAxis = [0.0, 0.0, 1.0]

    xFinal = []
    d1Final = []
    d2Final = []
    xiList = []
    flatWidthList = []
    sRadiusAlongSegment = []

    for n2 in range(elementsCountAlongSegment + 1):
        phase = startPhase + n2 * 360.0 / elementsCountAlongSegment
        xi = (phase if phase <= 360.0 else phase - 360.0) / 360.0
        radius = interp.interpolateCubicHermite([startRadius],
                                                [startRadiusDerivative],
                                                [endRadius],
                                                [endRadiusDerivative], xi)[0]
        sRadiusAlongSegment.append(radius)
        z = segmentLength / elementsCountAlongSegment * n2 + startPhase / 360.0 * segmentLength

        xLoop, d1Loop = createCirclePoints([0.0, 0.0, z], [radius, 0.0, 0.0],
                                           [0.0, radius, 0.0],
                                           elementsCountAround,
                                           startRadians=0.0)
        xFinal = xFinal + xLoop
        d1Final = d1Final + d1Loop

    # Smooth d2 for segment
    smoothd2Raw = []
    for n1 in range(elementsCountAround):
        nx = []
        nd2 = []
        for n2 in range(elementsCountAlongSegment + 1):
            n = n2 * elementsCountAround + n1
            nx.append(xFinal[n])
            nd2.append(segmentAxis)
        smoothd2 = interp.smoothCubicHermiteDerivativesLine(nx, nd2)
        smoothd2Raw.append(smoothd2)

    # Re-arrange smoothd2
    for n2 in range(elementsCountAlongSegment + 1):
        radius = sRadiusAlongSegment[n2]
        flatWidth = 2.0 * math.pi * (radius + wallThickness)
        flatWidthList.append(flatWidth)
        xiFace = []
        for n1 in range(elementsCountAround):
            d2Final.append(smoothd2Raw[n1][n2])
        for n1 in range(elementsCountAround + 1):
            xi = 1.0 / elementsCountAround * n1
            xiFace.append(xi)
        xiList.append(xiFace)

    return xFinal, d1Final, d2Final, transitElementList, xiList, flatWidthList, segmentAxis, sRadiusAlongSegment
Exemple #7
0
def getCoordinatesFromInner(xInner, d1Inner, d2Inner, d3Inner,
                            wallThicknessList, relativeThicknessList,
                            elementsCountAround, elementsCountAlong,
                            elementsCountThroughWall, transitElementList):
    """
    Generates coordinates from inner to outer surface using coordinates
    and derivatives of inner surface.
    :param xInner: Coordinates on inner surface
    :param d1Inner: Derivatives on inner surface around tube
    :param d2Inner: Derivatives on inner surface along tube
    :param d3Inner: Derivatives on inner surface through wall
    :param wallThicknessList: Wall thickness for each element along tube
    :param relativeThicknessList: Relative wall thickness for each element through wall
    :param elementsCountAround: Number of elements around tube
    :param elementsCountAlong: Number of elements along tube
    :param elementsCountThroughWall: Number of elements through tube wall
    :param transitElementList: stores true if element around is a transition
    element that is between a big and a small element.
    return nodes and derivatives for mesh, and curvature along inner surface.
    """

    xOuter = []
    curvatureAroundInner = []
    curvatureAlong = []
    curvatureList = []
    xList = []
    d1List = []
    d2List = []
    d3List = []

    if relativeThicknessList:
        xi3 = 0.0
        xi3List = [0.0]
        for n3 in range(elementsCountThroughWall):
            xi3 += relativeThicknessList[n3]
            xi3List.append(xi3)
        relativeThicknessList.append(relativeThicknessList[-1])

    for n2 in range(elementsCountAlong + 1):
        wallThickness = wallThicknessList[n2]
        for n1 in range(elementsCountAround):
            n = n2 * elementsCountAround + n1
            norm = d3Inner[n]
            # Calculate outer coordinates
            x = [xInner[n][i] + norm[i] * wallThickness for i in range(3)]
            xOuter.append(x)
            # Calculate curvature along elements around
            prevIdx = n - 1 if (
                n1 != 0) else (n2 + 1) * elementsCountAround - 1
            nextIdx = n + 1 if (
                n1 < elementsCountAround - 1) else n2 * elementsCountAround
            kappam = interp.getCubicHermiteCurvatureSimple(
                xInner[prevIdx], d1Inner[prevIdx], xInner[n], d1Inner[n], 1.0)
            kappap = interp.getCubicHermiteCurvatureSimple(
                xInner[n], d1Inner[n], xInner[nextIdx], d1Inner[nextIdx], 0.0)
            if not transitElementList[n1] and not transitElementList[
                (n1 - 1) % elementsCountAround]:
                curvatureAround = 0.5 * (kappam + kappap)
            elif transitElementList[n1]:
                curvatureAround = kappam
            elif transitElementList[(n1 - 1) % elementsCountAround]:
                curvatureAround = kappap
            curvatureAroundInner.append(curvatureAround)

            # Calculate curvature along
            if n2 == 0:
                curvature = interp.getCubicHermiteCurvature(
                    xInner[n], d2Inner[n], xInner[n + elementsCountAround],
                    d2Inner[n + elementsCountAround],
                    vector.normalise(d3Inner[n]), 0.0)
            elif n2 == elementsCountAlong:
                curvature = interp.getCubicHermiteCurvature(
                    xInner[n - elementsCountAround],
                    d2Inner[n - elementsCountAround], xInner[n], d2Inner[n],
                    vector.normalise(d3Inner[n]), 1.0)
            else:
                curvature = 0.5 * (interp.getCubicHermiteCurvature(
                    xInner[n - elementsCountAround],
                    d2Inner[n - elementsCountAround], xInner[n], d2Inner[n],
                    vector.normalise(d3Inner[n]),
                    1.0) + interp.getCubicHermiteCurvature(
                        xInner[n], d2Inner[n], xInner[n + elementsCountAround],
                        d2Inner[n + elementsCountAround],
                        vector.normalise(d3Inner[n]), 0.0))
            curvatureAlong.append(curvature)

        for n3 in range(elementsCountThroughWall + 1):
            xi3 = xi3List[
                n3] if relativeThicknessList else 1.0 / elementsCountThroughWall * n3
            for n1 in range(elementsCountAround):
                n = n2 * elementsCountAround + n1
                norm = d3Inner[n]
                innerx = xInner[n]
                outerx = xOuter[n]
                dWall = [wallThickness * c for c in norm]
                # x
                x = interp.interpolateCubicHermite(innerx, dWall, outerx,
                                                   dWall, xi3)
                xList.append(x)

                # dx_ds1
                factor = 1.0 + wallThickness * xi3 * curvatureAroundInner[n]
                d1 = [factor * c for c in d1Inner[n]]
                d1List.append(d1)

                # dx_ds2
                curvature = curvatureAlong[n]
                distance = vector.magnitude(
                    [x[i] - xInner[n][i] for i in range(3)])
                factor = 1.0 - curvature * distance
                d2 = [factor * c for c in d2Inner[n]]
                d2List.append(d2)
                curvatureList.append(curvature)

                #dx_ds3
                d3 = [
                    c * wallThickness *
                    (relativeThicknessList[n3] if relativeThicknessList else
                     1.0 / elementsCountThroughWall) for c in norm
                ]
                d3List.append(d3)

    return xList, d1List, d2List, d3List, curvatureList
Exemple #8
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
Exemple #9
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 []