def make_tube_bifurcation_elements_2d(region, coordinates, elementIdentifier, paNodeId, paStartIndex, c1NodeId, c1StartIndex, c2NodeId, c2StartIndex, roNodeId, coNodeId, useCrossDerivatives=False): ''' Creates elements from parent, ring/row, crotch/column, child1 and child2 nodes. Assumes client has active ChangeManager(fieldmodule). :param paNodeId, paStartIndex, c1NodeId, c1StartIndex, c2NodeId, c2StartIndex: Lists of parent, child1, child2 nodes and their starting index to be at hex2 :param roNodeId, coNodeId: Lists of ring/row and crotch/column nodes, starting at hex2 and between hex1 and hex2, respectively. :return next elementIdentifier. ''' paCount = len(paNodeId) c1Count = len(c1NodeId) c2Count = len(c2NodeId) pac1Count, pac2Count, c1c2Count = get_tube_bifurcation_connection_elements_counts( paCount, c1Count, c2Count) fieldmodule = region.getFieldmodule() mesh = fieldmodule.findMeshByDimension(2) elementtemplateStd = mesh.createElementtemplate() elementtemplateStd.setElementShapeType(Element.SHAPE_TYPE_SQUARE) bicubicHermiteBasis = fieldmodule.createElementbasis( 2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) eftStd = mesh.createElementfieldtemplate(bicubicHermiteBasis) if not useCrossDerivatives: for n in range(4): eftStd.setFunctionNumberOfTerms(n * 4 + 4, 0) elementtemplateStd.defineField(coordinates, -1, eftStd) elementtemplateMod = mesh.createElementtemplate() elementtemplateMod.setElementShapeType(Element.SHAPE_TYPE_SQUARE) for e1 in range(paCount): eft = eftStd elementtemplate = elementtemplateStd np = e1 + paStartIndex nids = [ paNodeId[np % paCount], paNodeId[(np + 1) % paCount], roNodeId[e1], roNodeId[(e1 + 1) % paCount] ] scalefactors = None meshGroups = [] if e1 in (0, pac1Count - 1, pac1Count, paCount - 1): eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) if not useCrossDerivatives: for n in range(4): eft.setFunctionNumberOfTerms(n * 4 + 4, 0) if e1 in (0, pac1Count): scalefactors = [-1.0] setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elif e1 in (pac1Count - 1, paCount - 1): remapEftNodeValueLabel(eft, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateMod.defineField(coordinates, -1, eft) elementtemplate = elementtemplateMod element = mesh.createElement(elementIdentifier, elementtemplate) result2 = element.setNodesByIdentifier(eft, nids) if scalefactors: result3 = element.setScaleFactors(eft, scalefactors) else: result3 = '-' #print('create element tube bifurcation pa', element.isValid(), elementIdentifier, result2, result3, nids) elementIdentifier += 1 for meshGroup in meshGroups: meshGroup.addElement(element) for e1 in range(c1Count): eft = eftStd elementtemplate = elementtemplateStd nr = e1 nc = e1 + c1StartIndex nids = [ roNodeId[nr % paCount], roNodeId[(nr + 1) % paCount], c1NodeId[nc % c1Count], c1NodeId[(nc + 1) % c1Count] ] if e1 >= pac1Count: nids[1] = roNodeId[0] if (e1 == (c1Count - 1)) else coNodeId[e1 - pac1Count] if e1 > pac1Count: #nids[0] = coNodeId[(e1 - pac1Count - 1)] nids[0] = coNodeId[(e1 - pac1Count - 1) % c1Count] scalefactors = None meshGroups = [] if e1 in (0, pac1Count, c1Count - 1): eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) if not useCrossDerivatives: for n in range(4): eft.setFunctionNumberOfTerms(n * 4 + 4, 0) if e1 == 0: scalefactors = [-1.0] setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, [1], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elif e1 == pac1Count: remapEftNodeValueLabel(eft, [1], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elif e1 == (c1Count - 1): scalefactors = [-1.0] setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, [2], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, [2], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateMod.defineField(coordinates, -1, eft) elementtemplate = elementtemplateMod element = mesh.createElement(elementIdentifier, elementtemplate) result2 = element.setNodesByIdentifier(eft, nids) if scalefactors: result3 = element.setScaleFactors(eft, scalefactors) else: result3 = '-' #print('create element tube bifurcation c1', element.isValid(), elementIdentifier, result2, result3, nids) elementIdentifier += 1 for meshGroup in meshGroups: meshGroup.addElement(element) for e1 in range(c2Count): eft = eftStd elementtemplate = elementtemplateStd nr = 0 if (e1 == 0) else (paCount - c2Count + e1) nc = e1 + c2StartIndex nids = [ roNodeId[nr % paCount], roNodeId[(nr + 1) % paCount], c2NodeId[nc % c2Count], c2NodeId[(nc + 1) % c2Count] ] if 0 <= e1 < (c1c2Count - 1): nids[1] = coNodeId[c1c2Count - e1 - 2] if 0 < e1 <= (c1c2Count - 1): nids[0] = coNodeId[c1c2Count - e1 - 1] scalefactors = None meshGroups = [] if e1 <= c1c2Count: eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) if not useCrossDerivatives: for n in range(4): eft.setFunctionNumberOfTerms(n * 4 + 4, 0) scalefactors = [-1.0] setEftScaleFactorIds(eft, [1], []) if e1 == 0: remapEftNodeValueLabel(eft, [1], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) scaleEftNodeValueLabels( eft, [2], [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2], [1]) elif e1 < (c1c2Count - 1): scaleEftNodeValueLabels( eft, [1, 2], [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2], [1]) elif e1 == (c1c2Count - 1): scaleEftNodeValueLabels( eft, [1], [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2], [1]) remapEftNodeValueLabel(eft, [2], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, [2], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elif e1 == c1c2Count: remapEftNodeValueLabel(eft, [1], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateMod.defineField(coordinates, -1, eft) elementtemplate = elementtemplateMod element = mesh.createElement(elementIdentifier, elementtemplate) result2 = element.setNodesByIdentifier(eft, nids) if scalefactors: result3 = element.setScaleFactors(eft, scalefactors) else: result3 = '-' #print('create element tube bifurcation c2', element.isValid(), elementIdentifier, result2, result3, nids) elementIdentifier += 1 for meshGroup in meshGroups: meshGroup.addElement(element) return elementIdentifier
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
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