def defineFaceAnnotations(cls, region, options, annotationGroups): """ Add face annotation groups from the highest dimension mesh. Must have defined faces and added subelements for highest dimension groups. :param region: Zinc region containing model. :param options: Dict containing options. See getDefaultOptions(). :param annotationGroups: List of annotation groups for top-level elements. New face annotation groups are appended to this list. """ # add epicardium of fibrous ring fm = region.getFieldmodule() MeshType_3d_heartventriclesbase1.defineFaceAnnotations( region, options, annotationGroups) MeshType_3d_heartatria1.defineFaceAnnotations(region, options, annotationGroups) lFibrousRingGroup = getAnnotationGroupForTerm( annotationGroups, get_heart_term("left fibrous ring")) rFibrousRingGroup = getAnnotationGroupForTerm( annotationGroups, get_heart_term("right fibrous ring")) epiGroup = getAnnotationGroupForTerm(annotationGroups, get_heart_term("epicardium")) mesh2d = fm.findMeshByDimension(2) is_exterior_face_xi3_1 = fm.createFieldAnd( fm.createFieldIsExterior(), fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) is_non_septal_fibrous_ring = fm.createFieldXor( lFibrousRingGroup.getFieldElementGroup(mesh2d), rFibrousRingGroup.getFieldElementGroup(mesh2d)) is_non_septal_fibrous_ring_epi = fm.createFieldAnd( is_non_septal_fibrous_ring, is_exterior_face_xi3_1) epiGroup.getMeshGroup(mesh2d).addElementsConditional( is_non_septal_fibrous_ring_epi)
def test_heart1(self): """ Test creation of heart scaffold. """ scaffold = MeshType_3d_heart1 parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, [ "Default", "Human 1", "Mouse 1", "Pig 1", "Rat 1", "Unit Human 1", "Unit Mouse 1", "Unit Pig 1", "Unit Rat 1" ]) options = scaffold.getDefaultOptions("Human 1") self.assertEqual(123, len(options)) self.assertEqual(0.9, options.get("LV outer height")) self.assertEqual(80.0, options.get("Unit scale")) self.assertEqual(7, options.get("Number of elements around LV free wall")) self.assertEqual(7, options.get("Number of elements around RV free wall")) # simplify atria self.assertEqual(8, options.get("Number of elements over atria")) options["Number of elements over atria"] = 6 self.assertEqual( 2, options.get("Number of elements radial pulmonary vein annuli")) options["Number of elements radial pulmonary vein annuli"] = 1 self.assertFalse(scaffold.checkOptions(options)) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = scaffold.generateMesh(region, options) self.assertEqual(32, len(annotationGroups)) fieldmodule = region.getFieldmodule() mesh3d = fieldmodule.findMeshByDimension(3) self.assertEqual(332, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) self.assertEqual(1287, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(1567, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self.assertEqual(614, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) # check coordinates range, epicardium surface area and volume coordinates = fieldmodule.findFieldByName( "coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) assertAlmostEqualList(self, minimums, [-50.7876375290527, -58.42494589146976, -91.6], 1.0E-6) assertAlmostEqualList( self, maximums, [43.810947610743156, 39.03925080604259, 42.018608492002784], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) epicardiumGroup = fieldmodule.findFieldByName( 'epicardium').castGroup() self.assertTrue(epicardiumGroup.isValid()) epicardiumMeshGroup = epicardiumGroup.getFieldElementGroup( mesh2d).getMeshGroup() self.assertTrue(epicardiumMeshGroup.isValid()) surfaceAreaField = fieldmodule.createFieldMeshIntegral( one, coordinates, epicardiumMeshGroup) surfaceAreaField.setNumbersOfPoints(4) volumeField = fieldmodule.createFieldMeshIntegral( one, coordinates, mesh3d) volumeField.setNumbersOfPoints(3) fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(surfaceArea, 36541.36513577538, delta=1.0E-2) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 218014.81436425756, delta=1.0E-1) # check some annotationGroups: expectedSizes3d = { "left ventricle myocardium": 110, "right ventricle myocardium": 95, "interventricular septum": 37, "left atrium myocardium": 88, "right atrium myocardium": 80, "interatrial septum": 23 } for name in expectedSizes3d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh3d).getSize() self.assertEqual(expectedSizes3d[name], size, name) expectedSizes2d = { "endocardium of left ventricle": 88, "endocardium of right ventricle": 73, "endocardium of left atrium": 82, "endocardium of right atrium": 74, "epicardium": 229 } for name in expectedSizes2d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh2d).getSize() self.assertEqual(expectedSizes2d[name], size, name) # test finding a marker in scaffold markerGroup = fieldmodule.findFieldByName("marker").castGroup() markerNodes = markerGroup.getFieldNodeGroup(nodes).getNodesetGroup() self.assertEqual(7, markerNodes.getSize()) markerName = fieldmodule.findFieldByName("marker_name") self.assertTrue(markerName.isValid()) markerLocation = fieldmodule.findFieldByName("marker_location") self.assertTrue(markerLocation.isValid()) # test apex marker point cache = fieldmodule.createFieldcache() node = findNodeWithName(markerNodes, markerName, "apex of heart") self.assertTrue(node.isValid()) cache.setNode(node) element, xi = markerLocation.evaluateMeshLocation(cache, 3) self.assertEqual(1, element.getIdentifier()) assertAlmostEqualList(self, xi, [0.0, 0.0, 1.0], 1.0E-10) apexGroup = getAnnotationGroupForTerm(annotationGroups, get_heart_term("apex of heart")) self.assertTrue(apexGroup.getNodesetGroup(nodes).containsNode(node)) # refine 2x2x2 and check result # first remove any face (but not point) annotation groups as they are re-added by defineFaceAnnotations removeAnnotationGroups = [] for annotationGroup in annotationGroups: if (not annotationGroup.hasMeshGroup(mesh3d)) and ( annotationGroup.hasMeshGroup(mesh2d) or annotationGroup.hasMeshGroup(mesh1d)): removeAnnotationGroups.append(annotationGroup) for annotationGroup in removeAnnotationGroups: annotationGroups.remove(annotationGroup) self.assertEqual(23, len(annotationGroups)) refineRegion = region.createRegion() refineFieldmodule = refineRegion.getFieldmodule() options['Refine number of elements surface'] = 2 options['Refine number of elements through LV wall'] = 2 options['Refine number of elements through wall'] = 2 meshrefinement = MeshRefinement(region, refineRegion, annotationGroups) scaffold.refineMesh(meshrefinement, options) annotationGroups = meshrefinement.getAnnotationGroups() refineFieldmodule.defineAllFaces() oldAnnotationGroups = copy.copy(annotationGroups) for annotationGroup in annotationGroups: annotationGroup.addSubelements() scaffold.defineFaceAnnotations(refineRegion, options, annotationGroups) for annotation in annotationGroups: if annotation not in oldAnnotationGroups: annotationGroup.addSubelements() self.assertEqual(32, len(annotationGroups)) mesh3d = refineFieldmodule.findMeshByDimension(3) self.assertEqual(2580, mesh3d.getSize()) mesh2d = refineFieldmodule.findMeshByDimension(2) self.assertEqual(8872, mesh2d.getSize()) mesh1d = refineFieldmodule.findMeshByDimension(1) self.assertEqual(9983, mesh1d.getSize()) nodes = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self.assertEqual(3693, nodes.getSize()) datapoints = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) # check some refined annotationGroups: for name in expectedSizes3d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh3d).getSize() self.assertEqual(expectedSizes3d[name] * 8, size, name) for name in expectedSizes2d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh2d).getSize() if name == "epicardium": # fibrous ring is only refined by 1 through its thickness fibrousRingReduction = ( options['Refine number of elements surface'] - 1 ) * options['Refine number of elements surface'] * ( options['Number of elements around left atrium free wall'] + options['Number of elements around right atrium free wall'] ) self.assertEqual( expectedSizes2d[name] * 4 - fibrousRingReduction, size, name) else: self.assertEqual(expectedSizes2d[name] * 4, size, name) # test finding a marker in refined scaffold markerGroup = refineFieldmodule.findFieldByName("marker").castGroup() refinedNodes = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) markerNodes = markerGroup.getFieldNodeGroup( refinedNodes).getNodesetGroup() self.assertEqual(7, markerNodes.getSize()) markerName = refineFieldmodule.findFieldByName("marker_name") self.assertTrue(markerName.isValid()) markerLocation = refineFieldmodule.findFieldByName("marker_location") self.assertTrue(markerLocation.isValid()) # test apex marker point cache = refineFieldmodule.createFieldcache() node = findNodeWithName(markerNodes, markerName, "apex of heart") self.assertTrue(node.isValid()) cache.setNode(node) element, xi = markerLocation.evaluateMeshLocation(cache, 3) self.assertEqual(5, element.getIdentifier()) assertAlmostEqualList(self, xi, [0.0, 0.0, 1.0], 1.0E-10) apexGroup = getAnnotationGroupForTerm(annotationGroups, get_heart_term("apex of heart")) self.assertTrue(apexGroup.getNodesetGroup(nodes).containsNode(node))
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
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 test_heart1(self): """ Test creation of heart scaffold. """ scaffold = MeshType_3d_heart1 parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, [ "Default", "Human 1", "Mouse 1", "Pig 1", "Rat 1", "Unit Human 1", "Unit Mouse 1", "Unit Pig 1", "Unit Rat 1" ]) options = scaffold.getDefaultOptions("Human 1") self.assertEqual(117, len(options)) self.assertEqual(0.9, options.get("LV outer height")) self.assertEqual(80.0, options.get("Unit scale")) self.assertEqual(7, options.get("Number of elements around LV free wall")) self.assertEqual(7, options.get("Number of elements around RV free wall")) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = scaffold.generateMesh(region, options) self.assertEqual(27, len(annotationGroups)) fieldmodule = region.getFieldmodule() mesh3d = fieldmodule.findMeshByDimension(3) self.assertEqual(289, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) self.assertEqual(1117, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(1356, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self.assertEqual(528, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) coordinates = fieldmodule.findFieldByName( "coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) assertAlmostEqualList(self, minimums, [-50.7876375290527, -57.76590573823474, -91.6], 1.0E-6) assertAlmostEqualList( self, maximums, [43.81084359764995, 39.03925080604259, 40.71693637558552], 1.0E-6) # check some annotationGroups: expectedSizes3d = { "left ventricle myocardium": 94, "right ventricle myocardium": 79, "interventricular septum": 30, "left atrium myocardium": 88, "right atrium myocardium": 62, "interatrial septum": 17 } for name in expectedSizes3d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh3d).getSize() self.assertEqual(expectedSizes3d[name], size, name) expectedSizes2d = { "endocardium of left ventricle": 74, "endocardium of right ventricle": 59, "endocardium of left atrium": 82, "endocardium of right atrium": 56, "epicardium": 197 } for name in expectedSizes2d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh2d).getSize() self.assertEqual(expectedSizes2d[name], size, name) # refine 2x2x2 and check result # first remove any surface annotation groups as they are re-added by defineFaceAnnotations removeAnnotationGroups = [] for annotationGroup in annotationGroups: if annotationGroup.getMeshGroup(mesh3d).getSize() == 0: removeAnnotationGroups.append(annotationGroup) for annotationGroup in removeAnnotationGroups: annotationGroups.remove(annotationGroup) self.assertEqual(18, len(annotationGroups)) refineRegion = region.createRegion() refineFieldmodule = refineRegion.getFieldmodule() options['Refine number of elements surface'] = 2 options['Refine number of elements through LV wall'] = 2 options['Refine number of elements through wall'] = 2 meshrefinement = MeshRefinement(region, refineRegion, annotationGroups) scaffold.refineMesh(meshrefinement, options) annotationGroups = meshrefinement.getAnnotationGroups() refineFieldmodule.defineAllFaces() oldAnnotationGroups = copy.copy(annotationGroups) for annotationGroup in annotationGroups: annotationGroup.addSubelements() scaffold.defineFaceAnnotations(refineRegion, options, annotationGroups) for annotation in annotationGroups: if annotation not in oldAnnotationGroups: annotationGroup.addSubelements() self.assertEqual(27, len(annotationGroups)) mesh3d = refineFieldmodule.findMeshByDimension(3) self.assertEqual(2236, mesh3d.getSize()) mesh2d = refineFieldmodule.findMeshByDimension(2) self.assertEqual(7676, mesh2d.getSize()) mesh1d = refineFieldmodule.findMeshByDimension(1) self.assertEqual(8623, mesh1d.getSize()) nodes = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self.assertEqual(3183, nodes.getSize()) datapoints = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) # check some refined annotationGroups: for name in expectedSizes3d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh3d).getSize() self.assertEqual(expectedSizes3d[name] * 8, size, name) for name in expectedSizes2d: group = getAnnotationGroupForTerm(annotationGroups, get_heart_term(name)) size = group.getMeshGroup(mesh2d).getSize() if name == "epicardium": # fibrous ring is only refined by 1 through its thickness fibrousRingReduction = ( options['Refine number of elements surface'] - 1 ) * options['Refine number of elements surface'] * ( options['Number of elements around left atrium free wall'] + options['Number of elements around right atrium free wall'] ) self.assertEqual( expectedSizes2d[name] * 4 - fibrousRingReduction, size, name) else: self.assertEqual(expectedSizes2d[name] * 4, size, name) # test finding a marker in refined scaffold markerGroup = refineFieldmodule.findFieldByName("marker").castGroup() refinedNodes = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) markerNodes = markerGroup.getFieldNodeGroup( refinedNodes).getNodesetGroup() self.assertEqual(5, markerNodes.getSize()) markerName = refineFieldmodule.findFieldByName("marker_name") self.assertTrue(markerName.isValid()) markerLocation = refineFieldmodule.findFieldByName("marker_location") self.assertTrue(markerLocation.isValid()) cache = refineFieldmodule.createFieldcache() node = findNodeWithName(markerNodes, markerName, "APEX") self.assertTrue(node.isValid()) cache.setNode(node) element, xi = markerLocation.evaluateMeshLocation(cache, 3) self.assertEqual(5, element.getIdentifier()) assertAlmostEqualList(self, xi, [0.0, 0.0, 1.0], 1.0E-10)
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. 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 = findOrCreateFieldCoordinates(fm) cache = fm.createFieldcache() mesh = fm.findMeshByDimension(3) if aorticNotPulmonary: arterialRootGroup = AnnotationGroup(region, get_heart_term("root of aorta")) cuspGroups = [ AnnotationGroup(region, get_heart_term("posterior cusp of aortic valve")), AnnotationGroup(region, get_heart_term("right cusp of aortic valve")), AnnotationGroup(region, get_heart_term("left cusp of aortic valve")) ] else: arterialRootGroup = AnnotationGroup(region, get_heart_term("root of pulmonary trunk")) cuspGroups = [ AnnotationGroup(region, get_heart_term("right cusp of pulmonary valve")), AnnotationGroup(region, get_heart_term("anterior cusp of pulmonary valve")), AnnotationGroup(region, get_heart_term("left cusp of pulmonary valve")) ] allGroups = [ arterialRootGroup ] # groups that all elements in scaffold will go in annotationGroups = allGroups + cuspGroups nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) ################# # Create 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, 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 ################# 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, 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) result3 = element.setScaleFactors(eft1, scalefactors) if scalefactors else None #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) result3 = element.setScaleFactors(eft1, scalefactors) if scalefactors else None #print('create semilunar cusp', cusp, e, 'element',elementIdentifier, result, result2, result3, nids) elementIdentifier += 1 for meshGroup in meshGroups: meshGroup.addElement(element) fm.endChange() return annotationGroups