def generateBaseMesh(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
        """

        centralPath = options['Central path']
        full = not options['Lower half']
        elementsCountAcrossMajor = options['Number of elements across major']
        if not full:
            elementsCountAcrossMajor //= 2
        elementsCountAcrossMinor = options['Number of elements across minor']
        elementsCountAcrossShell = options['Number of elements across shell']
        elementsCountAcrossTransition = options[
            'Number of elements across transition']
        elementsCountAlong = options['Number of elements along']
        shellProportion = options['Shell element thickness proportion']
        useCrossDerivatives = options['Use cross derivatives']

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

        cylinderCentralPath = CylinderCentralPath(region, centralPath,
                                                  elementsCountAlong)

        cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if full else CylinderShape.CYLINDER_SHAPE_LOWER_HALF

        base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor,
                            elementsCountAcrossShell,
                            elementsCountAcrossTransition, shellProportion,
                            [0.0, 0.0, 0.0], cylinderCentralPath.alongAxis[0],
                            cylinderCentralPath.majorAxis[0],
                            cylinderCentralPath.minorRadii[0])
        cylinder1 = CylinderMesh(fm,
                                 coordinates,
                                 elementsCountAlong,
                                 base,
                                 cylinderShape=cylinderShape,
                                 cylinderCentralPath=cylinderCentralPath,
                                 useCrossDerivatives=False)

        annotationGroup = []
        return annotationGroup
Exemple #2
0
    def generateBaseMesh(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: List of AnnotationGroup
        """

        baseParameterSetName = options['Base parameter set']
        isHuman = 'Human' in baseParameterSetName
        isRat = 'Rat' in baseParameterSetName

        centralPath = options['Central path']
        full = not options['Lower half']
        elementsCountAcrossMajor = options['Number of elements across major']
        if not full:
            elementsCountAcrossMajor //= 2
        elementsCountAcrossMinor = options['Number of elements across minor']
        elementsCountAcrossShell = options['Number of elements across shell']
        elementsCountAcrossTransition = options['Number of elements across transition']
        elementsCountAlongAbdomen = options['Number of elements in abdomen']
        elementsCountAlongHead = options['Number of elements in head']
        elementsCountAlongNeck = options['Number of elements in neck']
        elementsCountAlongThorax = options['Number of elements in thorax']
        shellRadiusProportion = options['Shell thickness proportion']
        shellProportion = 1/(1/shellRadiusProportion-1)*(elementsCountAcrossMajor/2/elementsCountAcrossShell - 1)
        discontinuity = options['Discontinuity on the core boundary']
        useCrossDerivatives = options['Use cross derivatives']

        elementsCountAlong = elementsCountAlongAbdomen + elementsCountAlongThorax + elementsCountAlongNeck + elementsCountAlongHead

        fieldmodule = region.getFieldmodule()
        coordinates = findOrCreateFieldCoordinates(fieldmodule)
        mesh = fieldmodule.findMeshByDimension(3)

        bodyGroup = AnnotationGroup(region, get_body_term("body"))
        coreGroup = AnnotationGroup(region, get_body_term("core"))
        non_coreGroup = AnnotationGroup(region, get_body_term("non core"))
        abdomenGroup = AnnotationGroup(region, get_body_term("abdomen"))
        thoraxGroup = AnnotationGroup(region, get_body_term("thorax"))
        neckGroup = AnnotationGroup(region, get_body_term("neck core"))
        headGroup = AnnotationGroup(region, get_body_term("head core"))
        annotationGroups = [bodyGroup, coreGroup, non_coreGroup, abdomenGroup, thoraxGroup, neckGroup, headGroup]

        cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong)

        cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL

        base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell,
                            elementsCountAcrossTransition, shellProportion,
                            [0.0, 0.0, 0.0], cylinderCentralPath.alongAxis[0], cylinderCentralPath.majorAxis[0],
                            cylinderCentralPath.minorRadii[0])
        cylinder1 = CylinderMesh(fieldmodule, coordinates, elementsCountAlong, base,
                                 cylinderShape=cylinderShape,
                                 cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False)

        # body coordinates
        bodyCoordinates = findOrCreateFieldCoordinates(fieldmodule, name="body coordinates")
        tmp_region = region.createRegion()
        tmp_fieldmodule = tmp_region.getFieldmodule()
        tmp_body_coordinates = findOrCreateFieldCoordinates(tmp_fieldmodule, name="body coordinates")
        tmp_cylinder = CylinderMesh(tmp_fieldmodule, tmp_body_coordinates, elementsCountAlong, base,
                                 cylinderShape=cylinderShape,
                                 cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False)
        sir = tmp_region.createStreaminformationRegion()
        srm = sir.createStreamresourceMemory()
        tmp_region.write(sir)
        result, buffer = srm.getBuffer()
        sir = region.createStreaminformationRegion()
        srm = sir.createStreamresourceMemoryBuffer(buffer)
        region.read(sir)

        del srm
        del sir
        del tmp_body_coordinates
        del tmp_fieldmodule
        del tmp_region

        # Groups of different parts of the body
        is_body = fieldmodule.createFieldConstant(1)
        bodyMeshGroup = bodyGroup.getMeshGroup(mesh)
        bodyMeshGroup.addElementsConditional(is_body)

        coreMeshGroup = coreGroup.getMeshGroup(mesh)

        # core group
        e1a = elementsCountAcrossShell
        e1z = elementsCountAcrossMinor - elementsCountAcrossShell - 1
        e2a = elementsCountAcrossShell
        e2b = e2a + elementsCountAcrossTransition
        e2z = elementsCountAcrossMajor - elementsCountAcrossShell - 1
        e2y = e2z - elementsCountAcrossTransition
        e1oc = elementsCountAcrossMinor - 2*elementsCountAcrossShell - 2*elementsCountAcrossTransition
        e2oc = elementsCountAcrossMajor - 2*elementsCountAcrossShell - 2*elementsCountAcrossTransition
        e2oCore = e2oc * e1oc + 2 * elementsCountAcrossTransition * (e2oc + e1oc)
        elementsCountAround = cylinder1.getElementsCountAround()
        e2oShell = elementsCountAround * elementsCountAcrossShell
        e2o = e2oCore + e2oShell
        elementId = cylinder1.getElementIdentifiers()
        for e3 in range(elementsCountAlong):
            for e2 in range(elementsCountAcrossMajor):
                for e1 in range(elementsCountAcrossMinor):
                    coreElement = ((e2 >= e2a) and (e2 <= e2z)) and ((e1 >= e1a) and (e1 <= e1z))
                    if coreElement:
                        elementIdentifier = elementId[e3][e2][e1]
                        if elementIdentifier:
                            element = mesh.findElementByIdentifier(elementIdentifier)
                            coreMeshGroup.addElement(element)

        is_non_core = fieldmodule.createFieldNot(coreGroup.getGroup())
        non_coreMeshGroup = non_coreGroup.getMeshGroup(mesh)
        non_coreMeshGroup.addElementsConditional(is_non_core)

        abdomenMeshGroup = abdomenGroup.getMeshGroup(mesh)
        thoraxMeshGroup = thoraxGroup.getMeshGroup(mesh)
        neckMeshGroup = neckGroup.getMeshGroup(mesh)
        headMeshGroup = headGroup.getMeshGroup(mesh)
        meshGroups = [abdomenMeshGroup, thoraxMeshGroup, neckMeshGroup, headMeshGroup]

        abdomenRange = [1, elementsCountAlongAbdomen*e2o]
        thoraxRange = [abdomenRange[1]+1, abdomenRange[1]+elementsCountAlongThorax*e2o]
        neckRange = [thoraxRange[1]+1, thoraxRange[1] + elementsCountAlongNeck*e2o]
        headRange = [neckRange[1]+1, elementsCountAlong*e2o]
        groupsRanges = [abdomenRange, thoraxRange, neckRange, headRange]

        totalElements = e2o*elementsCountAlong
        for elementIdentifier in range(1, totalElements+1):
            element = mesh.findElementByIdentifier(elementIdentifier)
            if coreMeshGroup.containsElement(element):
                ri = 0
                for groupRange in groupsRanges:
                    if (elementIdentifier >= groupRange[0]) and (elementIdentifier <= groupRange[1]):
                        meshGroups[ri].addElement(element)
                        break
                    ri += 1

        if discontinuity:
            # create discontinuity in d3 on the core boundary
            nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
            elementtemplate = mesh.createElementtemplate()
            undefineNodetemplate = nodes.createNodetemplate()
            undefineNodetemplate.undefineField(coordinates)
            nodetemplate = nodes.createNodetemplate()
            fieldcache = fieldmodule.createFieldcache()
            with ChangeManager(fieldmodule):
                localNodeIndexes = [1, 2, 3, 4]
                valueLabel = Node.VALUE_LABEL_D_DS3
                for e3 in range(elementsCountAlong):
                    for e2 in range(elementsCountAcrossMajor):
                        for e1 in range(elementsCountAcrossMinor):
                            regularRowElement = (((e2 >= e2b) and (e2 <= e2y)) and ((e1 == e1a - 1) or (e1 == e1z + 1)))
                            non_coreFirstLayerElement = (e2 == e2a - 1) or regularRowElement or (e2 == e2z + 1)
                            elementIdentifier = elementId[e3][e2][e1]
                            if elementIdentifier and non_coreFirstLayerElement:
                                element = mesh.findElementByIdentifier(elementIdentifier)
                                eft = element.getElementfieldtemplate(coordinates, -1)
                                nodeIds = get_element_node_identifiers(element, eft)
                                for localNodeIndex in localNodeIndexes:
                                    node = element.getNode(eft, localNodeIndex)
                                    nodetemplate.defineFieldFromNode(coordinates, node)
                                    versionsCount = nodetemplate.getValueNumberOfVersions(coordinates, -1, valueLabel)
                                    if versionsCount == 1:
                                        fieldcache.setNode(node)
                                        result0, x = coordinates.getNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, 3)
                                        result0, d1 = coordinates.getNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, 3)
                                        result0, d2 = coordinates.getNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, 3)
                                        result0, d3 = coordinates.getNodeParameters(fieldcache, -1, valueLabel, 1, 3)
                                        result1 = node.merge(undefineNodetemplate)
                                        result2 = nodetemplate.setValueNumberOfVersions(coordinates, -1, valueLabel, 2)
                                        result3 = node.merge(nodetemplate)
                                        result4 = coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, x)
                                        result4 = coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, d1)
                                        result4 = coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, d2)
                                        result4 = coordinates.setNodeParameters(fieldcache, -1, valueLabel, 1, d3)
                                        result5 = coordinates.setNodeParameters(fieldcache, -1, valueLabel, 2, d3)
                                remapEftNodeValueLabelsVersion(eft, localNodeIndexes, [valueLabel], 2)
                                result1 = elementtemplate.defineField(coordinates, -1, eft)
                                result2 = element.merge(elementtemplate)
                                result3 = element.setNodesByIdentifier(eft, nodeIds)
        else:
            fieldcache = fieldmodule.createFieldcache()

        # Annotation fiducial point
        markerGroup = findOrCreateFieldGroup(fieldmodule, "marker")
        markerName = findOrCreateFieldStoredString(fieldmodule, name="marker_name")
        markerLocation = findOrCreateFieldStoredMeshLocation(fieldmodule, mesh, name="marker_location")
        markerBodyCoordinates = findOrCreateFieldCoordinates(fieldmodule, name="marker_body_coordinates")
        nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
        markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup()
        markerTemplateInternal = nodes.createNodetemplate()
        markerTemplateInternal.defineField(markerName)
        markerTemplateInternal.defineField(markerLocation)
        markerTemplateInternal.defineField(markerBodyCoordinates)
        #
        middleLeft = elementsCountAcrossMinor//2
        topElem = elementsCountAcrossMajor - 1
        middleRight = middleLeft - 1
        neckFirstElem = elementsCountAlongAbdomen+elementsCountAlongThorax
        thoraxFirstElem = elementsCountAlongAbdomen
        middleDown = elementsCountAcrossMajor//2 - 1

        # organ landmarks groups
        apexOfHeart = heart_terms.get_heart_term('apex of heart')
        leftAtriumEpicardiumVenousMidpoint = heart_terms.get_heart_term('left atrium epicardium venous midpoint')
        rightAtriumEpicardiumVenousMidpoint = heart_terms.get_heart_term('right atrium epicardium venous midpoint')
        apexOfUrinaryBladder = bladder_terms.get_bladder_term('apex of urinary bladder')
        leftUreterJunctionWithBladder = bladder_terms.get_bladder_term('left ureter junction with bladder')
        rightUreterJunctionWithBladder = bladder_terms.get_bladder_term('right ureter junction with bladder')
        urethraJunctionWithBladderDorsal = bladder_terms.get_bladder_term('urethra junction of dorsal bladder neck')
        urethraJunctionWithBladderVentral = bladder_terms.get_bladder_term('urethra junction of ventral bladder neck')
        gastroesophagalJunctionOnLesserCurvature = stomach_terms.get_stomach_term('esophagogastric junction along the lesser curvature on serosa')
        limitingRidgeOnGreaterCurvature = stomach_terms.get_stomach_term('limiting ridge at the greater curvature on serosa')
        pylorusOnGreaterCurvature = stomach_terms.get_stomach_term('gastroduodenal junction along the greater curvature on serosa')
        junctionBetweenFundusAndBodyOnGreaterCurvature = stomach_terms.get_stomach_term("fundus-body junction along the greater curvature on serosa")
        apexOfLeftLung = lung_terms.get_lung_term('apex of left lung')
        ventralBaseOfLeftLung = lung_terms.get_lung_term('ventral base of left lung')
        dorsalBaseOfLeftLung = lung_terms.get_lung_term('dorsal base of left lung')
        apexOfRightLung = lung_terms.get_lung_term('apex of right lung')
        ventralBaseOfRightLung = lung_terms.get_lung_term('ventral base of right lung')
        dorsalBaseOfRightLung = lung_terms.get_lung_term('dorsal base of right lung')
        laterodorsalTipOfMiddleLobeOfRightLung = lung_terms.get_lung_term('laterodorsal tip of middle lobe of right lung')
        apexOfRightLungAccessoryLobe = lung_terms.get_lung_term('apex of right lung accessory lobe')
        ventralBaseOfRightLungAccessoryLobe = lung_terms.get_lung_term('ventral base of right lung accessory lobe')
        dorsalBaseOfRightLungAccessoryLobe = lung_terms.get_lung_term('dorsal base of right lung accessory lobe')
        medialBaseOfLeftLung = lung_terms.get_lung_term("medial base of left lung")
        medialBaseOfRightLung = lung_terms.get_lung_term("medial base of right lung")
        brainstemDorsalMidlineCaudalPoint = brainstem_terms.get_brainstem_term('brainstem dorsal midline caudal point')
        brainstemDorsalMidlineCranialPoint = brainstem_terms.get_brainstem_term('brainstem dorsal midline cranial point')
        brainstemVentralMidlineCaudalPoint = brainstem_terms.get_brainstem_term('brainstem ventral midline caudal point')
        brainstemVentralMidlineCranialPoint = brainstem_terms.get_brainstem_term('brainstem ventral midline cranial point')

        # marker coordinates. In future we want to have only one table for all species.
        if isRat:
            bodyMarkerPoints = [
                {"group": ("left hip joint", ''), "x": [0.367, 0.266, 0.477]},
                {"group": ("right hip joint", ''), "x": [-0.367, 0.266, 0.477]},
                {"group": ("left shoulder joint", ''), "x": [0.456, -0.071, 2.705]},
                {"group": ("right shoulder joint", ''), "x": [-0.456, -0.071, 2.705]},
                {"group": ("along left femur", ''), "x": [0.456, 0.07, 0.633]},
                {"group": ("along right femur", ''), "x": [-0.456, 0.07, 0.633]},
                {"group": ("along left humerus", ''), "x": [0.423, -0.173, 2.545]},
                {"group": ("along right humerus", ''), "x": [-0.423, -0.173, 2.545]},
                {"group": apexOfUrinaryBladder, "x": [-0.124, -0.383, 0.434]},
                {"group": leftUreterJunctionWithBladder, "x": [-0.111, -0.172, 0.354]},
                {"group": rightUreterJunctionWithBladder, "x": [-0.03, -0.196, 0.363]},
                {"group": urethraJunctionWithBladderDorsal, "x": [-0.03, -0.26, 0.209]},
                {"group": urethraJunctionWithBladderVentral, "x": [-0.037, -0.304, 0.203]},
                {"group": brainstemDorsalMidlineCaudalPoint, "x": [-0.032, 0.418, 2.713]},
                {"group": brainstemDorsalMidlineCranialPoint, "x": [-0.017, 0.203, 2.941]},
                {"group": brainstemVentralMidlineCaudalPoint, "x": [-0.028, 0.388, 2.72]},
                {"group": brainstemVentralMidlineCranialPoint, "x": [-0.019, 0.167, 2.95]},
                {"group": apexOfHeart, "x": [0.096, -0.128, 1.601]},
                {"group": leftAtriumEpicardiumVenousMidpoint, "x": [0.127, -0.083, 2.079]},
                {"group": rightAtriumEpicardiumVenousMidpoint, "x": [0.039, -0.082, 2.075]},
                {"group": apexOfLeftLung, "x": [0.172, -0.175, 2.337]},
                {"group": ventralBaseOfLeftLung, "x": [0.274, -0.285, 1.602]},
                {"group": dorsalBaseOfLeftLung, "x": [0.037, 0.31, 1.649]},
                {"group": apexOfRightLung, "x": [-0.086, -0.096, 2.311]},
                {"group": ventralBaseOfRightLung, "x": [0.14, -0.357, 1.662]},
                {"group": dorsalBaseOfRightLung, "x": [-0.054, 0.304, 1.667]},
                {"group": laterodorsalTipOfMiddleLobeOfRightLung, "x": [-0.258, -0.173, 2.013]},
                {"group": apexOfRightLungAccessoryLobe, "x": [0.041, -0.063, 1.965]},
                {"group": ventralBaseOfRightLungAccessoryLobe, "x": [0.143, -0.356, 1.66]},
                {"group": dorsalBaseOfRightLungAccessoryLobe, "x": [0.121, -0.067, 1.627]},
                {"group": gastroesophagalJunctionOnLesserCurvature, "x": [0.12, 0.009, 1.446]},
                {"group": limitingRidgeOnGreaterCurvature, "x": [0.318, 0.097, 1.406]},
                {"group": pylorusOnGreaterCurvature, "x": [0.08, -0.111, 1.443]},
            ]
        elif isHuman:
            bodyMarkerPoints = [
                {"group": urethraJunctionWithBladderDorsal, "x": [-0.0071, -0.2439, 0.1798]},
                {"group": urethraJunctionWithBladderVentral, "x": [-0.007, -0.2528, 0.1732]},
                {"group": leftUreterJunctionWithBladder, "x": [0.1074, 0.045, 0.1728]},
                {"group": rightUreterJunctionWithBladder, "x": [-0.1058, 0.0533, 0.1701]},
                {"group": apexOfUrinaryBladder, "x": [0.005, 0.1286, 0.1264]},
                {"group": brainstemDorsalMidlineCaudalPoint, "x": [0.0068, 0.427, 2.7389]},
                {"group": brainstemDorsalMidlineCranialPoint, "x": [0.008, -0.0231, 3.0778]},
                {"group": brainstemVentralMidlineCaudalPoint, "x": [0.0054, 0.3041, 2.7374]},
                {"group": brainstemVentralMidlineCranialPoint, "x": [0.0025, -0.2308, 3.091]},
                {"group": apexOfHeart, "x": [0.1373, -0.1855, 1.421]},
                {"group": leftAtriumEpicardiumVenousMidpoint, "x": [0.0024, 0.1452, 1.8022]},
                {"group": rightAtriumEpicardiumVenousMidpoint, "x": [-0.0464, 0.0373, 1.7491]},
                {"group": apexOfLeftLung, "x": [0.0655, -0.0873, 2.3564]},
                {"group": apexOfRightLung, "x": [-0.088, -0.0363, 2.3518]},
                {"group": laterodorsalTipOfMiddleLobeOfRightLung, "x": [-0.2838, -0.0933, 1.9962]},
                {"group": ventralBaseOfLeftLung, "x": [0.219, -0.2866, 1.4602]},
                {"group": medialBaseOfLeftLung, "x": [0.0426, -0.0201, 1.4109]},
                {"group": ventralBaseOfRightLung, "x": [-0.2302, -0.2356, 1.3926]},
                {"group": medialBaseOfRightLung, "x": [-0.0363, 0.0589, 1.3984]},
                {"group": dorsalBaseOfLeftLung, "x": [0.1544, 0.2603, 1.3691]},
                {"group": dorsalBaseOfRightLung, "x": [0.0369, -0.2524, 0.912]},
                {"group": gastroesophagalJunctionOnLesserCurvature, "x": [-0.0062, -0.3259, 0.8586]},
                {"group": pylorusOnGreaterCurvature, "x": [-0.0761, -0.3189, 0.8663]},
                {"group": junctionBetweenFundusAndBodyOnGreaterCurvature, "x": [0.1884, -0.1839, 0.9639]},
            ]

        nodeIdentifier = cylinder1._endNodeIdentifier
        findMarkerLocation = fieldmodule.createFieldFindMeshLocation(markerBodyCoordinates, bodyCoordinates, mesh)
        findMarkerLocation.setSearchMode(FieldFindMeshLocation.SEARCH_MODE_EXACT)
        for bodyMarkerPoint in bodyMarkerPoints:
            markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal)
            fieldcache.setNode(markerPoint)
            markerBodyCoordinates.assignReal(fieldcache, bodyMarkerPoint["x"])
            markerName.assignString(fieldcache, bodyMarkerPoint["group"][0])

            element, xi = findMarkerLocation.evaluateMeshLocation(fieldcache, 3)
            markerLocation.assignMeshLocation(fieldcache, element, xi)
            nodeIdentifier += 1

        return annotationGroups
    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']
        isCat = 'Cat 1' in parameterSetName
        isHuman = 'Human 1' in parameterSetName
        isMouse = 'Mouse 1' in parameterSetName
        isRat = 'Rat 1' in parameterSetName
        isPig = 'Pig 1' in parameterSetName
        isSheep = 'Sheep 1' in parameterSetName

        centralPath = options['Central path']
        brainstemPath = cls.centralPathDefaultScaffoldPackages['Brainstem 1']
        elementsCountAcrossMajor = options['Number of elements across major']
        elementsCountAcrossMinor = options['Number of elements across minor']
        elementsCountAlong = options['Number of elements along']

        # Cross section at Z axis
        halfBrainStem = False
        if halfBrainStem:
            elementsCountAcrossMajor //= 2
        elementsPerLayer = (
            (elementsCountAcrossMajor - 2) *
            elementsCountAcrossMinor) + (2 * (elementsCountAcrossMinor - 2))

        fm = region.getFieldmodule()
        cache = fm.createFieldcache()
        coordinates = findOrCreateFieldCoordinates(fm)
        mesh = fm.findMeshByDimension(3)

        # Annotation groups
        brainstemGroup = AnnotationGroup(region,
                                         get_brainstem_term('brainstem'))
        brainstemMeshGroup = brainstemGroup.getMeshGroup(mesh)
        midbrainGroup = AnnotationGroup(region, get_brainstem_term('midbrain'))
        midbrainMeshGroup = midbrainGroup.getMeshGroup(mesh)
        ponsGroup = AnnotationGroup(region, get_brainstem_term('pons'))
        ponsMeshGroup = ponsGroup.getMeshGroup(mesh)
        medullaGroup = AnnotationGroup(region,
                                       get_brainstem_term('medulla oblongata'))
        medullaMeshGroup = medullaGroup.getMeshGroup(mesh)
        annotationGroups = [
            brainstemGroup, midbrainGroup, ponsGroup, medullaGroup
        ]

        annotationGroupAlong = [[brainstemGroup, midbrainGroup],
                                [brainstemGroup, ponsGroup],
                                [brainstemGroup, medullaGroup]]

        # point markers
        # centralCanal = findOrCreateAnnotationGroupForTerm(annotationGroups, region,
        #                                                        get_brainstem_term('central canal of spinal cord'))
        # cerebralAqueduct = findOrCreateAnnotationGroupForTerm(annotationGroups, region,
        #                                                        get_brainstem_term('cerebral aqueduct'))
        # foramenCaecum = findOrCreateAnnotationGroupForTerm(annotationGroups, region,
        #                                                        get_brainstem_term('foramen caecum of medulla oblongata'))
        dorsalMidCaudalGroup = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term('brainstem dorsal midline caudal point'))
        ventralMidCaudalGroup = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term('brainstem ventral midline caudal point'))
        dorsalMidCranGroup = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term('brainstem dorsal midline cranial point'))
        ventralMidCranGroup = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term('brainstem ventral midline cranial point'))
        dorsalMidMedullaPonsJunction = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term(
                'brainstem dorsal midline pons-medulla junction'))
        ventralMidMedullaPonsJunction = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term(
                'brainstem ventral midline pons-medulla junction'))
        dorsalMidMidbrainPonsJunction = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term(
                'brainstem dorsal midline midbrain-pons junction'))
        ventralMidMidbrainPonsJunction = findOrCreateAnnotationGroupForTerm(
            annotationGroups, region,
            get_brainstem_term(
                'brainstem ventral midline midbrain-pons junction'))

        #######################
        # CREATE MAIN BODY MESH
        #######################
        cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if not halfBrainStem else CylinderShape.CYLINDER_SHAPE_LOWER_HALF

        # Body coordinates
        cylinderCentralPath = CylinderCentralPath(region, centralPath,
                                                  elementsCountAlong)
        base = CylinderEnds(elementsCountAcrossMajor,
                            elementsCountAcrossMinor,
                            centre=[0.0, 0.0, 0.0],
                            alongAxis=cylinderCentralPath.alongAxis[0],
                            majorAxis=cylinderCentralPath.majorAxis[0],
                            minorRadius=cylinderCentralPath.minorRadii[0])

        cylinder1 = CylinderMesh(fm,
                                 coordinates,
                                 elementsCountAlong,
                                 base,
                                 cylinderShape=cylinderShape,
                                 cylinderCentralPath=cylinderCentralPath,
                                 useCrossDerivatives=False)

        brainstem_coordinates = findOrCreateFieldCoordinates(
            fm, name="brainstem coordinates")

        # Brain coordinates
        tmp_region = region.createRegion()
        tmp_fm = tmp_region.getFieldmodule()
        tmp_brainstem_coordinates = findOrCreateFieldCoordinates(
            tmp_fm, name="brainstem coordinates")

        cylinderCentralPath1 = CylinderCentralPath(tmp_region, brainstemPath,
                                                   elementsCountAlong)

        base1 = CylinderEnds(elementsCountAcrossMajor,
                             elementsCountAcrossMinor,
                             centre=[0.0, 0.0, 0.0],
                             alongAxis=cylinderCentralPath1.alongAxis[0],
                             majorAxis=cylinderCentralPath1.majorAxis[0],
                             minorRadius=cylinderCentralPath1.minorRadii[0])

        cylinder2 = CylinderMesh(tmp_fm,
                                 tmp_brainstem_coordinates,
                                 elementsCountAlong,
                                 base1,
                                 cylinderShape=cylinderShape,
                                 cylinderCentralPath=cylinderCentralPath1,
                                 useCrossDerivatives=False)

        # Write two coordinates
        sir = tmp_region.createStreaminformationRegion()
        srm = sir.createStreamresourceMemory()
        tmp_region.write(sir)
        result, buffer = srm.getBuffer()

        sir = region.createStreaminformationRegion()
        srm = sir.createStreamresourceMemoryBuffer(buffer)
        region.read(sir)

        del srm
        del sir
        del tmp_fm
        del tmp_brainstem_coordinates
        del tmp_region

        # Annotating groups
        iRegionBoundaries = [
            int(6 * elementsCountAlong / 15),
            int(13 * elementsCountAlong / 15)
        ]
        for elementIdentifier in range(1, mesh.getSize() + 1):
            element = mesh.findElementByIdentifier(elementIdentifier)
            brainstemMeshGroup.addElement(element)
            if elementIdentifier > (iRegionBoundaries[-1] * elementsPerLayer):
                midbrainMeshGroup.addElement(element)
            elif (elementIdentifier >
                  (iRegionBoundaries[0] * elementsPerLayer)) and (
                      elementIdentifier <=
                      (iRegionBoundaries[-1] * elementsPerLayer)):
                ponsMeshGroup.addElement(element)
            else:
                medullaMeshGroup.addElement(element)

        ################
        # point markers
        ################
        pointMarkers = [
            {
                "group": dorsalMidCaudalGroup,
                "marker_brainstem_coordinates": [0.0, 1.0, 0.0]
            },
            {
                "group": ventralMidCaudalGroup,
                "marker_brainstem_coordinates": [0.0, -1.0, 0.0]
            },
            {
                "group": dorsalMidCranGroup,
                "marker_brainstem_coordinates": [0.0, 1.0, 8.0]
            },
            {
                "group": ventralMidCranGroup,
                "marker_brainstem_coordinates": [0.0, -1.0, 8.0]
            },
            {
                "group": dorsalMidMedullaPonsJunction,
                "marker_brainstem_coordinates": [0.0, 1.0, 3.0]
            },
            {
                "group": ventralMidMedullaPonsJunction,
                "marker_brainstem_coordinates": [0.0, -1.0, 3.0]
            },
            {
                "group": dorsalMidMidbrainPonsJunction,
                "marker_brainstem_coordinates": [0.0, 1.0, 6.0]
            },
            {
                "group": ventralMidMidbrainPonsJunction,
                "marker_brainstem_coordinates": [0.0, -1.0, 6.0]
            },
        ]

        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()
        markerBrainstemCoordinates = findOrCreateFieldCoordinates(
            fm, name="marker_body_coordinates")
        markerTemplateInternal = nodes.createNodetemplate()
        markerTemplateInternal.defineField(markerName)
        markerTemplateInternal.defineField(markerLocation)
        markerTemplateInternal.defineField(markerBrainstemCoordinates)

        cache = fm.createFieldcache()

        brainstemNodesetGroup = brainstemGroup.getNodesetGroup(nodes)

        nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1)
        findMarkerLocation = fm.createFieldFindMeshLocation(
            markerBrainstemCoordinates, brainstem_coordinates, mesh)
        findMarkerLocation.setSearchMode(
            FieldFindMeshLocation.SEARCH_MODE_EXACT)

        for pointMarker in pointMarkers:
            group = pointMarker["group"]
            markerPoint = markerPoints.createNode(nodeIdentifier,
                                                  markerTemplateInternal)
            cache.setNode(markerPoint)

            markerBrainstemCoordinates.assignReal(
                cache, pointMarker["marker_brainstem_coordinates"])
            markerName.assignString(cache, group.getName())

            element, xi = findMarkerLocation.evaluateMeshLocation(cache, 3)
            markerLocation.assignMeshLocation(cache, element, xi)
            group.getNodesetGroup(nodes).addNode(markerPoint)
            brainstemNodesetGroup.addNode(markerPoint)
            nodeIdentifier += 1

        return annotationGroups
    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']
        isCat = 'Cat 1' in parameterSetName
        isHuman = 'Human 1' in parameterSetName
        isMouse = 'Mouse 1' in parameterSetName
        isRat = 'Rat 1' in parameterSetName
        isPig = 'Pig 1' in parameterSetName
        isSheep = 'Sheep 1' in parameterSetName

        centralPath = options['Central path']
        brainstemPath = cls.centralPathDefaultScaffoldPackages['Brainstem 1']
        elementsCountAcrossMajor = options['Number of elements across major']
        elementsCountAcrossMinor = options['Number of elements across minor']
        elementsCountAlong = options['Number of elements along']

        # Cross section at Z axis
        halfBrainStem = False
        if halfBrainStem:
            elementsCountAcrossMajor //= 2
        elementsPerLayer = ((elementsCountAcrossMajor - 2) * elementsCountAcrossMinor) + (
                2 * (elementsCountAcrossMinor - 2))

        fm = region.getFieldmodule()
        cache = fm.createFieldcache()
        coordinates = findOrCreateFieldCoordinates(fm)
        mesh = fm.findMeshByDimension(3)

        # Annotation groups
        brainstemGroup = AnnotationGroup(region, get_brainstem_term('brainstem'))
        brainstemMeshGroup = brainstemGroup.getMeshGroup(mesh)
        midbrainGroup = AnnotationGroup(region, get_brainstem_term('midbrain'))
        midbrainMeshGroup = midbrainGroup.getMeshGroup(mesh)
        ponsGroup = AnnotationGroup(region, get_brainstem_term('pons'))
        ponsMeshGroup = ponsGroup.getMeshGroup(mesh)
        medullaGroup = AnnotationGroup(region, get_brainstem_term('medulla oblongata'))
        medullaMeshGroup = medullaGroup.getMeshGroup(mesh)
        annotationGroups = [brainstemGroup, midbrainGroup, ponsGroup, medullaGroup]

        annotationGroupAlong = [[brainstemGroup, midbrainGroup],
                                [brainstemGroup, ponsGroup],
                                [brainstemGroup, medullaGroup]]
        # centralCanal = findOrCreateAnnotationGroupForTerm(annotationGroups, region,
        #                                                        get_brainstem_term('central canal of spinal cord'))
        # cerebralAqueduct = findOrCreateAnnotationGroupForTerm(annotationGroups, region,
        #                                                        get_brainstem_term('cerebral aqueduct'))
        # foramenCaecum = findOrCreateAnnotationGroupForTerm(annotationGroups, region,

        #######################
        # CREATE MAIN BODY MESH
        #######################
        cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if not halfBrainStem else CylinderShape.CYLINDER_SHAPE_LOWER_HALF

        # brainstem coordinates
        cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong)
        base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor,
                            centre=[0.0, 0.0, 0.0],
                            alongAxis=cylinderCentralPath.alongAxis[0],
                            majorAxis=cylinderCentralPath.majorAxis[0],
                            minorRadius=cylinderCentralPath.minorRadii[0])

        cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base,
                                 cylinderShape=cylinderShape,
                                 cylinderCentralPath=cylinderCentralPath,
                                 useCrossDerivatives=False)

        #  workaround for old Zinc field wrapper bug: must create brainstem coordinates field before reading file
        brainstem_coordinates = findOrCreateFieldCoordinates(fm, name="brainstem coordinates")

        # generate brainstem coordinates field in temporary region
        tmp_region = region.createRegion()
        tmp_fm = tmp_region.getFieldmodule()
        with ChangeManager(tmp_fm):
            tmp_brainstem_coordinates = findOrCreateFieldCoordinates(tmp_fm, name="brainstem coordinates")

            cylinderCentralPath1 = CylinderCentralPath(tmp_region, brainstemPath, elementsCountAlong)

            base1 = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor,
                                 centre=[0.0, 0.0, 0.0],
                                 alongAxis=cylinderCentralPath1.alongAxis[0],
                                 majorAxis=cylinderCentralPath1.majorAxis[0],
                                 minorRadius=cylinderCentralPath1.minorRadii[0])

            cylinder2 = CylinderMesh(tmp_fm, tmp_brainstem_coordinates, elementsCountAlong, base1,
                                     cylinderShape=cylinderShape,
                                     cylinderCentralPath=cylinderCentralPath1,
                                     useCrossDerivatives=False)

            # write to memory buffer
            sir = tmp_region.createStreaminformationRegion()
            srm = sir.createStreamresourceMemory()
            tmp_region.write(sir)
            result, buffer = srm.getBuffer()

            # read into main region
            sir = region.createStreaminformationRegion()
            srm = sir.createStreamresourceMemoryBuffer(buffer)
            region.read(sir)

            del srm
            del sir
            del tmp_brainstem_coordinates
        del tmp_fm
        del tmp_region

        # Annotating groups
        iRegionBoundaries = [int(6 * elementsCountAlong / 15), int(13 * elementsCountAlong / 15)]
        for elementIdentifier in range(1, mesh.getSize() + 1):
            element = mesh.findElementByIdentifier(elementIdentifier)
            brainstemMeshGroup.addElement(element)
            if elementIdentifier > (iRegionBoundaries[-1] * elementsPerLayer):
                midbrainMeshGroup.addElement(element)
            elif (elementIdentifier > (iRegionBoundaries[0] * elementsPerLayer)) and (
                    elementIdentifier <= (iRegionBoundaries[-1] * elementsPerLayer)):
                ponsMeshGroup.addElement(element)
            else:
                medullaMeshGroup.addElement(element)

        ################
        # point markers
        ################

        markerTermNameBrainstemCoordinatesMap = {
            'brainstem dorsal midline caudal point': [0.0, 1.0, 0.0],
            'brainstem ventral midline caudal point': [0.0, -1.0, 0.0],
            'brainstem dorsal midline cranial point': [0.0, 1.0, 8.0],
            'brainstem ventral midline cranial point': [0.0, -1.0, 8.0],
            'brainstem dorsal midline pons-medulla junction': [0.0, 1.0, 3.0],
            'brainstem ventral midline pons-medulla junction': [0.0, -1.0, 3.0],
            'brainstem dorsal midline midbrain-pons junction': [0.0, 1.0, 6.0],
            'brainstem ventral midline midbrain-pons junction': [0.0, -1.0, 6.0]
        }
        nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
        nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1)
        for termName, brainstemCoordinatesValues in markerTermNameBrainstemCoordinatesMap.items():
            annotationGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_brainstem_term(termName))
            annotationGroup.createMarkerNode(nodeIdentifier, brainstem_coordinates, brainstemCoordinatesValues)
            nodeIdentifier += 1

        return annotationGroups