예제 #1
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: list of AnnotationGroup
        """
        # set dependent outer diameter used in atria2
        options['LV outlet outer diameter'] = options[
            'LV outlet inner diameter'] + 2.0 * options[
                'LV outlet wall thickness']

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

        # generate heartventriclesbase2 model and put atria2 on it
        ventriclesAnnotationGroups = MeshType_3d_heartventriclesbase2.generateBaseMesh(
            region, options)
        atriaAnnotationGroups = MeshType_3d_heartatria2.generateBaseMesh(
            region, options)
        annotationGroups = mergeAnnotationGroups(ventriclesAnnotationGroups,
                                                 atriaAnnotationGroups)

        fm.endChange()
        return annotationGroups
예제 #2
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: list of AnnotationGroup
        """
        # set dependent outer diameter used in atria2
        options['Aorta outer plus diameter'] = options[
            'LV outlet inner diameter'] + 2.0 * options[
                'LV outlet wall thickness']
        elementsCountAroundAtrialSeptum = options[
            'Number of elements around atrial septum']
        elementsCountAroundLeftAtriumFreeWall = options[
            'Number of elements around left atrium free wall']
        elementsCountAroundLeftAtrium = elementsCountAroundLeftAtriumFreeWall + elementsCountAroundAtrialSeptum
        elementsCountAroundRightAtriumFreeWall = options[
            'Number of elements around right atrium free wall']
        elementsCountAroundRightAtrium = elementsCountAroundRightAtriumFreeWall + elementsCountAroundAtrialSeptum
        useCrossDerivatives = False

        fm = region.getFieldmodule()
        coordinates = findOrCreateFieldCoordinates(fm)
        cache = fm.createFieldcache()

        mesh = fm.findMeshByDimension(3)

        # generate heartventriclesbase1 model and put atria1 on it
        ventriclesAnnotationGroups = MeshType_3d_heartventriclesbase1.generateBaseMesh(
            region, options)
        atriaAnnotationGroups = MeshType_3d_heartatria1.generateBaseMesh(
            region, options)
        annotationGroups = mergeAnnotationGroups(ventriclesAnnotationGroups,
                                                 atriaAnnotationGroups)
        lFibrousRingGroup = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region, get_heart_term("left fibrous ring"))
        rFibrousRingGroup = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region, get_heart_term("right fibrous ring"))

        # annotation fiducial points
        markerGroup = findOrCreateFieldGroup(fm, "marker")
        markerName = findOrCreateFieldStoredString(fm, name="marker_name")
        markerLocation = findOrCreateFieldStoredMeshLocation(
            fm, mesh, name="marker_location")

        nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
        markerPoints = findOrCreateFieldNodeGroup(markerGroup,
                                                  nodes).getNodesetGroup()
        markerTemplateInternal = nodes.createNodetemplate()
        markerTemplateInternal.defineField(markerName)
        markerTemplateInternal.defineField(markerLocation)

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

        nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1)

        # discover left and right fibrous ring nodes from ventricles and atria
        # because nodes are iterated in identifier order, the lowest and first are on the lv outlet cfb, right and left on lower outer layers
        # left fibrous ring
        lavNodeId = [[[], []], [[], []]]  # [n3][n2][n1]
        iter = lFibrousRingGroup.getNodesetGroup(nodes).createNodeiterator()
        # left fibrous ring, bottom row
        cfbNodeId = iter.next().getIdentifier()
        cfbLeftNodeId = iter.next().getIdentifier()
        for n1 in range(elementsCountAroundLeftAtrium):
            lavNodeId[0][0].append(iter.next().getIdentifier())
        lavNodeId[1][0].append(cfbNodeId)
        lavNodeId[1][0].append(cfbLeftNodeId)
        for n1 in range(elementsCountAroundLeftAtriumFreeWall - 1):
            lavNodeId[1][0].append(iter.next().getIdentifier())
        for n1 in range(elementsCountAroundAtrialSeptum - 1):
            lavNodeId[1][0].append(None)  # no outer node on interatrial septum
        # left fibrous ring, top row
        for n1 in range(elementsCountAroundLeftAtrium):
            lavNodeId[0][1].append(iter.next().getIdentifier())
        for n1 in range(elementsCountAroundLeftAtriumFreeWall + 1):
            lavNodeId[1][1].append(iter.next().getIdentifier())
        for n1 in range(elementsCountAroundAtrialSeptum - 1):
            lavNodeId[1][1].append(None)  # no outer node on interatrial septum
        # right fibrous ring
        ravNodeId = [[[], []], [[], []]]  # [n3][n2][n1]
        iter = rFibrousRingGroup.getNodesetGroup(nodes).createNodeiterator()
        cfbNodeId = iter.next().getIdentifier()
        cfbRightNodeId = iter.next().getIdentifier()
        # right fibrous ring, bottom row
        for n1 in range(elementsCountAroundRightAtrium):
            ravNodeId[0][0].append(iter.next().getIdentifier())
        for n1 in range(elementsCountAroundRightAtriumFreeWall - 1):
            ravNodeId[1][0].append(iter.next().getIdentifier())
        ravNodeId[1][0].append(cfbRightNodeId)
        ravNodeId[1][0].append(cfbNodeId)
        for n1 in range(elementsCountAroundAtrialSeptum - 1):
            ravNodeId[1][0].append(None)  # no outer node on interatrial septum
        # right fibrous ring, top row
        for n1 in range(elementsCountAroundRightAtrium):
            ravNodeId[0][1].append(iter.next().getIdentifier())
        cfbUpperNodeId = iter.next().getIdentifier(
        )  # cfb from left will be first
        for n1 in range(elementsCountAroundRightAtriumFreeWall):
            ravNodeId[1][1].append(iter.next().getIdentifier())
        ravNodeId[1][1].append(cfbUpperNodeId)
        for n1 in range(elementsCountAroundAtrialSeptum - 1):
            ravNodeId[1][1].append(None)  # no outer node on interatrial septum

        #for n2 in range(2):
        #    print('n2', n2)
        #    print('lavNodeId[0]', lavNodeId[0][n2])
        #    print('lavNodeId[1]', lavNodeId[1][n2])
        #    print('ravNodeId[0]', ravNodeId[0][n2])
        #    print('ravNodeId[1]', ravNodeId[1][n2])

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

        lFibrousRingMeshGroup = lFibrousRingGroup.getMeshGroup(mesh)
        rFibrousRingMeshGroup = rFibrousRingGroup.getMeshGroup(mesh)

        elementIdentifier = getMaximumElementIdentifier(mesh) + 1

        elementtemplate1 = mesh.createElementtemplate()
        elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE)

        # create fibrous ring elements

        bicubichermitelinear = eftfactory_bicubichermitelinear(
            mesh,
            useCrossDerivatives,
            linearAxis=2,
            d_ds1=Node.VALUE_LABEL_D_DS1,
            d_ds2=Node.VALUE_LABEL_D_DS3)
        eftFibrousRing = bicubichermitelinear.createEftBasic()

        # left fibrous ring, starting at crux / collapsed posterior interatrial sulcus
        cruxElementId = None
        for e in range(-1, elementsCountAroundLeftAtriumFreeWall):
            eft1 = eftFibrousRing
            n1 = e
            nids = [
                lavNodeId[0][0][n1], lavNodeId[0][0][n1 + 1],
                lavNodeId[0][1][n1], lavNodeId[0][1][n1 + 1],
                lavNodeId[1][0][n1], lavNodeId[1][0][n1 + 1],
                lavNodeId[1][1][n1], lavNodeId[1][1][n1 + 1]
            ]
            scalefactors = None
            meshGroups = [lFibrousRingMeshGroup]

            if e == -1:
                # interatrial groove straddles left and right atria, collapsed to 6 node wedge
                nids[0] = ravNodeId[0][0][
                    elementsCountAroundRightAtriumFreeWall]
                nids[2] = ravNodeId[0][1][
                    elementsCountAroundRightAtriumFreeWall]
                nids.pop(6)
                nids.pop(4)
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
                remapEftNodeValueLabel(eft1, [5, 6, 7, 8],
                                       Node.VALUE_LABEL_D_DS1, [])
                # reverse d3 on cfb:
                remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
                remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [0]),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
                remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                ln_map = [1, 2, 3, 4, 5, 5, 6, 6]
                remapEftLocalNodes(eft1, 6, ln_map)
                meshGroups += [rFibrousRingMeshGroup]
            elif e == 0:
                # general linear map d3 adjacent to collapsed sulcus
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                # reverse d1, d3 on cfb, left cfb:
                scaleEftNodeValueLabels(
                    eft1, [6],
                    [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS3], [1])
                remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, [1])])
                remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
                remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [])])
            elif e == 1:
                # reverse d1, d3 on left cfb:
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS3, [1])])
            elif e == (elementsCountAroundLeftAtriumFreeWall - 1):
                # general linear map d3 adjacent to collapsed sulcus
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                remapEftNodeValueLabel(eft1, [6, 8], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [])])

            result = elementtemplate1.defineField(coordinates, -1, eft1)
            element = mesh.createElement(elementIdentifier, elementtemplate1)
            result2 = element.setNodesByIdentifier(eft1, nids)
            result3 = element.setScaleFactors(
                eft1, scalefactors) if scalefactors else None
            #print('create element fibrous ring left', elementIdentifier, result, result2, result3, nids)
            elementIdentifier += 1

            for meshGroup in meshGroups:
                meshGroup.addElement(element)

        # right fibrous ring, starting at crux / collapsed posterior interatrial sulcus
        for e in range(-1, elementsCountAroundRightAtriumFreeWall):
            eft1 = eftFibrousRing
            n1 = e
            nids = [
                ravNodeId[0][0][n1], ravNodeId[0][0][n1 + 1],
                ravNodeId[0][1][n1], ravNodeId[0][1][n1 + 1],
                ravNodeId[1][0][n1], ravNodeId[1][0][n1 + 1],
                ravNodeId[1][1][n1], ravNodeId[1][1][n1 + 1]
            ]
            scalefactors = None
            meshGroups = [rFibrousRingMeshGroup]

            if e == -1:
                # interatrial groove straddles left and right atria, collapsed to 6 node wedge
                nids[0] = lavNodeId[0][0][
                    elementsCountAroundLeftAtriumFreeWall]
                nids[2] = lavNodeId[0][1][
                    elementsCountAroundLeftAtriumFreeWall]
                nids.pop(6)
                nids.pop(4)
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
                remapEftNodeValueLabel(eft1, [5, 6, 7, 8],
                                       Node.VALUE_LABEL_D_DS1, [])
                remapEftNodeValueLabel(eft1, [5, 7], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                remapEftNodeValueLabel(eft1, [6, 8], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                ln_map = [1, 2, 3, 4, 5, 5, 6, 6]
                remapEftLocalNodes(eft1, 6, ln_map)
                meshGroups += [lFibrousRingMeshGroup]
                cruxElementId = elementIdentifier
            elif e == 0:
                # general linear map d3 adjacent to collapsed crux/posterior sulcus
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                remapEftNodeValueLabel(eft1, [5, 7], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [])])
            elif e == (elementsCountAroundRightAtriumFreeWall - 2):
                # reverse d1, d3 on right cfb:
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
                remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS3, [1])])
            elif e == (elementsCountAroundRightAtriumFreeWall - 1):
                # general linear map d3 adjacent to collapsed cfb/anterior sulcus
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]
                # reverse d1, d3 on right cfb, cfb:
                scaleEftNodeValueLabels(
                    eft1, [5],
                    [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS3], [1])
                remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS1, [1])])
                remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
                remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [])])

            result = elementtemplate1.defineField(coordinates, -1, eft1)
            element = mesh.createElement(elementIdentifier, elementtemplate1)
            result2 = element.setNodesByIdentifier(eft1, nids)
            result3 = element.setScaleFactors(
                eft1, scalefactors) if scalefactors else None
            #print('create element fibrous ring right', elementIdentifier, result, result2, result3, nids)
            elementIdentifier += 1

            for meshGroup in meshGroups:
                meshGroup.addElement(element)

        # fibrous ring septum:
        meshGroups = [lFibrousRingMeshGroup, rFibrousRingMeshGroup]
        for e in range(elementsCountAroundAtrialSeptum):
            eft1 = eftFibrousRing
            nlm = e - elementsCountAroundAtrialSeptum
            nlp = nlm + 1
            nrm = -e
            nrp = nrm - 1
            nids = [
                lavNodeId[0][0][nlm], lavNodeId[0][0][nlp],
                lavNodeId[0][1][nlm], lavNodeId[0][1][nlp],
                ravNodeId[0][0][nrm], ravNodeId[0][0][nrp],
                ravNodeId[0][1][nrm], ravNodeId[0][1][nrp]
            ]

            eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
            setEftScaleFactorIds(eft1, [1], [])
            scalefactors = [-1.0]
            if e == 0:
                # general linear map d3 adjacent to collapsed posterior interventricular sulcus
                scaleEftNodeValueLabels(eft1, [5, 6, 7, 8],
                                        [Node.VALUE_LABEL_D_DS1], [1])
                scaleEftNodeValueLabels(eft1, [6, 8], [Node.VALUE_LABEL_D_DS3],
                                        [1])
                remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                remapEftNodeValueLabel(eft1, [5, 7], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, []),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
            elif e == (elementsCountAroundAtrialSeptum - 1):
                # general linear map d3 adjacent to cfb
                scaleEftNodeValueLabels(eft1, [5, 6, 7, 8],
                                        [Node.VALUE_LABEL_D_DS1], [1])
                scaleEftNodeValueLabels(eft1, [5, 7], [Node.VALUE_LABEL_D_DS3],
                                        [1])
                remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [])])
                remapEftNodeValueLabel(eft1, [6, 8], Node.VALUE_LABEL_D_DS3,
                                       [(Node.VALUE_LABEL_D_DS1, [1]),
                                        (Node.VALUE_LABEL_D_DS3, [1])])
            else:
                scaleEftNodeValueLabels(
                    eft1, [5, 6, 7, 8],
                    [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS3], [1])

            result = elementtemplate1.defineField(coordinates, -1, eft1)
            element = mesh.createElement(elementIdentifier, elementtemplate1)
            result2 = element.setNodesByIdentifier(eft1, nids)
            result3 = element.setScaleFactors(
                eft1, scalefactors) if scalefactors else None
            #print('create element fibrous ring septum', elementIdentifier, result, result2, result3, nids)
            elementIdentifier += 1

            for meshGroup in meshGroups:
                meshGroup.addElement(element)

        # annotation fiducial points
        cruxElement = mesh.findElementByIdentifier(cruxElementId)
        cruxXi = [0.5, 0.5, 1.0]
        cache.setMeshLocation(cruxElement, cruxXi)
        result, cruxCoordinates = coordinates.evaluateReal(cache, 3)
        markerPoint = markerPoints.createNode(nodeIdentifier,
                                              markerTemplateInternal)
        nodeIdentifier += 1
        cache.setNode(markerPoint)
        markerName.assignString(cache, "crux of heart")
        markerLocation.assignMeshLocation(cache, cruxElement, cruxXi)

        return annotationGroups
예제 #3
0
def createNodesAndElements(region, x, d1, d2, d3, xFlat, d1Flat, d2Flat,
                           xOrgan, d1Organ, d2Organ, organCoordinateFieldName,
                           elementsCountAround, elementsCountAlong,
                           elementsCountThroughWall, annotationGroupsAround,
                           annotationGroupsAlong, annotationGroupsThroughWall,
                           firstNodeIdentifier, firstElementIdentifier,
                           useCubicHermiteThroughWall, useCrossDerivatives,
                           closedProximalEnd):
    """
    Create nodes and elements for the coordinates and flat coordinates fields.
    :param x, d1, d2, d3: coordinates and derivatives of coordinates field.
    :param xFlat, d1Flat, d2Flat, d3Flat: coordinates and derivatives of
    flat coordinates field.
    :param xOrgan, d1Organ, d2Organ, d3Organ, organCoordinateFieldName: coordinates, derivatives and name of organ
    coordinates field.
    :param elementsCountAround: Number of elements around tube.
    :param elementsCountAlong: Number of elements along tube.
    :param elementsCountThroughWall: Number of elements through wall.
    :param annotationGroupsAround: Annotation groups of elements around.
    :param annotationGroupsAlong: Annotation groups of elements along.
    :param annotationGroupsThroughWall: Annotation groups of elements through wall.
    :param firstNodeIdentifier, firstElementIdentifier: first node and
    element identifier to use.
    :param useCubicHermiteThroughWall: use linear when false
    :param useCrossDerivatives: use cross derivatives when true
    :return nodeIdentifier, elementIdentifier, allAnnotationGroups
    """

    nodeIdentifier = firstNodeIdentifier
    elementIdentifier = firstElementIdentifier
    zero = [0.0, 0.0, 0.0]

    fm = region.getFieldmodule()
    fm.beginChange()
    cache = fm.createFieldcache()

    # Coordinates field
    coordinates = findOrCreateFieldCoordinates(fm)
    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)
    if useCubicHermiteThroughWall:
        nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                              Node.VALUE_LABEL_D_DS3, 1)
        if useCrossDerivatives:
            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)

    mesh = fm.findMeshByDimension(3)

    if useCubicHermiteThroughWall:
        eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives)
    else:
        eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives)
    eft = eftfactory.createEftBasic()

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

    if xFlat:
        # Flat coordinates field
        bicubichermitelinear = eftfactory_bicubichermitelinear(
            mesh, useCrossDerivatives)
        eftFlat1 = bicubichermitelinear.createEftBasic()
        eftFlat2 = bicubichermitelinear.createEftOpenTube()

        flatCoordinates = findOrCreateFieldCoordinates(fm,
                                                       name="flat coordinates")
        flatNodetemplate1 = nodes.createNodetemplate()
        flatNodetemplate1.defineField(flatCoordinates)
        flatNodetemplate1.setValueNumberOfVersions(flatCoordinates, -1,
                                                   Node.VALUE_LABEL_VALUE, 1)
        flatNodetemplate1.setValueNumberOfVersions(flatCoordinates, -1,
                                                   Node.VALUE_LABEL_D_DS1, 1)
        flatNodetemplate1.setValueNumberOfVersions(flatCoordinates, -1,
                                                   Node.VALUE_LABEL_D_DS2, 1)
        if useCrossDerivatives:
            flatNodetemplate1.setValueNumberOfVersions(
                flatCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1)

        flatNodetemplate2 = nodes.createNodetemplate()
        flatNodetemplate2.defineField(flatCoordinates)
        flatNodetemplate2.setValueNumberOfVersions(flatCoordinates, -1,
                                                   Node.VALUE_LABEL_VALUE, 2)
        flatNodetemplate2.setValueNumberOfVersions(flatCoordinates, -1,
                                                   Node.VALUE_LABEL_D_DS1, 2)
        flatNodetemplate2.setValueNumberOfVersions(flatCoordinates, -1,
                                                   Node.VALUE_LABEL_D_DS2, 2)
        if useCrossDerivatives:
            flatNodetemplate2.setValueNumberOfVersions(
                flatCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 2)

        flatElementtemplate1 = mesh.createElementtemplate()
        flatElementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE)
        flatElementtemplate1.defineField(flatCoordinates, -1, eftFlat1)

        flatElementtemplate2 = mesh.createElementtemplate()
        flatElementtemplate2.setElementShapeType(Element.SHAPE_TYPE_CUBE)
        flatElementtemplate2.defineField(flatCoordinates, -1, eftFlat2)

    if xOrgan:
        # Organ coordinates field
        bicubichermitelinear = eftfactory_bicubichermitelinear(
            mesh, useCrossDerivatives)
        eftOrgan = bicubichermitelinear.createEftBasic()

        organCoordinates = findOrCreateFieldCoordinates(
            fm, name=organCoordinateFieldName)
        organNodetemplate = nodes.createNodetemplate()
        organNodetemplate.defineField(organCoordinates)
        organNodetemplate.setValueNumberOfVersions(organCoordinates, -1,
                                                   Node.VALUE_LABEL_VALUE, 1)
        organNodetemplate.setValueNumberOfVersions(organCoordinates, -1,
                                                   Node.VALUE_LABEL_D_DS1, 1)
        organNodetemplate.setValueNumberOfVersions(organCoordinates, -1,
                                                   Node.VALUE_LABEL_D_DS2, 1)
        if useCrossDerivatives:
            organNodetemplate.setValueNumberOfVersions(
                organCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1)

        organElementtemplate = mesh.createElementtemplate()
        organElementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE)
        organElementtemplate.defineField(organCoordinates, -1, eftOrgan)

    # Create nodes
    # Coordinates field
    for n in range(len(x)):
        node = nodes.createNode(nodeIdentifier, nodetemplate)
        cache.setNode(node)
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1,
                                      x[n])
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1,
                                      d1[n])
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1,
                                      d2[n])
        coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1,
                                      d3[n])
        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)
        # print('NodeIdentifier = ', nodeIdentifier, x[n], d1[n], d2[n])
        nodeIdentifier = nodeIdentifier + 1

    # Flat coordinates field
    if xFlat:
        nodeIdentifier = firstNodeIdentifier
        for n2 in range(elementsCountAlong + 1):
            for n3 in range(elementsCountThroughWall + 1):
                for n1 in range(elementsCountAround):
                    i = n2 * (elementsCountAround +
                              1) * (elementsCountThroughWall +
                                    1) + (elementsCountAround + 1) * n3 + n1
                    node = nodes.findNodeByIdentifier(nodeIdentifier)
                    node.merge(flatNodetemplate2 if n1 ==
                               0 else flatNodetemplate1)
                    cache.setNode(node)
                    # print('NodeIdentifier', nodeIdentifier, 'version 1, xList Index =', i+1)
                    flatCoordinates.setNodeParameters(cache, -1,
                                                      Node.VALUE_LABEL_VALUE,
                                                      1, xFlat[i])
                    flatCoordinates.setNodeParameters(cache, -1,
                                                      Node.VALUE_LABEL_D_DS1,
                                                      1, d1Flat[i])
                    flatCoordinates.setNodeParameters(cache, -1,
                                                      Node.VALUE_LABEL_D_DS2,
                                                      1, d2Flat[i])
                    if useCrossDerivatives:
                        flatCoordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero)
                    if n1 == 0:
                        # print('NodeIdentifier', nodeIdentifier, 'version 2, xList Index =', i+elementsCountAround+1)
                        flatCoordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_VALUE, 2,
                            xFlat[i + elementsCountAround])
                        flatCoordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_D_DS1, 2,
                            d1Flat[i + elementsCountAround])
                        flatCoordinates.setNodeParameters(
                            cache, -1, Node.VALUE_LABEL_D_DS2, 2,
                            d2Flat[i + elementsCountAround])
                        if useCrossDerivatives:
                            flatCoordinates.setNodeParameters(
                                cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 2, zero)
                    nodeIdentifier = nodeIdentifier + 1

    # Organ coordinates field
    if xOrgan:
        nodeIdentifier = firstNodeIdentifier
        for n in range(len(xOrgan)):
            node = nodes.findNodeByIdentifier(nodeIdentifier)
            node.merge(organNodetemplate)
            cache.setNode(node)
            organCoordinates.setNodeParameters(cache, -1,
                                               Node.VALUE_LABEL_VALUE, 1,
                                               xOrgan[n])
            organCoordinates.setNodeParameters(cache, -1,
                                               Node.VALUE_LABEL_D_DS1, 1,
                                               d1Organ[n])
            organCoordinates.setNodeParameters(cache, -1,
                                               Node.VALUE_LABEL_D_DS2, 1,
                                               d2Organ[n])
            if useCrossDerivatives:
                organCoordinates.setNodeParameters(cache, -1,
                                                   Node.VALUE_LABEL_D2_DS1DS2,
                                                   1, zero)
            nodeIdentifier = nodeIdentifier + 1

    # create elements
    elementtemplate3 = mesh.createElementtemplate()
    elementtemplate3.setElementShapeType(Element.SHAPE_TYPE_CUBE)
    radiansPerElementAround = math.pi * 2.0 / elementsCountAround

    allAnnotationGroups = []

    if closedProximalEnd:
        # Create apex
        for e3 in range(elementsCountThroughWall):
            for e1 in range(elementsCountAround):
                va = e1
                vb = (e1 + 1) % elementsCountAround
                eft1 = eftfactory.createEftShellPoleBottom(va * 100, vb * 100)
                elementtemplate3.defineField(coordinates, -1, eft1)
                element = mesh.createElement(elementIdentifier,
                                             elementtemplate3)
                bni1 = e3 + 1
                bni2 = elementsCountThroughWall + 1 + elementsCountAround * e3 + e1 + 1
                bni3 = elementsCountThroughWall + 1 + elementsCountAround * e3 + (
                    e1 + 1) % elementsCountAround + 1
                nodeIdentifiers = [
                    bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAround,
                    bni3 + elementsCountAround
                ]
                element.setNodesByIdentifier(eft1, nodeIdentifiers)
                # set general linear map coefficients
                radiansAround = e1 * radiansPerElementAround
                radiansAroundNext = (
                    (e1 + 1) % elementsCountAround) * radiansPerElementAround
                scalefactors = [
                    -1.0,
                    math.sin(radiansAround),
                    math.cos(radiansAround), radiansPerElementAround,
                    math.sin(radiansAroundNext),
                    math.cos(radiansAroundNext), radiansPerElementAround,
                    math.sin(radiansAround),
                    math.cos(radiansAround), radiansPerElementAround,
                    math.sin(radiansAroundNext),
                    math.cos(radiansAroundNext), radiansPerElementAround
                ]
                result = element.setScaleFactors(eft1, scalefactors)
                elementIdentifier = elementIdentifier + 1
                annotationGroups = annotationGroupsAround[e1] + annotationGroupsAlong[0] + \
                                   annotationGroupsThroughWall[e3]
                if annotationGroups:
                    allAnnotationGroups = mergeAnnotationGroups(
                        allAnnotationGroups, annotationGroups)
                    for annotationGroup in annotationGroups:
                        meshGroup = annotationGroup.getMeshGroup(mesh)
                        meshGroup.addElement(element)

    # Create regular elements
    now = elementsCountAround * (elementsCountThroughWall + 1)
    for e2 in range(1 if closedProximalEnd else 0, elementsCountAlong):
        for e3 in range(elementsCountThroughWall):
            for e1 in range(elementsCountAround):
                if closedProximalEnd:
                    bni11 = (e2 -
                             1) * now + e3 * elementsCountAround + e1 + 1 + (
                                 elementsCountThroughWall + 1)
                    bni12 = (e2-1) * now + e3 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 + \
                            (elementsCountThroughWall + 1)
                    bni21 = (e2 - 1) * now + (
                        e3 + 1) * elementsCountAround + e1 + 1 + (
                            elementsCountThroughWall + 1)
                    bni22 = (e2-1) * now + (e3 + 1) * elementsCountAround + (e1 + 1) % elementsCountAround + 1 + \
                            (elementsCountThroughWall + 1)
                else:
                    bni11 = e2 * now + e3 * elementsCountAround + e1 + 1
                    bni12 = e2 * now + e3 * elementsCountAround + (
                        e1 + 1) % elementsCountAround + 1
                    bni21 = e2 * now + (e3 + 1) * elementsCountAround + e1 + 1
                    bni22 = e2 * now + (e3 + 1) * elementsCountAround + (
                        e1 + 1) % elementsCountAround + 1
                nodeIdentifiers = [
                    bni11, bni12, bni11 + now, bni12 + now, bni21, bni22,
                    bni21 + now, bni22 + now
                ]
                onOpening = e1 > elementsCountAround - 2
                element = mesh.createElement(elementIdentifier,
                                             elementtemplate)
                element.setNodesByIdentifier(eft, nodeIdentifiers)
                if xFlat:
                    element.merge(flatElementtemplate2
                                  if onOpening else flatElementtemplate1)
                    element.setNodesByIdentifier(
                        eftFlat2 if onOpening else eftFlat1, nodeIdentifiers)
                if xOrgan:
                    element.merge(organElementtemplate)
                    element.setNodesByIdentifier(eftOrgan, nodeIdentifiers)
                elementIdentifier = elementIdentifier + 1

                annotationGroups = annotationGroupsAround[e1] + annotationGroupsAlong[e2] + \
                                   annotationGroupsThroughWall[e3]
                if annotationGroups:
                    allAnnotationGroups = mergeAnnotationGroups(
                        allAnnotationGroups, annotationGroups)
                    for annotationGroup in annotationGroups:
                        meshGroup = annotationGroup.getMeshGroup(mesh)
                        meshGroup.addElement(element)

    fm.endChange()

    return nodeIdentifier, elementIdentifier, allAnnotationGroups