예제 #1
0
def computeNodeDerivativeHermiteLagrange(cache, coordinates, node1, derivative1, scale1, node2, scale2):
    """
    Computes the derivative at node2 from quadratic Hermite-Lagrange interpolation of
    node1 value and derivative1 to node2 value.
    :param cache: Field cache to evaluate in.
    :param coordinates: Coordinates field.
    :param node1, node2: Start and end nodes.
    :param derivative1: Node value label for derivative at node1.
    :param scale1, scale2: Scaling to apply to derivatives at nodes, e.g. -1.0 to reverse.
    :return: dx_dxi at node2
    """
    cache.setNode(node1)
    result, v1 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, 3 )
    result, d1 = coordinates.getNodeParameters(cache, -1, derivative1, 1, 3 )
    d1 = [ d*scale1 for d in d1 ]
    cache.setNode(node2)
    result, v2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, 3 )
    d2 = interp.interpolateHermiteLagrangeDerivative(v1, d1, v2, 1.0)
    d2 = [ d*scale2 for d in d2 ]
    return d2
    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
예제 #3
0
 def smooth(self,
            updateDirections=False,
            maxIterations=10,
            arcLengthTolerance=1.0E-6):
     '''
     :param maxIterations: Maximum iterations before stopping if not converging.
     :param arcLengthTolerance: Ratio of difference in arc length from last iteration
     divided by current arc length under which convergence is achieved. Required to
     be met by every element edge.
     '''
     if not self._derivativeMap:
         return  # no nodes being smoothed
     componentsCount = self._field.getNumberOfComponents()
     with ChangeManager(self._fieldmodule):
         fieldcache = self._fieldmodule.createFieldcache()
         for iter in range(maxIterations + 1):
             converged = True
             for edge in self._edgesMap.values():
                 lastArcLength = edge.getLastArcLength()
                 arcLength = edge.evaluateArcLength(self._nodes,
                                                    self._field, fieldcache)
                 edge.updateLastArcLength()
                 if (math.fabs(arcLength - lastArcLength) /
                         arcLength) > arcLengthTolerance:
                     converged = False
             if converged:
                 print('Derivative smoothing: Converged after', iter,
                       'iterations.')
                 break
             elif (iter == maxIterations):
                 print('Derivative smoothing: Stopping after',
                       maxIterations, 'iterations without converging.')
                 break
             for derivativeKey, derivativeEdges in self._derivativeMap.items(
             ):
                 edgeCount = len(derivativeEdges)
                 if edgeCount > 1:
                     nodeIdentifier, nodeValueLabel, nodeVersion = derivativeKey
                     fieldcache.setNode(
                         self._nodes.findNodeByIdentifier(nodeIdentifier))
                     if updateDirections:
                         x = [0.0 for _ in range(componentsCount)]
                     else:
                         result, x = self._field.getNodeParameters(
                             fieldcache, -1, nodeValueLabel, nodeVersion,
                             componentsCount)
                     mag = 0.0
                     for derivativeEdge in derivativeEdges:
                         edge, expressionIndex, totalScaleFactor = derivativeEdge
                         arcLength = edge.getArcLength()
                         if updateDirections:
                             delta = edge.getDelta()
                             if totalScaleFactor < 0.0:
                                 delta = [-d for d in delta]
                             for c in range(componentsCount):
                                 x[c] += delta[c] / arcLength
                         if self._scalingMode == DerivativeScalingMode.ARITHMETIC_MEAN:
                             mag += arcLength / math.fabs(totalScaleFactor)
                         else:  # self._scalingMode == DerivativeScalingMode.HARMONIC_MEAN
                             mag += math.fabs(totalScaleFactor) / arcLength
                     if self._scalingMode == DerivativeScalingMode.ARITHMETIC_MEAN:
                         mag /= edgeCount
                     else:  # self._scalingMode == DerivativeScalingMode.HARMONIC_MEAN
                         mag = edgeCount / mag
                     if (mag <= 0.0):
                         print('Node', nodeIdentifier, 'value', nodeValueLabel, 'version', nodeVersion, \
                               'has negative mag', mag)
                     x = setMagnitude(x, mag)
                     result = self._field.setNodeParameters(
                         fieldcache, -1, nodeValueLabel, nodeVersion, x)
             for derivativeKey, derivativeEdges in self._derivativeMap.items(
             ):
                 edgeCount = len(derivativeEdges)
                 if edgeCount == 1:
                     # boundary smoothing over single edge
                     nodeIdentifier, nodeValueLabel, nodeVersion = derivativeKey
                     edge, expressionIndex, totalScaleFactor = derivativeEdges[
                         0]
                     # re-evaluate arc length so parameters are up-to-date for other end
                     arcLength = edge.evaluateArcLength(
                         self._nodes, self._field, fieldcache)
                     fieldcache.setNode(
                         self._nodes.findNodeByIdentifier(nodeIdentifier)
                     )  # since changed by evaluateArcLength
                     otherExpressionIndex = 3 if (expressionIndex
                                                  == 1) else 1
                     otherd = edge.getParameter(otherExpressionIndex)
                     if updateDirections:
                         thisx = edge.getParameter(expressionIndex - 1)
                         otherx = edge.getParameter(otherExpressionIndex -
                                                    1)
                         bothEndsOnBoundary = False
                         otherExpression = edge.getExpression(
                             otherExpressionIndex)
                         if len(otherExpression) == 1:
                             otherNodeIdentifier, otherValueLabel, otherNodeVersion, otherTotalScaleFactor = otherExpression[
                                 0]
                             otherDerivativeKey = (otherNodeIdentifier,
                                                   otherValueLabel,
                                                   otherNodeVersion)
                             otherDerivativeEdges = self._derivativeMap.get(
                                 otherDerivativeKey)
                             bothEndsOnBoundary = (
                                 otherDerivativeEdges
                                 is not None) and (len(otherDerivativeEdges)
                                                   == 1)
                         if bothEndsOnBoundary:
                             if expressionIndex == 1:
                                 x = [(otherx[c] - thisx[c])
                                      for c in range(componentsCount)]
                             else:
                                 x = [(thisx[c] - otherx[c])
                                      for c in range(componentsCount)]
                         else:
                             if expressionIndex == 1:
                                 x = interpolateLagrangeHermiteDerivative(
                                     thisx, otherx, otherd, 0.0)
                             else:
                                 x = interpolateHermiteLagrangeDerivative(
                                     otherx, otherd, thisx, 1.0)
                         x = [d / totalScaleFactor for d in x]
                     else:
                         result, x = self._field.getNodeParameters(
                             fieldcache, -1, nodeValueLabel, nodeVersion,
                             componentsCount)
                     othermag = magnitude(otherd)
                     mag = (2.0 * arcLength -
                            othermag) / math.fabs(totalScaleFactor)
                     if (mag <= 0.0):
                         print('Derivative smoothing: Node', nodeIdentifier,
                               'label', nodeValueLabel, 'version',
                               nodeVersion, 'has negative magnitude', mag)
                     x = setMagnitude(x, mag)
                     result = self._field.setNodeParameters(
                         fieldcache, -1, nodeValueLabel, nodeVersion, x)
         # record modified nodes while ChangeManager is in effect
         if self._editNodesetGroup:
             for derivativeKey in self._derivativeMap:
                 self._editNodesetGroup.addNode(
                     (self._nodes.findNodeByIdentifier(derivativeKey[0])))
         del fieldcache
예제 #4
0
 def createHermiteCurvePoints(self,
                              aProportion1,
                              aProportion2,
                              bProportion1,
                              bProportion2,
                              elementsCount,
                              derivativeStart=None,
                              derivativeEnd=None,
                              curveMode=HermiteCurveMode.SMOOTH):
     '''
     Create hermite curve points between two points a and b on the surface, each defined
     by their proportions over the surface in directions 1 and 2.
     Also returns cross direction 2 in plane of surface with similar magnitude to curve derivative 1,
     and unit surface normals.
     :param derivativeStart, derivativeEnd: Optional derivative vectors in 3-D world coordinates
     to match at the start and end of the curves. If omitted, fits in with other derivative or is
     in a straight line from a to b.
     :param elementsCount:  Number of elements out.
     :return: nx[], nd1[], nd2[], nd3[], nProportions[]
     '''
     #print('createHermiteCurvePoints', aProportion1, aProportion2, bProportion1, bProportion2, elementsCount, derivativeStart, derivativeEnd)
     if derivativeStart:
         position = self.createPositionProportion(aProportion1,
                                                  aProportion2)
         _, sd1, sd2 = self.evaluateCoordinates(position, derivatives=True)
         delta_xi1, delta_xi2 = calculate_surface_delta_xi(
             sd1, sd2, derivativeStart)
         dp1Start = delta_xi1 / self.elementsCount1
         if self.loop1:
             dp1Start *= 2.0
         dp2Start = delta_xi2 / self.elementsCount2
         derivativeMagnitudeStart = math.sqrt(dp1Start * dp1Start +
                                              dp2Start * dp2Start)
         dp1Start *= elementsCount
         dp2Start *= elementsCount
         #print('start delta_xi1', delta_xi1, 'delta_xi2', delta_xi2)
         #print('dp1Start', dp1Start, 'dp2Start', dp2Start)
     if derivativeEnd:
         position = self.createPositionProportion(bProportion1,
                                                  bProportion2)
         _, sd1, sd2 = self.evaluateCoordinates(position, derivatives=True)
         delta_xi1, delta_xi2 = calculate_surface_delta_xi(
             sd1, sd2, derivativeEnd)
         dp1End = delta_xi1 / self.elementsCount1
         dp2End = delta_xi2 / self.elementsCount2
         derivativeMagnitudeEnd = math.sqrt(dp1End * dp1End +
                                            dp2End * dp2End)
         dp1End *= elementsCount
         if self.loop1:
             dp1End *= 2.0
         dp2End *= elementsCount
         #print('end delta_xi1', delta_xi1, 'delta_xi2', delta_xi2)
         #print('dp1End', dp1End, 'dp2End', dp2End)
     if not derivativeStart:
         if derivativeEnd:
             dp1Start, dp2Start = interp.interpolateLagrangeHermiteDerivative(
                 [aProportion1, aProportion2], [bProportion1, bProportion2],
                 [dp1End, dp2End], 0.0)
         else:
             dp1Start = bProportion1 - aProportion1
             dp2Start = bProportion2 - aProportion2
         derivativeMagnitudeStart = math.sqrt(
             dp1Start * dp1Start + dp2Start * dp2Start) / elementsCount
     if not derivativeEnd:
         if derivativeStart:
             dp1End, dp2End = interp.interpolateHermiteLagrangeDerivative(
                 [aProportion1, aProportion2], [dp1Start, dp2Start],
                 [bProportion1, bProportion2], 1.0)
         else:
             dp1End = bProportion1 - aProportion1
             dp2End = bProportion2 - aProportion2
         derivativeMagnitudeEnd = math.sqrt(dp1End * dp1End +
                                            dp2End * dp2End) / elementsCount
     maxProportion1 = 2.0 if self.loop1 else 1.0
     #print('derivativeMagnitudeStart', derivativeMagnitudeStart, 'derivativeMagnitudeEnd', derivativeMagnitudeEnd)
     proportions, dproportions = interp.sampleCubicHermiteCurvesSmooth([ [ aProportion1, aProportion2 ], [ bProportion1, bProportion2 ] ], \
         [ [ dp1Start, dp2Start ], [ dp1End, dp2End ] ], elementsCount, derivativeMagnitudeStart, derivativeMagnitudeEnd)[0:2]
     if curveMode != self.HermiteCurveMode.SMOOTH:
         if derivativeStart and (curveMode in [
                 self.HermiteCurveMode.TRANSITION_START,
                 self.HermiteCurveMode.TRANSITION_START_AND_END
         ]):
             addLengthStart = 0.5 * derivativeMagnitudeStart
             lengthFractionStart = 0.5
         else:
             addLengthStart = 0.0
             lengthFractionStart = 1.0
         if derivativeEnd and (curveMode in [
                 self.HermiteCurveMode.TRANSITION_END,
                 self.HermiteCurveMode.TRANSITION_START_AND_END
         ]):
             addLengthEnd = 0.5 * derivativeMagnitudeEnd
             lengthFractionEnd = 0.5
         else:
             addLengthEnd = 0.0
             lengthFractionEnd = 1.0
         proportions, dproportions = interp.sampleCubicHermiteCurves(
             proportions, dproportions, elementsCount, addLengthStart,
             addLengthEnd, lengthFractionStart, lengthFractionEnd)[0:2]
     #print(' proportions', proportions)
     #print('dproportions', dproportions)
     nx = []
     nd1 = []
     nd2 = []
     nd3 = []
     for n in range(0, elementsCount + 1):
         position = self.createPositionProportion(proportions[n][0],
                                                  proportions[n][1])
         x, sd1, sd2 = self.evaluateCoordinates(position, derivatives=True)
         f1 = dproportions[n][0] * self.elementsCount1 / maxProportion1
         f2 = dproportions[n][1] * self.elementsCount2
         d1 = [(f1 * sd1[c] + f2 * sd2[c]) for c in range(3)]
         d3 = vector.crossproduct3(sd1, sd2)
         # handle zero magnitude of d3
         mag = math.sqrt(sum(d3[c] * d3[c] for c in range(3)))
         if mag > 0.0:
             d3 = [(d3[c] / mag) for c in range(3)]
         d2 = vector.crossproduct3(d3, d1)
         nx.append(x)
         nd2.append(d2)
         nd1.append(d1)
         nd3.append(d3)
     #print('createHermiteCurvePoints end \n nx', nx,'\nnd1',nd1,'\nnd2',nd2,'\nnd3',nd3)
     return nx, nd1, nd2, nd3, proportions