コード例 #1
0
    def createEftTetrahedronXi1Zero(self, nodeScaleFactorOffset0,
                                    nodeScaleFactorOffset1):
        '''
        Create a bicubic hermite linear element field for a solid tetrahedron for the apex of cecum,
        with xi1 and xi3 collapsed on xi2 = 0, and xi3 collapsed on xi1 = 0, xi2 = 1.
        Each collapsed node on xi2 = 0 has 3 scale factors giving the cos, sin coefficients of
        the radial line from global derivatives, plus the arc subtended by the element in radians,
        so the circumferential direction is rounded.
        Need to create a new template for each sector around axis giving common
        nodeScaleFactorOffset values on common faces. Suggestion is to start at 0 and
        add 10000 for each radial line around axis.
        :param nodeScaleFactorOffset0: offset of node scale factors at axis on xi1=0
        :param nodeScaleFactorOffset1: offset of node scale factors at axis on xi1=1
        :return: Element field template
        '''
        # start with full bicubic hermite linear
        eft = self._mesh.createElementfieldtemplate(self._basis)
        for n in [2, 3, 6, 7]:
            eft.setFunctionNumberOfTerms(n * 4 + 4, 0)

        # GRC: allow scale factor identifier for global -1.0 to be prescribed
        setEftScaleFactorIds(eft, [1], [
            nodeScaleFactorOffset0 + 1, nodeScaleFactorOffset0 + 2,
            nodeScaleFactorOffset0 + 3, nodeScaleFactorOffset1 + 1,
            nodeScaleFactorOffset1 + 2, nodeScaleFactorOffset1 + 3
        ])

        # remap parameters on xi2 = 0 before collapsing nodes
        remapEftNodeValueLabel(eft, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [])

        for layer in range(2):
            soAround = 1
            ln = layer * 4 + 1
            # 2 terms for d/dxi2 via general linear map:
            remapEftNodeValueLabel(eft, [ln], Node.VALUE_LABEL_D_DS2,
                                   [(Node.VALUE_LABEL_D_DS1, [soAround + 1]),
                                    (Node.VALUE_LABEL_D_DS2, [soAround + 2])])
            # 2 terms for cross derivative 1 2 to correct circular apex: cos(theta).phi, -sin(theta).phi
            remapEftNodeValueLabel(
                eft, [ln], Node.VALUE_LABEL_D2_DS1DS2,
                [(Node.VALUE_LABEL_D_DS1, [soAround + 2, soAround + 3]),
                 (Node.VALUE_LABEL_D_DS2, [1, soAround + 1, soAround + 3])])

            ln = layer * 4 + 2
            # 2 terms for d/dxi2 via general linear map:
            remapEftNodeValueLabel(eft, [ln], Node.VALUE_LABEL_D_DS2,
                                   [(Node.VALUE_LABEL_D_DS1, [soAround + 4]),
                                    (Node.VALUE_LABEL_D_DS2, [soAround + 5])])
            # 2 terms for cross derivative 1 2 to correct circular apex: cos(theta).phi, -sin(theta).phi
            remapEftNodeValueLabel(
                eft, [ln], Node.VALUE_LABEL_D2_DS1DS2,
                [(Node.VALUE_LABEL_D_DS1, [soAround + 5, soAround + 6]),
                 (Node.VALUE_LABEL_D_DS2, [1, soAround + 4, soAround + 6])])

        ln_map = [1, 1, 2, 3, 1, 1, 2, 4]
        remapEftLocalNodes(eft, 4, ln_map)

        assert eft.validate(
        ), 'eftfactory_bicubichermitelinear.createEftTetrahedronXi1Zero:  Failed to validate eft'
        return eft
 def createEftWedgeXi1Zero(self):
     '''
     Create a basic bicubic hermite linear element template for elements
     along boundary of tenia coli where nodes on xi1 = 0 are collapsed.
     :return: Element field template
     '''
     eft = self.createEftBasic()
     ln_map = [1, 2, 3, 4, 1, 5, 3, 6]
     remapEftLocalNodes(eft, 6, ln_map)
     assert eft.validate(
     ), 'eftfactory_tricubichermite.createEftWedgeXi1Zero:  Failed to validate eft'
     return eft
 def createEftWedgeXi1ZeroOpenTube(self):
     '''
     Create a basic bicubic hermite linear element template for elements
     along boundary of tenia coli where nodes on xi1 = 0 are collapsed
     where a tube is opened on xi1 = 1 for a flat preparation.
     :return: Element field template
     '''
     eft = self.createEftBasic()
     for n in [1, 3, 5, 7]:
         ln = n + 1
         eft.setTermNodeParameter(n * 4 + 1, 1, ln, Node.VALUE_LABEL_VALUE,
                                  2)
         eft.setTermNodeParameter(n * 4 + 2, 1, ln, Node.VALUE_LABEL_D_DS1,
                                  2)
         eft.setTermNodeParameter(n * 4 + 3, 1, ln, Node.VALUE_LABEL_D_DS2,
                                  2)
         if self._useCrossDerivatives:
             eft.setTermNodeParameter(n * 4 + 4, 1, ln,
                                      Node.VALUE_LABEL_D2_DS1DS2, 2)
     ln_map = [1, 2, 3, 4, 1, 5, 3, 6]
     remapEftLocalNodes(eft, 6, ln_map)
     assert eft.validate(
     ), 'eftfactory_tricubichermite.createEftWedgeXi1ZeroOpenTube:  Failed to validate eft'
     return eft
    def createEftShellPoleBottom(self, nodeScaleFactorOffset0,
                                 nodeScaleFactorOffset1):
        '''
        Create a bicubic hermite linear element field for closing bottom pole of a shell.
        Element is collapsed in xi1 on xi2 = 0.
        Each collapsed node has 3 scale factors giving the cos, sin coefficients
        of the radial line from global derivatives, plus the arc subtended by
        the element in radians, so the pole can be rounded.
        Need to create a new template for each sector around pole giving common
        nodeScaleFactorOffset values on common faces. Suggestion is to start at 0 and
        add 100 for each radial line around pole.
        :param nodeScaleFactorOffset0: offset of node scale factors at pole on xi1=0
        :param nodeScaleFactorOffset1: offset of node scale factors at pole on xi1=1
        :return: Element field template
        '''
        # start with full bicubic hermite linear to remap D2_DS1DS2 at pole
        eft = self._mesh.createElementfieldtemplate(self._basis)
        if not self._useCrossDerivatives:
            for n in [2, 3, 6, 7]:
                eft.setFunctionNumberOfTerms(n * 4 + 4, 0)

        # GRC: allow scale factor identifier for global -1.0 to be prescribed
        setEftScaleFactorIds(eft, [1], [
            nodeScaleFactorOffset0 + 1, nodeScaleFactorOffset0 + 2,
            nodeScaleFactorOffset0 + 3, nodeScaleFactorOffset1 + 1,
            nodeScaleFactorOffset1 + 2, nodeScaleFactorOffset1 + 3,
            nodeScaleFactorOffset0 + 1, nodeScaleFactorOffset0 + 2,
            nodeScaleFactorOffset0 + 3, nodeScaleFactorOffset1 + 1,
            nodeScaleFactorOffset1 + 2, nodeScaleFactorOffset1 + 3
        ])
        # remap parameters before collapsing nodes
        remapEftNodeValueLabel(eft, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [])
        for layer in range(2):
            so = layer * 6 + 1
            ln = layer * 4 + 1
            # 2 terms for d/dxi2 via general linear map:
            remapEftNodeValueLabel(eft, [ln], Node.VALUE_LABEL_D_DS2,
                                   [(Node.VALUE_LABEL_D_DS1, [so + 1]),
                                    (Node.VALUE_LABEL_D_DS2, [so + 2])])
            # 2 terms for cross derivative 1 2 to correct circular pole: -sin(theta).phi, cos(theta).phi
            remapEftNodeValueLabel(
                eft, [ln], Node.VALUE_LABEL_D2_DS1DS2,
                [(Node.VALUE_LABEL_D_DS1, [so + 2, so + 3]),
                 (Node.VALUE_LABEL_D_DS2, [1, so + 1, so + 3])])

            ln = layer * 4 + 2
            # 2 terms for d/dxi2 via general linear map:
            remapEftNodeValueLabel(eft, [ln], Node.VALUE_LABEL_D_DS2,
                                   [(Node.VALUE_LABEL_D_DS1, [so + 4]),
                                    (Node.VALUE_LABEL_D_DS2, [so + 5])])
            # 2 terms for cross derivative 1 2 to correct circular pole: -sin(theta).phi, cos(theta).phi
            remapEftNodeValueLabel(
                eft, [ln], Node.VALUE_LABEL_D2_DS1DS2,
                [(Node.VALUE_LABEL_D_DS1, [so + 5, so + 6]),
                 (Node.VALUE_LABEL_D_DS2, [1, so + 4, so + 6])])

        ln_map = [1, 1, 2, 3, 4, 4, 5, 6]
        remapEftLocalNodes(eft, 6, ln_map)

        assert eft.validate(
        ), 'eftfactory_tricubichermite.createEftShellPoleBottom:  Failed to validate eft'
        return eft
コード例 #5
0
    def generateBaseMesh(cls, region, options):
        """
        Generate the base tricubic Hermite mesh. See also generateMesh().
        :param region: Zinc region to define model in. Must be empty.
        :param options: Dict containing options. See getDefaultOptions().
        :return: None
        """
        parameterSetName = options['Base parameter set']
        isDefault = 'Default' in parameterSetName
        isMouse = 'Mouse' in parameterSetName
        isMean = 'mean' in parameterSetName

        fm = region.getFieldmodule()
        nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
        coordinates = findOrCreateFieldCoordinates(fm)
        mesh = fm.findMeshByDimension(3)
        cache = fm.createFieldcache()
        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)

        armCount = 3
        elementLengthCentral = options['Element width central']
        elementLengths = [
            options['Element length along arm'],
            options['Element width across arm'], options['Element thickness']
        ]
        elementsCountsAlongArms = options['Numbers of elements along arms']
        elementsCount2 = 2
        elementsCount3 = 1
        useCrossDerivatives = False
        # arm group annotations for user
        armTerms, _ = getAutomaticArmFaceTerms(armCount)
        armGroups = [AnnotationGroup(region, armTerm) for armTerm in armTerms]
        stellateTerm = get_stellate_term(
            "cervicothoracic ganglion") if isMouse else ("stellate", None)
        stellateGroup = AnnotationGroup(region, stellateTerm)
        annotationGroups = [stellateGroup] + armGroups
        armMeshGroups = [a.getMeshGroup(mesh) for a in armGroups]
        stellateMeshGroup = stellateGroup.getMeshGroup(mesh)

        # markers with element number and xi position
        allMarkers = {}
        if isMouse:
            xProportion = {}
            xProportion['ICN'] = 0.9
            xProportion['VA'] = 0.9
            xProportion['DA'] = 0.9
            xProportion['C8'] = 0.9
            xProportion['T1'] = 0.25
            xProportion['T2'] = 0.5
            xProportion['T3'] = 0.75
            xProportion['TST'] = 1
            armNumber = {}
            armNumber['ICN'] = 2
            armNumber['VA'] = 2
            armNumber['DA'] = 3
            armNumber['C8'] = 3
            armNumber['T1'] = 1
            armNumber['T2'] = 1
            armNumber['T3'] = 1
            armNumber['TST'] = 1
            nerveAbbrev = list(xProportion.keys())
            elementIndex = {}
            xi1 = {}
            for nerve in nerveAbbrev:
                elementIndex[nerve] = int(
                    xProportion[nerve] *
                    elementsCountsAlongArms[armNumber[nerve] - 1])
                xi1[nerve] = 1 if xProportion[nerve] == 1 else xProportion[
                    nerve] * elementsCountsAlongArms[armNumber[nerve] -
                                                     1] - elementIndex[nerve]
                elementIndex[nerve] += 1 if xProportion[nerve] < 1 else 0

            allMarkers = {
                "Inferior cardiac nerve": {
                    "elementID":
                    elementIndex['ICN'] + 2 * elementsCountsAlongArms[0],
                    "xi": [xi1['ICN'], 0.0, 0.5]
                },
                "Ventral ansa subclavia": {
                    "elementID":
                    elementIndex['VA'] + 2 * elementsCountsAlongArms[0] +
                    elementsCountsAlongArms[1],
                    "xi": [xi1['VA'], 1.0, 0.5]
                },
                "Dorsal ansa subclavia": {
                    "elementID":
                    elementIndex['DA'] + 2 *
                    (elementsCountsAlongArms[0] + elementsCountsAlongArms[1]),
                    "xi": [xi1['DA'], 0.0, 0.5]
                },
                "Cervical spinal nerve 8": {
                    "elementID":
                    elementIndex['C8'] + 2 *
                    (elementsCountsAlongArms[0] + elementsCountsAlongArms[1]) +
                    elementsCountsAlongArms[2],
                    "xi": [xi1['C8'], 1.0, 0.5]
                },
                "Thoracic spinal nerve 1": {
                    "elementID": elementIndex['T1'],
                    "xi": [xi1['T1'], 0.0, 0.5]
                },
                "Thoracic spinal nerve 2": {
                    "elementID": elementIndex['T2'],
                    "xi": [xi1['T2'], 0.0, 0.5]
                },
                "Thoracic spinal nerve 3": {
                    "elementID": elementIndex['T3'],
                    "xi": [xi1['T3'], 0.0, 0.5]
                },
                "Thoracic sympathetic nerve trunk": {
                    "elementID": elementIndex['TST'],
                    "xi": [xi1['TST'], 1.0, 0.5]
                },
            }
            markerGroup = findOrCreateFieldGroup(fm, "marker")
            markerName = findOrCreateFieldStoredString(fm, name="marker_name")
            markerLocation = findOrCreateFieldStoredMeshLocation(
                fm, mesh, name="marker_location")

            markerPoints = findOrCreateFieldNodeGroup(markerGroup,
                                                      nodes).getNodesetGroup()
            markerTemplateInternal = nodes.createNodetemplate()
            markerTemplateInternal.defineField(markerName)
            markerTemplateInternal.defineField(markerLocation)

        # Create nodes
        nodeIdentifier = 1
        minArmAngle = 2 * math.pi / armCount
        halfArmArcAngleRadians = minArmAngle / 2
        if not isMean:
            dipMultiplier = 1
            for na in range(armCount):
                elementsCount_i = [
                    elementsCountsAlongArms[na], elementsCount2, elementsCount3
                ]
                x, ds1, ds2, nWheelEdge = createArm(halfArmArcAngleRadians,
                                                    elementLengths,
                                                    elementLengthCentral,
                                                    elementsCount_i,
                                                    dipMultiplier, armCount,
                                                    na)
                for ix in range(len(x)):
                    if na == 0 or ix not in nWheelEdge:
                        node = nodes.createNode(nodeIdentifier, nodetemplate)
                        cache.setNode(node)
                        coordinates.setNodeParameters(cache, -1,
                                                      Node.VALUE_LABEL_VALUE,
                                                      1, x[ix])
                        coordinates.setNodeParameters(cache, -1,
                                                      Node.VALUE_LABEL_D_DS1,
                                                      1, ds1[ix])
                        coordinates.setNodeParameters(cache, -1,
                                                      Node.VALUE_LABEL_D_DS2,
                                                      1, ds2[ix])
                        nodeIdentifier += 1
        else:
            x_dx_all = cls.mouseMeanMesh['meshEdits']
            xyz_all = [x[0] for x in x_dx_all]
            dxyz = [[x[1], x[2]] for x in x_dx_all]
            nodeIdentifier = 1
            for i, nx in enumerate(xyz_all):
                node = nodes.createNode(nodeIdentifier, nodetemplate)
                cache.setNode(node)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_VALUE, 1, nx)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS1, 1,
                                              dxyz[i][0])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS2, 1,
                                              dxyz[i][1])
                nodeIdentifier += 1
        nodesCountsPerArm = [0] + [((elementsCount2 + 1) * e + 1) * 2
                                   for e in elementsCountsAlongArms]

        # Create elements
        bicubichermitelinear = eftfactory_bicubichermitelinear(
            mesh, useCrossDerivatives)
        eft = bicubichermitelinear.createEftNoCrossDerivatives(
        )  #createEftBasic()
        elementtemplate = mesh.createElementtemplate()
        elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE)
        elementtemplate.defineField(coordinates, -1, eft)
        elementtemplateX = mesh.createElementtemplate()
        elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE)
        elementIdentifier = 1

        cumNodesCountsPerArm = [
            sum(nodesCountsPerArm[:i + 1])
            for i in range(len(nodesCountsPerArm))
        ]
        nCentre = [
            elementsCountsAlongArms[0] + 1,
            int(nodesCountsPerArm[1] / 2) + elementsCountsAlongArms[0] + 1
        ]
        for na in range(armCount):
            for e3 in range(elementsCount3):
                for e2 in range(elementsCount2):
                    for e1 in range(elementsCountsAlongArms[na]):
                        scalefactors = None
                        ### NODES ###
                        no2 = (elementsCountsAlongArms[na] + 1)
                        no3 = (elementsCount2 + 1) * no2 - 2
                        offset = (cumNodesCountsPerArm[na])
                        bni = e3 * no3 + e2 * no2 + e1 + 1 + offset
                        if e2 == 0:
                            if e1 == 0 and na > 0:  # and na < armCount -1: # wheelSouth
                                nWh = cumNodesCountsPerArm[na - 1] + (
                                    2 * elementsCountsAlongArms[na - 1]) + 2
                                nplUq = int(
                                    nodesCountsPerArm[na + 1] / 2
                                ) - elementsCountsAlongArms[
                                    na]  # unused nodes at centre and shared edge
                                npl = int(
                                    nodesCountsPerArm[na + 1] /
                                    2)  #  nodes at centre and shared edge
                                if na < armCount - 1:
                                    cn = cumNodesCountsPerArm[
                                        na] + elementsCountsAlongArms[na] - 2
                                    no2 = cumNodesCountsPerArm[na]
                                    em = elementsCountsAlongArms[na]
                                    nwPrev = [
                                        nWh,
                                        nWh + int(nodesCountsPerArm[na] / 2)
                                    ]  # previous arm's edge, depends on armCount.
                                    nodeIdentifiers = [
                                        nwPrev[0], no2 + 1, nCentre[0],
                                        no2 + em, nwPrev[1],
                                        no2 + em - 1 + nplUq, nCentre[1],
                                        bni + (4 * em) - 2
                                    ]
                                else:
                                    nplPrev = int(
                                        nodesCountsPerArm[na] / 2) - 2
                                    no2 = elementsCountsAlongArms[na] - 1
                                    no3 = int(
                                        nodesCountsPerArm[na + 1] / 2) - 3
                                    nwPrev = [
                                        cumNodesCountsPerArm[na - 1] + 2 *
                                        (elementsCountsAlongArms[na - 1]),
                                        cumNodesCountsPerArm[na - 1] + 2 *
                                        (elementsCountsAlongArms[na - 1]) +
                                        nplPrev
                                    ]
                                    start = cumNodesCountsPerArm[na] - 3
                                    nodeIdentifiers = [
                                        nwPrev[0], start, nCentre[0],
                                        start + no2, nwPrev[1], start + no3,
                                        nCentre[1], start + no2 + no3
                                    ]
                            elif e1 == elementsCountsAlongArms[
                                    na] - 1:  # armEnd, south
                                if na == 0:
                                    nodeIdentifiers = [
                                        bni, bni + no2 - 1, bni + no2,
                                        bni + no3, bni + no2 + no3 - 1,
                                        bni + no2 + no3
                                    ]
                                else:
                                    no3 = armCount * elementsCountsAlongArms[
                                        na] - 1
                                    no2 = elementsCountsAlongArms[na]
                                    if na > 1:
                                        bni -= 4
                                        no3 -= 1
                                    nodeIdentifiers = [
                                        bni - 1, bni + no2 - 2, bni + no2 - 1,
                                        bni + no3 - 1, bni + no2 - 2 + no3,
                                        bni + no2 + no3 - 1
                                    ]
                            elif na > 0 and e1 > 0:  #  [na=1+, e1=1+, e2=0] for len=3+
                                bni -= 1 + ((armCount + 1) * (na - 1))
                                no2 = elementsCountsAlongArms[na]
                                no3 = armCount * no2 - (na - 1) - 1
                                nodeIdentifiers = [
                                    bni, bni + 1, bni + no2 - 1, bni + no2,
                                    bni + no3, bni + no3 + 1,
                                    bni + no2 + no3 - 1, bni + no2 + no3
                                ]
                            else:
                                nodeIdentifiers = [
                                    bni, bni + 1, bni + no2 - 1, bni + no2,
                                    bni + no3, bni + no3 + 1,
                                    bni + no2 + no3 - 1, bni + no2 + no3
                                ]
                        else:
                            if e1 == 0 and na > 0:  # and na < armCount -1: # wheelNorth
                                if na < armCount - 1:
                                    bni -= armCount
                                    npl = int(
                                        nodesCountsPerArm[na + 1] / 2) - 2
                                    no2 = elementsCountsAlongArms[na]
                                    nodeIdentifiers = [
                                        nCentre[0], bni + 1, bni + no2 + 1,
                                        bni + no2 + 2, nCentre[1],
                                        bni + npl + 1, bni + npl + no2 + 1,
                                        bni + npl + no2 + 2
                                    ]
                                else:  # last arm
                                    bni = cumNodesCountsPerArm[na] - 2 - (
                                        armCount - elementsCountsAlongArms[na])
                                    nodeIdentifiers = [
                                        nCentre[0], bni + 1, 1, bni + no2,
                                        nCentre[1], bni + no3 - 2,
                                        int(nodesCountsPerArm[1] / 2) + 1,
                                        bni + no2 + no3 - armCount
                                    ]
                            elif e1 == elementsCountsAlongArms[
                                    na] - 1:  # armEnd north
                                if na > 0:
                                    no2 = elementsCountsAlongArms[na]
                                    nplUq = int(
                                        nodesCountsPerArm[na + 1] / 2) - 2
                                    if na > 1:
                                        adj = na - 1
                                        bni -= armCount * na + (
                                            armCount -
                                            elementsCountsAlongArms[na]) + 1
                                        if elementsCountsAlongArms[na] < 3:
                                            bni += 1
                                        if elementsCountsAlongArms[na] > 3:
                                            bni -= elementsCountsAlongArms[
                                                na] - 3
                                        no2 += 1 - adj
                                        no3 = nplUq - adj
                                        nodeIdentifiers = [
                                            bni, bni + 1, bni + no2, bni + no3,
                                            bni + no3 + 1, bni + no2 + no3
                                        ]
                                    else:
                                        bni -= armCount
                                        nodeIdentifiers = [
                                            bni, bni + 1, bni + no2 + 1,
                                            bni + nplUq, bni + nplUq + 1,
                                            bni + no2 + nplUq + 1
                                        ]
                                else:
                                    nodeIdentifiers = [
                                        bni - 1, bni, bni + no2 - 1,
                                        bni + no3 - 1, bni + no3,
                                        bni + no2 + no3 - 1
                                    ]

                            elif na > 0 and e1 > 0:  #  [na=1+, e1=1+, e2=1] for len=3+
                                adj = na - 1
                                bni -= armCount * na + adj
                                no2 -= adj
                                k = armCount * elementsCountsAlongArms[na] - na
                                nodeIdentifiers = [
                                    bni, bni + 1, bni + no2, bni + no2 + 1,
                                    bni + k, bni + k + 1, bni + no2 + k,
                                    bni + no2 + k + 1
                                ]
                            else:
                                nodeIdentifiers = [
                                    bni - 1, bni, bni + no2 - 1, bni + no2,
                                    bni + no3 - 1, bni + no3,
                                    bni + no2 + no3 - 1, bni + no2 + no3
                                ]

                        if e1 == 0:  # wheel
                            eft1 = bicubichermitelinear.createEftNoCrossDerivatives(
                            )
                            if armCount == 3:
                                if e2 == 0:
                                    setEftScaleFactorIds(eft1, [1], [])
                                    scalefactors = [-1.0]
                                    scaleEftNodeValueLabels(
                                        eft1, [1, 5], [
                                            Node.VALUE_LABEL_D_DS1,
                                            Node.VALUE_LABEL_D_DS2
                                        ], [1])
                                    ns = [3, 7]
                                else:
                                    ns = [1, 5]
                                if na == 0:
                                    remapEftNodeValueLabel(
                                        eft1, ns, Node.VALUE_LABEL_D_DS1,
                                        [(Node.VALUE_LABEL_D_DS1, []),
                                         (Node.VALUE_LABEL_D_DS2, [])])
                                    if e2 == 0:
                                        setEftScaleFactorIds(eft1, [1], [])
                                        scalefactors = [-1.0]
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, [1])])
                                elif na == 1:
                                    setEftScaleFactorIds(eft1, [1], [])
                                    scalefactors = [-1.0]
                                    remapEftNodeValueLabel(
                                        eft1, ns, Node.VALUE_LABEL_D_DS1,
                                        [(Node.VALUE_LABEL_D_DS1, [1])])
                                    if e2 == 0:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS2, [1])])
                                    elif e2 == 1:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, [1]),
                                             (Node.VALUE_LABEL_D_DS2, [1])])
                                elif na == 2:
                                    setEftScaleFactorIds(eft1, [1], [])
                                    scalefactors = [-1.0]
                                    remapEftNodeValueLabel(
                                        eft1, ns, Node.VALUE_LABEL_D_DS1,
                                        [(Node.VALUE_LABEL_D_DS2, [1])])
                                    if e2 == 0:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, []),
                                             (Node.VALUE_LABEL_D_DS2, [])])
                                    elif e2 == 1:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, [])])
                            elif armCount == 4:
                                if e2 == 0:
                                    setEftScaleFactorIds(eft1, [1], [])
                                    scalefactors = [-1.0]
                                    scaleEftNodeValueLabels(
                                        eft1, [1, 5], [
                                            Node.VALUE_LABEL_D_DS1,
                                            Node.VALUE_LABEL_D_DS2
                                        ], [1])
                                    ns = [3, 7]
                                else:
                                    ns = [1, 5]
                                if na == 0:
                                    remapEftNodeValueLabel(
                                        eft1, ns, Node.VALUE_LABEL_D_DS1,
                                        [(Node.VALUE_LABEL_D_DS1, []),
                                         (Node.VALUE_LABEL_D_DS2, [])])
                                    if e2 == 0:
                                        setEftScaleFactorIds(eft1, [1], [])
                                        scalefactors = [-1.0]
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, [1])])
                                elif na == 1:
                                    setEftScaleFactorIds(eft1, [1], [])
                                    scalefactors = [-1.0]
                                    remapEftNodeValueLabel(
                                        eft1, ns, Node.VALUE_LABEL_D_DS1,
                                        [(Node.VALUE_LABEL_D_DS1, [1]),
                                         (Node.VALUE_LABEL_D_DS2, [])])
                                    if e2 == 0:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS2, [1])])
                                    else:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, [1])])
                                elif na == 2:
                                    setEftScaleFactorIds(eft1, [1], [])
                                    scalefactors = [-1.0]
                                    remapEftNodeValueLabel(
                                        eft1, ns, Node.VALUE_LABEL_D_DS1,
                                        [(Node.VALUE_LABEL_D_DS1, [1]),
                                         (Node.VALUE_LABEL_D_DS2, [1])])
                                    if e2 == 0:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, [])])
                                    else:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS2, [1])])
                                elif na == 3:
                                    setEftScaleFactorIds(eft1, [1], [])
                                    scalefactors = [-1.0]
                                    remapEftNodeValueLabel(
                                        eft1, ns, Node.VALUE_LABEL_D_DS1,
                                        [(Node.VALUE_LABEL_D_DS1, []),
                                         (Node.VALUE_LABEL_D_DS2, [1])])
                                    if e2 == 0:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS2, [])])
                                    else:
                                        remapEftNodeValueLabel(
                                            eft1, ns, Node.VALUE_LABEL_D_DS2,
                                            [(Node.VALUE_LABEL_D_DS1, [])])

                        elif e1 < (elementsCountsAlongArms[na] - 1):
                            eft1 = eft
                            elementtemplate1 = elementtemplate
                        else:
                            # rounded ends of arms. Collapse xi2 at xi1 = 1
                            eft1 = bicubichermitelinear.createEftNoCrossDerivatives(
                            )
                            remapEftNodeValueLabel(eft1, [2, 4, 6, 8],
                                                   Node.VALUE_LABEL_D_DS2, [])
                            if e2 == 0:
                                remapEftNodeValueLabel(
                                    eft1, [2, 6], Node.VALUE_LABEL_D_DS1,
                                    [(Node.VALUE_LABEL_D_DS2, [])])
                                nodeIdentifiers = [
                                    nodeIdentifiers[0], nodeIdentifiers[2],
                                    nodeIdentifiers[1], nodeIdentifiers[3],
                                    nodeIdentifiers[5], nodeIdentifiers[4]
                                ]
                            else:  # e2 == 1
                                setEftScaleFactorIds(eft1, [1], [])
                                scalefactors = [-1.0]
                                remapEftNodeValueLabel(
                                    eft1, [4, 8], Node.VALUE_LABEL_D_DS1,
                                    [(Node.VALUE_LABEL_D_DS2, [1])])
                            ln_map = [1, 2, 3, 2, 4, 5, 6, 5]
                            remapEftLocalNodes(eft1, 6, ln_map)

                        if eft1 is not eft:
                            elementtemplateX.defineField(coordinates, -1, eft1)
                            elementtemplate1 = elementtemplateX

                        element = mesh.createElement(elementIdentifier,
                                                     elementtemplate1)
                        result = element.setNodesByIdentifier(
                            eft1, nodeIdentifiers)
                        result3 = element.setScaleFactors(
                            eft1, scalefactors) if scalefactors else None

                        # add to meshGroup
                        stellateMeshGroup.addElement(element)
                        armMeshGroups[na].addElement(element)

                        elementIdentifier += 1

        # annotation fiducial points
        if isMouse:
            for key in allMarkers:
                xi = allMarkers[key]["xi"]
                addMarker = {"name": key, "xi": allMarkers[key]["xi"]}

                markerPoint = markerPoints.createNode(nodeIdentifier,
                                                      markerTemplateInternal)
                nodeIdentifier += 1
                cache.setNode(markerPoint)
                markerName.assignString(cache, addMarker["name"])
                elementID = allMarkers[key]["elementID"]
                element = mesh.findElementByIdentifier(elementID)
                markerLocation.assignMeshLocation(cache, element,
                                                  addMarker["xi"])

        return annotationGroups
コード例 #6
0
    def generateBaseMesh(cls, region, options):
        """
        Generate the base tricubic Hermite mesh.
        :param region: Zinc region to define model in. Must be empty.
        :param options: Dict containing options. See getDefaultOptions().
        :return: 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
コード例 #7
0
    def createEftWedgeCollapseXi2Quadrant(self, collapseNodes):
        '''
        Create a bicubic hermite linear element field for a wedge element collapsed in xi2.
        :param collapseNodes: As the element can be collapsed in xi2 at either ends of xi1 or xi3, collapseNodes
        are the local indices of nodes whose d1 (for elements collapse at either ends of xi1) or
        d3 (for elements collapse at either ends of xi3) are remapped with d2 before collapsing the nodes.
        :return: Element field template
        '''
        eft = self.createEftBasic()

        valid = True
        if collapseNodes in [[1, 2], [3, 4]]:  # xi3 = 0
            nodes = [1, 2, 3, 4]
            remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
            ln_map = [1, 2, 1, 2, 3, 4, 5, 6]
        elif collapseNodes in [[5, 6], [7, 8]]:  # xi3 = 1
            nodes = [5, 6, 7, 8]
            remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
            ln_map = [1, 2, 3, 4, 5, 6, 5, 6]

        elif collapseNodes in [[3, 7]]:
            nodes = [1, 3, 5, 7]
            # remap parameters on xi1 = 0 before collapsing nodes
            if collapseNodes == [3, 7]:
                remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
                remapEftNodeValueLabel(eft, collapseNodes,
                                       Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS2, [])])
            else:
                valid = False
            ln_map = [1, 2, 1, 3, 4, 5, 4, 6]

        elif collapseNodes in [[2, 6], [4, 8]]:
            nodes = [2, 4, 6, 8]
            # remap parameters on xi1 = 1 before collapsing nodes
            if collapseNodes == [2, 6]:
                remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
                remapEftNodeValueLabel(eft, collapseNodes,
                                       Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS2, [])])
            elif collapseNodes == [4, 8]:
                setEftScaleFactorIds(eft, [1], [])
                remapEftNodeValueLabel(eft, collapseNodes,
                                       Node.VALUE_LABEL_D_DS1,
                                       [(Node.VALUE_LABEL_D_DS2, [1])])
                remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
            else:
                valid = False
            ln_map = [1, 2, 3, 2, 4, 5, 6, 5]

        else:
            valid = False

        if not valid:
            assert False, "createEftWedgeCollapseXi2Quadrant.  Not implemented for collapse nodes " + str(
                collapseNodes)

        # zero cross derivative parameters
        remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, [])

        remapEftLocalNodes(eft, 6, ln_map)
        if not eft.validate():
            print(
                'eftfactory_bicubichermitelinear.createEftWedgeCollapseXi2Quadrant:  Failed to validate eft for collapseNodes',
                collapseNodes)
        return eft
    def generateBaseMesh(cls,
                         region,
                         options,
                         baseCentre=[0.0, 0.0, 0.0],
                         axisSide1=[0.0, -1.0, 0.0],
                         axisUp=[0.0, 0.0, 1.0]):
        """
        Generate the base bicubic-linear Hermite mesh. See also generateMesh().
        Optional extra parameters allow centre and axes to be set.
        :param region: Zinc region to define model in. Must be empty.
        :param options: Dict containing options. See getDefaultOptions().
        :param baseCentre: Centre of valve on ventriculo-arterial junction.
        :param axisSide: Unit vector in first side direction where angle around starts.
        :param axisUp: Unit vector in outflow direction of valve.
        :return: list of AnnotationGroup
         """
        unitScale = options['Unit scale']
        outerHeight = unitScale * options['Outer height']
        innerDepth = unitScale * options['Inner depth']
        cuspHeight = unitScale * options['Cusp height']
        innerRadius = unitScale * 0.5 * options['Inner diameter']
        sinusRadialDisplacement = unitScale * options[
            'Sinus radial displacement']
        wallThickness = unitScale * options['Wall thickness']
        cuspThickness = unitScale * options['Cusp thickness']
        aorticNotPulmonary = options['Aortic not pulmonary']
        useCrossDerivatives = False

        fm = region.getFieldmodule()
        fm.beginChange()
        coordinates = zinc_utils.getOrCreateCoordinateField(fm)
        cache = fm.createFieldcache()

        if aorticNotPulmonary:
            arterialRootGroup = AnnotationGroup(region,
                                                'root of aorta',
                                                FMANumber=3740,
                                                lyphID='Lyph ID unknown')
            cuspGroups = [
                AnnotationGroup(region,
                                'posterior cusp of aortic valve',
                                FMANumber=7253,
                                lyphID='Lyph ID unknown'),
                AnnotationGroup(region,
                                'right cusp of aortic valve',
                                FMANumber=7252,
                                lyphID='Lyph ID unknown'),
                AnnotationGroup(region,
                                'left cusp of aortic valve',
                                FMANumber=7251,
                                lyphID='Lyph ID unknown')
            ]
        else:
            arterialRootGroup = AnnotationGroup(region,
                                                'root of pulmonary trunk',
                                                FMANumber=8612,
                                                lyphID='Lyph ID unknown')
            cuspGroups = [
                AnnotationGroup(region,
                                'right cusp of pulmonary valve',
                                FMANumber=7250,
                                lyphID='Lyph ID unknown'),
                AnnotationGroup(region,
                                'anterior cusp of pulmonary valve',
                                FMANumber=7249,
                                lyphID='Lyph ID unknown'),
                AnnotationGroup(region,
                                'left cusp of pulmonary valve',
                                FMANumber=7247,
                                lyphID='Lyph ID unknown')
            ]

        allGroups = [arterialRootGroup
                     ]  # groups that all elements in scaffold will go in
        annotationGroups = allGroups + cuspGroups

        # annotation fiducial points
        fiducialGroup = zinc_utils.getOrCreateGroupField(fm, 'fiducial')
        fiducialCoordinates = zinc_utils.getOrCreateCoordinateField(
            fm, 'fiducial_coordinates')
        fiducialLabel = zinc_utils.getOrCreateLabelField(fm, 'fiducial_label')
        #fiducialElementXi = zinc_utils.getOrCreateElementXiField(fm, 'fiducial_element_xi')

        datapoints = fm.findNodesetByFieldDomainType(
            Field.DOMAIN_TYPE_DATAPOINTS)
        fiducialPoints = zinc_utils.getOrCreateNodesetGroup(
            fiducialGroup, datapoints)
        datapointTemplateExternal = datapoints.createNodetemplate()
        datapointTemplateExternal.defineField(fiducialCoordinates)
        datapointTemplateExternal.defineField(fiducialLabel)

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

        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)
        nodetemplate.setValueNumberOfVersions(coordinates, -1,
                                              Node.VALUE_LABEL_D_DS3, 1)
        # most nodes in this scaffold do not have a DS3 derivative
        nodetemplateLinearS3 = nodes.createNodetemplate()
        nodetemplateLinearS3.defineField(coordinates)
        nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1,
                                                      Node.VALUE_LABEL_VALUE,
                                                      1)
        nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1,
                                                      Node.VALUE_LABEL_D_DS1,
                                                      1)
        nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1,
                                                      Node.VALUE_LABEL_D_DS2,
                                                      1)
        # several only have a DS1 derivative
        nodetemplateLinearS2S3 = nodes.createNodetemplate()
        nodetemplateLinearS2S3.defineField(coordinates)
        nodetemplateLinearS2S3.setValueNumberOfVersions(
            coordinates, -1, Node.VALUE_LABEL_VALUE, 1)
        nodetemplateLinearS2S3.setValueNumberOfVersions(
            coordinates, -1, Node.VALUE_LABEL_D_DS1, 1)

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

        elementsCountAround = 6
        radiansPerElementAround = 2.0 * math.pi / elementsCountAround
        axisSide2 = vector.crossproduct3(axisUp, axisSide1)
        outerRadius = innerRadius + wallThickness
        cuspOuterLength2 = 0.5 * getApproximateEllipsePerimeter(
            innerRadius, cuspHeight)
        cuspOuterWallArcLength = cuspOuterLength2 * innerRadius / (
            innerRadius + cuspHeight)
        noduleOuterAxialArcLength = cuspOuterLength2 - cuspOuterWallArcLength
        noduleOuterRadialArcLength = innerRadius
        cuspOuterWalld1 = interp.interpolateLagrangeHermiteDerivative(
            [innerRadius, outerHeight + innerDepth - cuspHeight], [0.0, 0.0],
            [-innerRadius, 0.0], 0.0)

        sin60 = math.sin(math.pi / 3.0)
        cuspThicknessLowerFactor = 4.5  # GRC fudge factor
        cuspInnerLength2 = 0.5 * getApproximateEllipsePerimeter(
            innerRadius - cuspThickness / sin60,
            cuspHeight - cuspThicknessLowerFactor * cuspThickness)

        noduleInnerAxialArcLength = cuspInnerLength2 * (
            cuspHeight - cuspThicknessLowerFactor * cuspThickness) / (
                innerRadius - cuspThickness / sin60 + cuspHeight -
                cuspThicknessLowerFactor * cuspThickness)
        noduleInnerRadialArcLength = innerRadius - cuspThickness / math.tan(
            math.pi / 3.0)
        nMidCusp = 0 if aorticNotPulmonary else 1

        # lower points
        ix, id1 = createCirclePoints(
            [(baseCentre[c] - axisUp[c] * innerDepth) for c in range(3)],
            [axisSide1[c] * innerRadius for c in range(3)],
            [axisSide2[c] * innerRadius
             for c in range(3)], elementsCountAround)
        ox, od1 = getSemilunarValveSinusPoints(baseCentre,
                                               axisSide1,
                                               axisSide2,
                                               outerRadius,
                                               sinusRadialDisplacement,
                                               startMidCusp=aorticNotPulmonary)
        lowerx, lowerd1 = [ix, ox], [id1, od1]

        # upper points
        topCentre = [(baseCentre[c] + axisUp[c] * outerHeight)
                     for c in range(3)]
        # twice as many on inner:
        ix, id1 = createCirclePoints(
            topCentre, [axisSide1[c] * innerRadius for c in range(3)],
            [axisSide2[c] * innerRadius
             for c in range(3)], elementsCountAround * 2)
        # tweak inner points so elements attached to cusps are narrower
        cuspRadiansFactor = 0.25  # GRC fudge factor
        midDerivativeFactor = 1.0 + 0.5 * (1.0 - cuspRadiansFactor
                                           )  # GRC test compromise
        cuspAttachmentRadians = cuspRadiansFactor * radiansPerElementAround
        cuspAttachmentRadialDisplacement = wallThickness * 0.333  # GRC fudge factor
        cuspAttachmentRadius = innerRadius - cuspAttachmentRadialDisplacement
        for cusp in range(3):
            n1 = cusp * 2 - 1 + nMidCusp
            n2 = n1 * 2
            id1[n2 + 2] = [2.0 * d for d in id1[n2 + 2]]
            # side 1
            radiansAround = n1 * radiansPerElementAround + cuspAttachmentRadians
            rcosRadiansAround = cuspAttachmentRadius * math.cos(radiansAround)
            rsinRadiansAround = cuspAttachmentRadius * math.sin(radiansAround)
            ix[n2 + 1] = [(topCentre[c] + rcosRadiansAround * axisSide1[c] +
                           rsinRadiansAround * axisSide2[c]) for c in range(3)]
            id1[n2 + 1] = interp.interpolateLagrangeHermiteDerivative(
                ix[n2 + 1], ix[n2 + 2], id1[n2 + 2], 0.0)
            # side 2
            n1 = ((cusp + 1) * 2 - 1 + nMidCusp) % elementsCountAround
            n2 = n1 * 2
            radiansAround = n1 * radiansPerElementAround - cuspAttachmentRadians
            rcosRadiansAround = cuspAttachmentRadius * math.cos(radiansAround)
            rsinRadiansAround = cuspAttachmentRadius * math.sin(radiansAround)
            ix[n2 - 1] = [(topCentre[c] + rcosRadiansAround * axisSide1[c] +
                           rsinRadiansAround * axisSide2[c]) for c in range(3)]
            id1[n2 - 1] = interp.interpolateHermiteLagrangeDerivative(
                ix[n2 - 2], id1[n2 - 2], ix[n2 - 1], 1.0)
        ox, od1 = createCirclePoints(
            topCentre, [axisSide1[c] * outerRadius for c in range(3)],
            [axisSide2[c] * outerRadius
             for c in range(3)], elementsCountAround)
        upperx, upperd1 = [ix, ox], [id1, od1]

        # get lower and upper derivative 2
        zero = [0.0, 0.0, 0.0]
        upperd2factor = outerHeight
        upd2 = [d * upperd2factor for d in axisUp]
        lowerOuterd2 = interp.smoothCubicHermiteDerivativesLine(
            [lowerx[1][nMidCusp], upperx[1][nMidCusp]], [upd2, upd2],
            fixStartDirection=True,
            fixEndDerivative=True)[0]
        lowerd2factor = 2.0 * (outerHeight + innerDepth) - upperd2factor
        lowerInnerd2 = [d * lowerd2factor for d in axisUp]
        lowerd2 = [[lowerInnerd2] * elementsCountAround,
                   [lowerOuterd2] * elementsCountAround
                   ]  # some lowerd2[0] to be fitted below
        upperd2 = [[upd2] * (elementsCountAround * 2),
                   [upd2] * elementsCountAround]

        # get lower and upper derivative 1 or 2 pointing to/from cusps
        for n1 in range(elementsCountAround):
            radiansAround = n1 * radiansPerElementAround
            cosRadiansAround = math.cos(radiansAround)
            sinRadiansAround = math.sin(radiansAround)
            if (n1 % 2) == nMidCusp:
                lowerd2[0][n1] = [
                    -cuspOuterWallArcLength *
                    (cosRadiansAround * axisSide1[c] +
                     sinRadiansAround * axisSide2[c]) for c in range(3)
                ]
            else:
                upperd1[0][n1 * 2] = [
                    (cuspOuterWalld1[0] * (cosRadiansAround * axisSide1[c] +
                                           sinRadiansAround * axisSide2[c]) +
                     cuspOuterWalld1[1] * axisUp[c]) for c in range(3)
                ]

        # inner wall and mid sinus points; only every second one is used
        sinusDepth = innerDepth - cuspThicknessLowerFactor * cuspThickness  # GRC test
        sinusCentre = [(baseCentre[c] - sinusDepth * axisUp[c])
                       for c in range(3)]
        sinusx, sinusd1 = createCirclePoints(
            sinusCentre, [axisSide1[c] * innerRadius for c in range(3)],
            [axisSide2[c] * innerRadius
             for c in range(3)], elementsCountAround)
        # get sinusd2, parallel to lower inclined lines
        sd2 = interp.smoothCubicHermiteDerivativesLine(
            [[innerRadius, -sinusDepth], [innerRadius, outerHeight]],
            [[wallThickness + sinusRadialDisplacement, innerDepth],
             [0.0, upperd2factor]],
            fixStartDirection=True,
            fixEndDerivative=True)[0]
        sinusd2 = [None] * elementsCountAround
        for cusp in range(3):
            n1 = cusp * 2 + nMidCusp
            radiansAround = n1 * radiansPerElementAround
            cosRadiansAround = math.cos(radiansAround)
            sinRadiansAround = math.sin(radiansAround)
            sinusd2[n1] = [(sd2[0] * (cosRadiansAround * axisSide1[c] +
                                      sinRadiansAround * axisSide2[c]) +
                            sd2[1] * axisUp[c]) for c in range(3)]

        # get points on arc between mid sinus and upper cusp points
        arcx = []
        arcd1 = []
        scaled1 = 2.5  # GRC fudge factor
        for cusp in range(3):
            n1 = cusp * 2 + nMidCusp
            n1m = n1 - 1
            n1p = (n1 + 1) % elementsCountAround
            n2m = n1m * 2 + 1
            n2p = n1p * 2 - 1
            ax, ad1 = interp.sampleCubicHermiteCurves(
                [upperx[0][n2m], sinusx[n1]],
                [[-scaled1 * d for d in upperd2[0][n2m]],
                 [scaled1 * d for d in sinusd1[n1]]],
                elementsCountOut=2,
                addLengthStart=0.5 * vector.magnitude(upperd2[0][n2m]),
                lengthFractionStart=0.5,
                addLengthEnd=0.5 * vector.magnitude(sinusd1[n1]),
                lengthFractionEnd=0.5,
                arcLengthDerivatives=False)[0:2]
            arcx.append(ax[1])
            arcd1.append(ad1[1])
            ax, ad1 = interp.sampleCubicHermiteCurves(
                [
                    sinusx[n1],
                    upperx[0][n2p],
                ], [[scaled1 * d for d in sinusd1[n1]],
                    [scaled1 * d for d in upperd2[0][n2p]]],
                elementsCountOut=2,
                addLengthStart=0.5 * vector.magnitude(sinusd1[n1]),
                lengthFractionStart=0.5,
                addLengthEnd=0.5 * vector.magnitude(upperd2[0][n2p]),
                lengthFractionEnd=0.5,
                arcLengthDerivatives=False)[0:2]
            arcx.append(ax[1])
            arcd1.append(ad1[1])
        if nMidCusp == 0:
            arcx.append(arcx.pop(0))
            arcd1.append(arcd1.pop(0))

        # cusp nodule points
        noduleCentre = [(baseCentre[c] + axisUp[c] * (cuspHeight - innerDepth))
                        for c in range(3)]
        nodulex = [[], []]
        noduled1 = [[], []]
        noduled2 = [[], []]
        noduled3 = [[], []]
        cuspRadialThickness = cuspThickness / sin60
        for i in range(3):
            nodulex[0].append(noduleCentre)
            n1 = i * 2 + nMidCusp
            radiansAround = n1 * radiansPerElementAround
            cosRadiansAround = math.cos(radiansAround)
            sinRadiansAround = math.sin(radiansAround)
            nodulex[1].append([(noduleCentre[c] + cuspRadialThickness *
                                (cosRadiansAround * axisSide1[c] +
                                 sinRadiansAround * axisSide2[c]))
                               for c in range(3)])
            n1 = i * 2 - 1 + nMidCusp
            radiansAround = n1 * radiansPerElementAround
            cosRadiansAround = math.cos(radiansAround)
            sinRadiansAround = math.sin(radiansAround)
            noduled1[0].append([
                noduleOuterRadialArcLength * (cosRadiansAround * axisSide1[c] +
                                              sinRadiansAround * axisSide2[c])
                for c in range(3)
            ])
            noduled1[1].append(
                vector.setMagnitude(noduled1[0][i],
                                    noduleInnerRadialArcLength))
            n1 = i * 2 + 1 + nMidCusp
            radiansAround = n1 * radiansPerElementAround
            cosRadiansAround = math.cos(radiansAround)
            sinRadiansAround = math.sin(radiansAround)
            noduled2[0].append([
                noduleOuterRadialArcLength * (cosRadiansAround * axisSide1[c] +
                                              sinRadiansAround * axisSide2[c])
                for c in range(3)
            ])
            noduled2[1].append(
                vector.setMagnitude(noduled2[0][i],
                                    noduleInnerRadialArcLength))
            noduled3[0].append(
                [noduleOuterAxialArcLength * axisUp[c] for c in range(3)])
            noduled3[1].append(
                [noduleInnerAxialArcLength * axisUp[c] for c in range(3)])

        # Create nodes

        lowerNodeId = [[], []]
        for n3 in range(2):
            for n1 in range(elementsCountAround):
                node = nodes.createNode(nodeIdentifier, nodetemplateLinearS3)
                cache.setNode(node)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_VALUE, 1,
                                              lowerx[n3][n1])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS1, 1,
                                              lowerd1[n3][n1])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS2, 1,
                                              lowerd2[n3][n1])
                lowerNodeId[n3].append(nodeIdentifier)
                nodeIdentifier += 1

        sinusNodeId = []
        for n1 in range(elementsCountAround):
            if (n1 % 2) != nMidCusp:
                sinusNodeId.append(None)
                continue
            node = nodes.createNode(nodeIdentifier, nodetemplateLinearS3)
            cache.setNode(node)
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1,
                                          sinusx[n1])
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1,
                                          sinusd1[n1])
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1,
                                          sinusd2[n1])
            sinusNodeId.append(nodeIdentifier)
            nodeIdentifier += 1

        arcNodeId = []
        for n1 in range(elementsCountAround):
            node = nodes.createNode(nodeIdentifier, nodetemplateLinearS2S3)
            cache.setNode(node)
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1,
                                          arcx[n1])
            coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1,
                                          arcd1[n1])
            arcNodeId.append(nodeIdentifier)
            nodeIdentifier += 1

        noduleNodeId = [[], []]
        for n3 in range(2):
            for n1 in range(3):
                node = nodes.createNode(nodeIdentifier, nodetemplate)
                cache.setNode(node)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_VALUE, 1,
                                              nodulex[n3][n1])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS1, 1,
                                              noduled1[n3][n1])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS2, 1,
                                              noduled2[n3][n1])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS3, 1,
                                              noduled3[n3][n1])
                noduleNodeId[n3].append(nodeIdentifier)
                nodeIdentifier += 1

        upperNodeId = [[], []]
        for n3 in range(2):
            for n1 in range(len(upperx[n3])):
                node = nodes.createNode(nodeIdentifier, nodetemplateLinearS3)
                cache.setNode(node)
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_VALUE, 1,
                                              upperx[n3][n1])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS1, 1,
                                              upperd1[n3][n1])
                coordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_D_DS2, 1,
                                              upperd2[n3][n1])
                upperNodeId[n3].append(nodeIdentifier)
                nodeIdentifier += 1

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

        mesh = fm.findMeshByDimension(3)

        allMeshGroups = [allGroup.getMeshGroup(mesh) for allGroup in allGroups]
        cuspMeshGroups = [
            cuspGroup.getMeshGroup(mesh) for cuspGroup in cuspGroups
        ]

        linearHermiteLinearBasis = fm.createElementbasis(
            3, Elementbasis.FUNCTION_TYPE_LINEAR_LAGRANGE)
        linearHermiteLinearBasis.setFunctionType(
            2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE)

        hermiteLinearLinearBasis = fm.createElementbasis(
            3, Elementbasis.FUNCTION_TYPE_LINEAR_LAGRANGE)
        hermiteLinearLinearBasis.setFunctionType(
            1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE)

        bicubichermitelinear = eftfactory_bicubichermitelinear(
            mesh, useCrossDerivatives)
        eftDefault = bicubichermitelinear.createEftNoCrossDerivatives()

        elementIdentifier = max(
            1,
            zinc_utils.getMaximumElementIdentifier(mesh) + 1)

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

        # wall elements
        for cusp in range(3):
            n1 = cusp * 2 - 1 + nMidCusp
            n2 = n1 * 2
            for e in range(6):
                eft1 = None
                scalefactors = None

                if (e == 0) or (e == 5):
                    # 6 node linear-hermite-linear collapsed wedge element expanding from zero width on outer wall of root, attaching to vertical part of cusp
                    eft1 = mesh.createElementfieldtemplate(
                        linearHermiteLinearBasis)
                    # switch mappings to use DS2 instead of default DS1
                    remapEftNodeValueLabel(eft1, [1, 2, 3, 4, 5, 6, 7, 8],
                                           Node.VALUE_LABEL_D_DS1,
                                           [(Node.VALUE_LABEL_D_DS2, [])])
                    if e == 0:
                        nids = [
                            lowerNodeId[0][n1], arcNodeId[n1],
                            upperNodeId[0][n2], upperNodeId[0][n2 + 1],
                            lowerNodeId[1][n1], upperNodeId[1][n1]
                        ]
                        setEftScaleFactorIds(eft1, [1], [])
                        scalefactors = [-1.0]
                        remapEftNodeValueLabel(eft1, [2],
                                               Node.VALUE_LABEL_D_DS2,
                                               [(Node.VALUE_LABEL_D_DS1, [1])])
                    else:
                        nids = [
                            arcNodeId[n1 + 1], lowerNodeId[0][n1 - 4],
                            upperNodeId[0][n2 + 3], upperNodeId[0][n2 - 8],
                            lowerNodeId[1][n1 - 4], upperNodeId[1][n1 - 4]
                        ]
                        remapEftNodeValueLabel(eft1, [1],
                                               Node.VALUE_LABEL_D_DS2,
                                               [(Node.VALUE_LABEL_D_DS1, [])])
                    ln_map = [1, 2, 3, 4, 5, 5, 6, 6]
                    remapEftLocalNodes(eft1, 6, ln_map)
                elif (e == 1) or (e == 4):
                    # 6 node hermite-linear-linear collapsed wedge element on lower wall
                    eft1 = mesh.createElementfieldtemplate(
                        hermiteLinearLinearBasis)
                    if e == 1:
                        nids = [
                            lowerNodeId[0][n1], lowerNodeId[0][n1 + 1],
                            arcNodeId[n1], sinusNodeId[n1 + 1],
                            lowerNodeId[1][n1], lowerNodeId[1][n1 + 1]
                        ]
                    else:
                        nids = [
                            lowerNodeId[0][n1 + 1], lowerNodeId[0][n1 - 4],
                            sinusNodeId[n1 + 1], arcNodeId[n1 + 1],
                            lowerNodeId[1][n1 + 1], lowerNodeId[1][n1 - 4]
                        ]
                    ln_map = [1, 2, 3, 4, 5, 6, 5, 6]
                    remapEftLocalNodes(eft1, 6, ln_map)
                else:
                    # 8 node elements with wedges on two sides
                    if e == 2:
                        eft1 = bicubichermitelinear.createEftNoCrossDerivatives(
                        )
                        setEftScaleFactorIds(eft1, [1], [])
                        scalefactors = [-1.0]
                        nids = [
                            arcNodeId[n1], sinusNodeId[n1 + 1],
                            upperNodeId[0][n2 + 1], upperNodeId[0][n2 + 2],
                            lowerNodeId[1][n1], lowerNodeId[1][n1 + 1],
                            upperNodeId[1][n1], upperNodeId[1][n1 + 1]
                        ]
                        remapEftNodeValueLabel(eft1, [1],
                                               Node.VALUE_LABEL_D_DS2,
                                               [(Node.VALUE_LABEL_D_DS1, [1])])
                    else:
                        eft1 = eftDefault
                        nids = [
                            sinusNodeId[n1 + 1], arcNodeId[n1 + 1],
                            upperNodeId[0][n2 + 2], upperNodeId[0][n2 + 3],
                            lowerNodeId[1][n1 + 1], lowerNodeId[1][n1 - 4],
                            upperNodeId[1][n1 + 1], upperNodeId[1][n1 - 4]
                        ]
                        remapEftNodeValueLabel(eft1, [2],
                                               Node.VALUE_LABEL_D_DS2,
                                               [(Node.VALUE_LABEL_D_DS1, [])])

                result = elementtemplate1.defineField(coordinates, -1, eft1)
                element = mesh.createElement(elementIdentifier,
                                             elementtemplate1)
                result2 = element.setNodesByIdentifier(eft1, nids)
                if scalefactors:
                    result3 = element.setScaleFactors(eft1, scalefactors)
                else:
                    result3 = 7
                #print('create arterial root wall', cusp, e, 'element',elementIdentifier, result, result2, result3, nids)
                elementIdentifier += 1

                for meshGroup in allMeshGroups:
                    meshGroup.addElement(element)

        # cusps (leaflets)
        for cusp in range(3):
            n1 = cusp * 2 - 1 + nMidCusp
            n2 = n1 * 2
            meshGroups = allMeshGroups + [cuspMeshGroups[cusp]]
            for e in range(2):
                eft1 = bicubichermitelinear.createEftNoCrossDerivatives()
                setEftScaleFactorIds(eft1, [1], [])
                scalefactors = [-1.0]

                if e == 0:
                    nids = [
                        lowerNodeId[0][n1], lowerNodeId[0][n1 + 1],
                        upperNodeId[0][n2], noduleNodeId[0][cusp],
                        arcNodeId[n1], sinusNodeId[n1 + 1],
                        upperNodeId[0][n2 + 1], noduleNodeId[1][cusp]
                    ]
                    remapEftNodeValueLabel(eft1, [4, 8],
                                           Node.VALUE_LABEL_D_DS1,
                                           [(Node.VALUE_LABEL_D_DS1, [1])])
                    remapEftNodeValueLabel(eft1, [4, 8],
                                           Node.VALUE_LABEL_D_DS2,
                                           [(Node.VALUE_LABEL_D_DS3, [])])
                    remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2,
                                           [(Node.VALUE_LABEL_D_DS1, [1])])
                    remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2,
                                           [(Node.VALUE_LABEL_D_DS2, [1])])
                    remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1,
                                           [(Node.VALUE_LABEL_D_DS1, [1])])
                else:
                    nids = [
                        lowerNodeId[0][n1 + 1], lowerNodeId[0][n1 - 4],
                        noduleNodeId[0][cusp], upperNodeId[0][n2 - 8],
                        sinusNodeId[n1 + 1], arcNodeId[n1 + 1],
                        noduleNodeId[1][cusp], upperNodeId[0][n2 + 3]
                    ]
                    remapEftNodeValueLabel(eft1, [3, 7],
                                           Node.VALUE_LABEL_D_DS2,
                                           [(Node.VALUE_LABEL_D_DS3, [])])
                    remapEftNodeValueLabel(eft1, [3, 7],
                                           Node.VALUE_LABEL_D_DS1,
                                           [(Node.VALUE_LABEL_D_DS2, [])])
                    remapEftNodeValueLabel(eft1, [4, 8],
                                           Node.VALUE_LABEL_D_DS1,
                                           [(Node.VALUE_LABEL_D_DS1, [1])])
                    remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2,
                                           [(Node.VALUE_LABEL_D_DS2, [1])])
                    remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2,
                                           [(Node.VALUE_LABEL_D_DS1, [])])

                result = elementtemplate1.defineField(coordinates, -1, eft1)
                element = mesh.createElement(elementIdentifier,
                                             elementtemplate1)
                result2 = element.setNodesByIdentifier(eft1, nids)
                if scalefactors:
                    result3 = element.setScaleFactors(eft1, scalefactors)
                else:
                    result3 = 7
                #print('create semilunar cusp', cusp, e, 'element',elementIdentifier, result, result2, result3, nids)
                elementIdentifier += 1

                for meshGroup in meshGroups:
                    meshGroup.addElement(element)

        # create annotation points

        datapoint = fiducialPoints.createNode(-1, datapointTemplateExternal)
        cache.setNode(datapoint)
        fiducialCoordinates.setNodeParameters(cache, -1,
                                              Node.VALUE_LABEL_VALUE, 1,
                                              noduleCentre)
        fiducialLabel.assignString(
            cache, 'aortic valve ctr'
            if aorticNotPulmonary else 'pulmonary valve ctr')

        fm.endChange()
        return annotationGroups