def generateNodes(self, nodes, fieldModule, coordinates): """ Create cylinder nodes from coordinates. :param nodes: nodes from coordinates. :param fieldModule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. :param coordinates: Coordinate field to define. """ nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) self._startNodeIdentifier = nodeIdentifier nodeIdentifier = self._shield.generateNodes(fieldModule, coordinates, nodeIdentifier) self._endNodeIdentifier = nodeIdentifier
def _loadData(self): """ Load zinc data file into self._rawDataRegion. Rename data groups to exactly match model groups where they differ by case and whitespace only. Transfer data points (and converted nodes) into self._region. """ result = self._rawDataRegion.readFile(self._zincDataFileName) assert result == RESULT_OK, "Failed to load data file " + str( self._zincDataFileName) fieldmodule = self._rawDataRegion.getFieldmodule() with ChangeManager(fieldmodule): # rename data groups to match model # future: match with annotation terms modelGroupNames = [ group.getName() for group in getGroupList(self._fieldmodule) ] writeDiagnostics = self.getDiagnosticLevel() > 0 for dataGroup in getGroupList(fieldmodule): dataGroupName = dataGroup.getName() compareName = dataGroupName.strip().casefold() for modelGroupName in modelGroupNames: if modelGroupName == dataGroupName: if writeDiagnostics: print("Load data: Data group '" + dataGroupName + "' found in model") break elif modelGroupName.strip().casefold() == compareName: result = dataGroup.setName(modelGroupName) if result == RESULT_OK: if writeDiagnostics: print("Load data: Data group '" + dataGroupName + "' found in model as '" + modelGroupName + "'. Renaming to match.") else: print("Error: Load data: Data group '" + dataGroupName + "' found in model as '" + modelGroupName + "'. Renaming to match FAILED.") if fieldmodule.findFieldByName( modelGroupName).isValid(): print( " Reason: field of that name already exists." ) break else: if writeDiagnostics: print("Load data: Data group '" + dataGroupName + "' not found in model") # if there are both nodes and datapoints, offset datapoint identifiers to ensure different nodes = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) if nodes.getSize() > 0: datapoints = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) if datapoints.getSize() > 0: maximumDatapointIdentifier = max( 0, getMaximumNodeIdentifier(datapoints)) maximumNodeIdentifier = max( 0, getMaximumNodeIdentifier(nodes)) # this assumes identifiers are in low ranges and can be improved if there is a problem: identifierOffset = 100000 while (maximumDatapointIdentifier > identifierOffset) or ( maximumNodeIdentifier > identifierOffset): assert identifierOffset < 1000000000, "Invalid node and datapoint identifier ranges" identifierOffset *= 10 while True: # logic relies on datapoints being in identifier order datapoint = datapoints.createNodeiterator().next() identifier = datapoint.getIdentifier() if identifier >= identifierOffset: break result = datapoint.setIdentifier(identifier + identifierOffset) assert result == RESULT_OK, "Failed to offset datapoint identifier" # transfer nodes as datapoints to self._region sir = self._rawDataRegion.createStreaminformationRegion() srm = sir.createStreamresourceMemory() sir.setResourceDomainTypes(srm, Field.DOMAIN_TYPE_NODES) self._rawDataRegion.write(sir) result, buffer = srm.getBuffer() assert result == RESULT_OK, "Failed to write nodes" buffer = buffer.replace(bytes("!#nodeset nodes", "utf-8"), bytes("!#nodeset datapoints", "utf-8")) sir = self._region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) result = self._region.read(sir) assert result == RESULT_OK, "Failed to load nodes as datapoints" # transfer datapoints to self._region sir = self._rawDataRegion.createStreaminformationRegion() srm = sir.createStreamresourceMemory() sir.setResourceDomainTypes(srm, Field.DOMAIN_TYPE_DATAPOINTS) self._rawDataRegion.write(sir) result, buffer = srm.getBuffer() assert result == RESULT_OK, "Failed to write datapoints" sir = self._region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) result = self._region.read(sir) assert result == RESULT_OK, "Failed to load datapoints" self._discoverDataCoordinatesField() self._discoverMarkerGroup()
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(cls, region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: None """ parameterSetName = options['Base parameter set'] isCat = 'Cat 1' in parameterSetName isHuman = 'Human 1' in parameterSetName isMouse = 'Mouse 1' in parameterSetName isRat = 'Rat 1' in parameterSetName isPig = 'Pig 1' in parameterSetName isSheep = 'Sheep 1' in parameterSetName centralPath = options['Central path'] brainstemPath = cls.centralPathDefaultScaffoldPackages['Brainstem 1'] elementsCountAcrossMajor = options['Number of elements across major'] elementsCountAcrossMinor = options['Number of elements across minor'] elementsCountAlong = options['Number of elements along'] # Cross section at Z axis halfBrainStem = False if halfBrainStem: elementsCountAcrossMajor //= 2 elementsPerLayer = ( (elementsCountAcrossMajor - 2) * elementsCountAcrossMinor) + (2 * (elementsCountAcrossMinor - 2)) fm = region.getFieldmodule() cache = fm.createFieldcache() coordinates = findOrCreateFieldCoordinates(fm) mesh = fm.findMeshByDimension(3) # Annotation groups brainstemGroup = AnnotationGroup(region, get_brainstem_term('brainstem')) brainstemMeshGroup = brainstemGroup.getMeshGroup(mesh) midbrainGroup = AnnotationGroup(region, get_brainstem_term('midbrain')) midbrainMeshGroup = midbrainGroup.getMeshGroup(mesh) ponsGroup = AnnotationGroup(region, get_brainstem_term('pons')) ponsMeshGroup = ponsGroup.getMeshGroup(mesh) medullaGroup = AnnotationGroup(region, get_brainstem_term('medulla oblongata')) medullaMeshGroup = medullaGroup.getMeshGroup(mesh) annotationGroups = [ brainstemGroup, midbrainGroup, ponsGroup, medullaGroup ] annotationGroupAlong = [[brainstemGroup, midbrainGroup], [brainstemGroup, ponsGroup], [brainstemGroup, medullaGroup]] # point markers # centralCanal = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('central canal of spinal cord')) # cerebralAqueduct = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('cerebral aqueduct')) # foramenCaecum = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('foramen caecum of medulla oblongata')) dorsalMidCaudalGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem dorsal midline caudal point')) ventralMidCaudalGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem ventral midline caudal point')) dorsalMidCranGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem dorsal midline cranial point')) ventralMidCranGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem ventral midline cranial point')) dorsalMidMedullaPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem dorsal midline pons-medulla junction')) ventralMidMedullaPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem ventral midline pons-medulla junction')) dorsalMidMidbrainPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem dorsal midline midbrain-pons junction')) ventralMidMidbrainPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem ventral midline midbrain-pons junction')) ####################### # CREATE MAIN BODY MESH ####################### cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if not halfBrainStem else CylinderShape.CYLINDER_SHAPE_LOWER_HALF # Body coordinates cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong) base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, centre=[0.0, 0.0, 0.0], alongAxis=cylinderCentralPath.alongAxis[0], majorAxis=cylinderCentralPath.majorAxis[0], minorRadius=cylinderCentralPath.minorRadii[0]) cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) brainstem_coordinates = findOrCreateFieldCoordinates( fm, name="brainstem coordinates") # Brain coordinates tmp_region = region.createRegion() tmp_fm = tmp_region.getFieldmodule() tmp_brainstem_coordinates = findOrCreateFieldCoordinates( tmp_fm, name="brainstem coordinates") cylinderCentralPath1 = CylinderCentralPath(tmp_region, brainstemPath, elementsCountAlong) base1 = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, centre=[0.0, 0.0, 0.0], alongAxis=cylinderCentralPath1.alongAxis[0], majorAxis=cylinderCentralPath1.majorAxis[0], minorRadius=cylinderCentralPath1.minorRadii[0]) cylinder2 = CylinderMesh(tmp_fm, tmp_brainstem_coordinates, elementsCountAlong, base1, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath1, useCrossDerivatives=False) # Write two coordinates sir = tmp_region.createStreaminformationRegion() srm = sir.createStreamresourceMemory() tmp_region.write(sir) result, buffer = srm.getBuffer() sir = region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) region.read(sir) del srm del sir del tmp_fm del tmp_brainstem_coordinates del tmp_region # Annotating groups iRegionBoundaries = [ int(6 * elementsCountAlong / 15), int(13 * elementsCountAlong / 15) ] for elementIdentifier in range(1, mesh.getSize() + 1): element = mesh.findElementByIdentifier(elementIdentifier) brainstemMeshGroup.addElement(element) if elementIdentifier > (iRegionBoundaries[-1] * elementsPerLayer): midbrainMeshGroup.addElement(element) elif (elementIdentifier > (iRegionBoundaries[0] * elementsPerLayer)) and ( elementIdentifier <= (iRegionBoundaries[-1] * elementsPerLayer)): ponsMeshGroup.addElement(element) else: medullaMeshGroup.addElement(element) ################ # point markers ################ pointMarkers = [ { "group": dorsalMidCaudalGroup, "marker_brainstem_coordinates": [0.0, 1.0, 0.0] }, { "group": ventralMidCaudalGroup, "marker_brainstem_coordinates": [0.0, -1.0, 0.0] }, { "group": dorsalMidCranGroup, "marker_brainstem_coordinates": [0.0, 1.0, 8.0] }, { "group": ventralMidCranGroup, "marker_brainstem_coordinates": [0.0, -1.0, 8.0] }, { "group": dorsalMidMedullaPonsJunction, "marker_brainstem_coordinates": [0.0, 1.0, 3.0] }, { "group": ventralMidMedullaPonsJunction, "marker_brainstem_coordinates": [0.0, -1.0, 3.0] }, { "group": dorsalMidMidbrainPonsJunction, "marker_brainstem_coordinates": [0.0, 1.0, 6.0] }, { "group": ventralMidMidbrainPonsJunction, "marker_brainstem_coordinates": [0.0, -1.0, 6.0] }, ] markerGroup = findOrCreateFieldGroup(fm, "marker") markerName = findOrCreateFieldStoredString(fm, name="marker_name") markerLocation = findOrCreateFieldStoredMeshLocation( fm, mesh, name="marker_location") nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() markerBrainstemCoordinates = findOrCreateFieldCoordinates( fm, name="marker_body_coordinates") markerTemplateInternal = nodes.createNodetemplate() markerTemplateInternal.defineField(markerName) markerTemplateInternal.defineField(markerLocation) markerTemplateInternal.defineField(markerBrainstemCoordinates) cache = fm.createFieldcache() brainstemNodesetGroup = brainstemGroup.getNodesetGroup(nodes) nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) findMarkerLocation = fm.createFieldFindMeshLocation( markerBrainstemCoordinates, brainstem_coordinates, mesh) findMarkerLocation.setSearchMode( FieldFindMeshLocation.SEARCH_MODE_EXACT) for pointMarker in pointMarkers: group = pointMarker["group"] markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) cache.setNode(markerPoint) markerBrainstemCoordinates.assignReal( cache, pointMarker["marker_brainstem_coordinates"]) markerName.assignString(cache, group.getName()) element, xi = findMarkerLocation.evaluateMeshLocation(cache, 3) markerLocation.assignMeshLocation(cache, element, xi) group.getNodesetGroup(nodes).addNode(markerPoint) brainstemNodesetGroup.addNode(markerPoint) nodeIdentifier += 1 return annotationGroups
def generateBaseMesh(cls, region, options, 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
def _loadData(self): """ Load zinc data file into self._rawDataRegion. Transfer data points (and converted nodes) into self._region. """ result = self._rawDataRegion.readFile(self._zincDataFileName) assert result == RESULT_OK, "Failed to load data file " + str( self._zincDataFileName) # if there both nodes and datapoints, offset datapoint identifiers to ensure different fieldmodule = self._rawDataRegion.getFieldmodule() nodes = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) if nodes.getSize() > 0: datapoints = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) if datapoints.getSize() > 0: maximumDatapointIdentifier = max( 0, getMaximumNodeIdentifier(datapoints)) maximumNodeIdentifier = max(0, getMaximumNodeIdentifier(nodes)) # this assumes identifiers are in low ranges and can be improved if there is a problem: identifierOffset = 100000 while (maximumDatapointIdentifier > identifierOffset) or ( maximumNodeIdentifier > identifierOffset): assert identifierOffset < 1000000000, "Invalid node and datapoint identifier ranges" identifierOffset *= 10 with ChangeManager(fieldmodule): while True: # logic relies on datapoints being in identifier order datapoint = datapoints.createNodeiterator().next() identifier = datapoint.getIdentifier() if identifier >= identifierOffset: break result = datapoint.setIdentifier(identifier + identifierOffset) assert result == RESULT_OK, "Failed to offset datapoint identifier" # transfer nodes as datapoints to self._region sir = self._rawDataRegion.createStreaminformationRegion() srm = sir.createStreamresourceMemory() sir.setResourceDomainTypes(srm, Field.DOMAIN_TYPE_NODES) self._rawDataRegion.write(sir) result, buffer = srm.getBuffer() assert result == RESULT_OK, "Failed to write nodes" buffer = buffer.replace(bytes("!#nodeset nodes", "utf-8"), bytes("!#nodeset datapoints", "utf-8")) sir = self._region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) result = self._region.read(sir) assert result == RESULT_OK, "Failed to load nodes as datapoints" # transfer datapoints to self._region sir = self._rawDataRegion.createStreaminformationRegion() srm = sir.createStreamresourceMemory() sir.setResourceDomainTypes(srm, Field.DOMAIN_TYPE_DATAPOINTS) self._rawDataRegion.write(sir) result, buffer = srm.getBuffer() assert result == RESULT_OK, "Failed to write datapoints" sir = self._region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) result = self._region.read(sir) assert result == RESULT_OK, "Failed to load datapoints" self._discoverDataCoordinatesField() self._discoverMarkerGroup()
def generateBaseMesh(cls, region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: None """ parameterSetName = options['Base parameter set'] isCat = 'Cat 1' in parameterSetName isHuman = 'Human 1' in parameterSetName isMouse = 'Mouse 1' in parameterSetName isRat = 'Rat 1' in parameterSetName isPig = 'Pig 1' in parameterSetName isSheep = 'Sheep 1' in parameterSetName centralPath = options['Central path'] brainstemPath = cls.centralPathDefaultScaffoldPackages['Brainstem 1'] elementsCountAcrossMajor = options['Number of elements across major'] elementsCountAcrossMinor = options['Number of elements across minor'] elementsCountAlong = options['Number of elements along'] # Cross section at Z axis halfBrainStem = False if halfBrainStem: elementsCountAcrossMajor //= 2 elementsPerLayer = ((elementsCountAcrossMajor - 2) * elementsCountAcrossMinor) + ( 2 * (elementsCountAcrossMinor - 2)) fm = region.getFieldmodule() cache = fm.createFieldcache() coordinates = findOrCreateFieldCoordinates(fm) mesh = fm.findMeshByDimension(3) # Annotation groups brainstemGroup = AnnotationGroup(region, get_brainstem_term('brainstem')) brainstemMeshGroup = brainstemGroup.getMeshGroup(mesh) midbrainGroup = AnnotationGroup(region, get_brainstem_term('midbrain')) midbrainMeshGroup = midbrainGroup.getMeshGroup(mesh) ponsGroup = AnnotationGroup(region, get_brainstem_term('pons')) ponsMeshGroup = ponsGroup.getMeshGroup(mesh) medullaGroup = AnnotationGroup(region, get_brainstem_term('medulla oblongata')) medullaMeshGroup = medullaGroup.getMeshGroup(mesh) annotationGroups = [brainstemGroup, midbrainGroup, ponsGroup, medullaGroup] annotationGroupAlong = [[brainstemGroup, midbrainGroup], [brainstemGroup, ponsGroup], [brainstemGroup, medullaGroup]] # centralCanal = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('central canal of spinal cord')) # cerebralAqueduct = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('cerebral aqueduct')) # foramenCaecum = findOrCreateAnnotationGroupForTerm(annotationGroups, region, ####################### # CREATE MAIN BODY MESH ####################### cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if not halfBrainStem else CylinderShape.CYLINDER_SHAPE_LOWER_HALF # brainstem coordinates cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong) base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, centre=[0.0, 0.0, 0.0], alongAxis=cylinderCentralPath.alongAxis[0], majorAxis=cylinderCentralPath.majorAxis[0], minorRadius=cylinderCentralPath.minorRadii[0]) cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) # workaround for old Zinc field wrapper bug: must create brainstem coordinates field before reading file brainstem_coordinates = findOrCreateFieldCoordinates(fm, name="brainstem coordinates") # generate brainstem coordinates field in temporary region tmp_region = region.createRegion() tmp_fm = tmp_region.getFieldmodule() with ChangeManager(tmp_fm): tmp_brainstem_coordinates = findOrCreateFieldCoordinates(tmp_fm, name="brainstem coordinates") cylinderCentralPath1 = CylinderCentralPath(tmp_region, brainstemPath, elementsCountAlong) base1 = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, centre=[0.0, 0.0, 0.0], alongAxis=cylinderCentralPath1.alongAxis[0], majorAxis=cylinderCentralPath1.majorAxis[0], minorRadius=cylinderCentralPath1.minorRadii[0]) cylinder2 = CylinderMesh(tmp_fm, tmp_brainstem_coordinates, elementsCountAlong, base1, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath1, useCrossDerivatives=False) # write to memory buffer sir = tmp_region.createStreaminformationRegion() srm = sir.createStreamresourceMemory() tmp_region.write(sir) result, buffer = srm.getBuffer() # read into main region sir = region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) region.read(sir) del srm del sir del tmp_brainstem_coordinates del tmp_fm del tmp_region # Annotating groups iRegionBoundaries = [int(6 * elementsCountAlong / 15), int(13 * elementsCountAlong / 15)] for elementIdentifier in range(1, mesh.getSize() + 1): element = mesh.findElementByIdentifier(elementIdentifier) brainstemMeshGroup.addElement(element) if elementIdentifier > (iRegionBoundaries[-1] * elementsPerLayer): midbrainMeshGroup.addElement(element) elif (elementIdentifier > (iRegionBoundaries[0] * elementsPerLayer)) and ( elementIdentifier <= (iRegionBoundaries[-1] * elementsPerLayer)): ponsMeshGroup.addElement(element) else: medullaMeshGroup.addElement(element) ################ # point markers ################ markerTermNameBrainstemCoordinatesMap = { 'brainstem dorsal midline caudal point': [0.0, 1.0, 0.0], 'brainstem ventral midline caudal point': [0.0, -1.0, 0.0], 'brainstem dorsal midline cranial point': [0.0, 1.0, 8.0], 'brainstem ventral midline cranial point': [0.0, -1.0, 8.0], 'brainstem dorsal midline pons-medulla junction': [0.0, 1.0, 3.0], 'brainstem ventral midline pons-medulla junction': [0.0, -1.0, 3.0], 'brainstem dorsal midline midbrain-pons junction': [0.0, 1.0, 6.0], 'brainstem ventral midline midbrain-pons junction': [0.0, -1.0, 6.0] } nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) for termName, brainstemCoordinatesValues in markerTermNameBrainstemCoordinatesMap.items(): annotationGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_brainstem_term(termName)) annotationGroup.createMarkerNode(nodeIdentifier, brainstem_coordinates, brainstemCoordinatesValues) nodeIdentifier += 1 return annotationGroups