def __init__(self, input_zinc_file, input_exelem_file=None, refine=None, output_zinc_file=None, output_vtk_file=None): self._context = ZincContext("RefineContext") self._region = self._context.getDefaultRegion() self._input_zinc_file = input_zinc_file self._region.readFile(self._input_zinc_file) if input_exelem_file is not None: self._region.readFile(input_exelem_file) self._field_module = self._region.getFieldmodule() self._annotation_groups = [ AnnotationGroup(self._region, (group.getName(), None)) for group in get_group_list(self._field_module) ] self._field_module.defineAllFaces() for group in self._annotation_groups: group.addSubelements() """ Refine """ self._refine_factor = refine self._refined_region, self._refined_annotation_groups = self._refine() """ Export to Zinc file""" self._refined_region.writeFile(output_zinc_file) """ Export to VTK """ description = "A Zinc model scaffold" exportvtk = ExportVtk(self._refined_region, description, self._refined_annotation_groups) exportvtk.writeFile(output_vtk_file)
def createUserAnnotationGroup(self, term=None): ''' Create a new, empty user annotation group. Only call after generate(). :param term: Identifier for anatomical term, a tuple of (name, id), or None to generate a unique name 'group#' with ID "None". If a term is supplied, both its name and id must be strings, the name must be unique i.e. unused in the list of annotation groups. The id should be a unique string, or use "None" if unknown. e.g. ('heart', 'FMA:7088') or None. :return: New AnnotationGroup. ''' assert self._region if term is not None: assert isinstance(term, tuple) and (len(term) == 2) and all(isinstance(s, str) for s in term),\ "Invalid annotation term " + str(term) assert not self.findAnnotationGroupByName( term[0]), "Annotation term " + str(term) + " name is in use" useTerm = term else: number = 1 while True: name = "group" + str(number) if not self.findAnnotationGroupByName(name): break number += 1 useTerm = (name, "None") annotationGroup = AnnotationGroup(self._region, useTerm) self._userAnnotationGroups.append(annotationGroup) return annotationGroup
def generate(self, region, applyTransformation=True): ''' Generate the finite element scaffold and define annotation groups. :param applyTransformation: If True (default) apply scale, rotation and translation to node coordinates. Specify False if client will transform, e.g. with graphics transformations. ''' self._region = region with ChangeManager(region.getFieldmodule()): self._autoAnnotationGroups = self._scaffoldType.generateMesh( region, self._scaffoldSettings) # need next node identifier for creating user-defined marker points nodes = region.getFieldmodule().findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self._nextNodeIdentifier = get_maximum_node_identifier(nodes) + 1 if self._meshEdits: # apply mesh edits, a Zinc-readable model file containing node edits # Note: these are untransformed coordinates sir = region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(self._meshEdits) region.read(sir) # define user AnnotationGroups from serialised Dict self._userAnnotationGroups = [ AnnotationGroup.fromDict(dct, self._region) for dct in self._userAnnotationGroupsDict ] self._isGenerated = True if applyTransformation: self.applyTransformation()
def defineFaceAnnotations(cls, region, options, annotationGroups): """ Add face annotation groups from the 1D mesh. :param region: Zinc region containing model. :param options: Dict containing options. See getDefaultOptions(). :param annotationGroups: List of annotation groups for ventral-level elements. New point annotation groups are appended to this list. """ # create groups fm = region.getFieldmodule() mesh2d = fm.findMeshByDimension(2) is_exterior = fm.createFieldIsExterior() is_exterior_face_xi1 = fm.createFieldOr( fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0)), fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1))) is_exterior_face_xi2 = fm.createFieldOr( fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0)), fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_1))) is_exterior_face_xi3 = fm.createFieldOr( fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)), fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1))) # external regions groupNames = ['brainstem', 'midbrain', 'medulla oblongata', 'pons'] for groupName in groupNames: subGroup = AnnotationGroup(region, get_brainstem_term(groupName)) issub = subGroup.getFieldElementGroup(mesh2d) is_subface_ext = fm.createFieldOr( fm.createFieldAnd(issub, is_exterior_face_xi1), fm.createFieldAnd(issub, is_exterior_face_xi3)) subFaceGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term(groupName + ' exterior')) subFaceGroup.getMeshGroup(mesh2d).addElementsConditional( is_subface_ext) # brainstem interface groupNames = [ 'brainstem-spinal cord interface', 'thalamus-brainstem interface' ] for groupName in groupNames: subGroupName = 'midbrain' if groupName == 'thalamus-brainstem interface' else 'medulla oblongata' subGroup = AnnotationGroup(region, get_brainstem_term(subGroupName)) issub = subGroup.getFieldElementGroup(mesh2d) is_subface_ext = fm.createFieldAnd(issub, is_exterior_face_xi2) subFaceGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term(groupName)) subFaceGroup.getMeshGroup(mesh2d).addElementsConditional( is_subface_ext)
def generate(self, region, applyTransformation=True): ''' Generate the finite element scaffold and define annotation groups. :param applyTransformation: If True (default) apply scale, rotation and translation to node coordinates. Specify False if client will transform, e.g. with graphics transformations. ''' self._region = region with ChangeManager(region.getFieldmodule()): self._autoAnnotationGroups = self._scaffoldType.generateMesh(region, self._scaffoldSettings) if self._meshEdits: # apply mesh edits, a Zinc-readable model file containing node edits # Note: these are untransformed coordinates sir = region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(self._meshEdits) region.read(sir) # define user AnnotationGroups from serialised Dict self._userAnnotationGroups = [ AnnotationGroup.fromDict(dct, self._region) for dct in self._userAnnotationGroupsDict ] if applyTransformation: self.applyTransformation()
def createUserAnnotationGroup(self, term=None): ''' Create a new, empty user annotation group. Only call after generate(). :param term: Identifier for anatomical term, currently a tuple of name, id. e.g. ('heart', 'FMA:7088'). Or None to generate a unique name. Name must be unique if supplied; id should be unique but may be None. :return: New AnnotationGroup. ''' assert self._region if term: assert not self.findAnnotationGroupByName(term[0]) useTerm = term else: number = 1 while True: name = "group" + str(number) if not self.findAnnotationGroupByName(name): break number += 1 useTerm = (name, None) annotationGroup = AnnotationGroup(self._region, useTerm) self._userAnnotationGroups.append(annotationGroup) return annotationGroup
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: annotationGroups """ centralPath = options['Central path'] elementsCountAround = options['Number of elements around'] elementsCountAlong = options['Number of elements along'] elementsCountThroughWall = options['Number of elements through wall'] wallThickness = options['Wall thickness'] mucosaRelThickness = options['Mucosa relative thickness'] submucosaRelThickness = options['Submucosa relative thickness'] circularRelThickness = options[ 'Circular muscle layer relative thickness'] longitudinalRelThickness = options[ 'Longitudinal muscle layer relative thickness'] useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not (options['Use linear through wall']) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path esophagusTermsAlong = [ None, 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus' ] arcLengthOfGroupsAlong = [] for i in range(len(esophagusTermsAlong)): tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ extractPathParametersFromRegion(tmpRegion, [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D2_DS1DS3], groupName=esophagusTermsAlong[i]) arcLength = 0.0 for e in range(len(cxGroup) - 1): arcLength += interp.getCubicHermiteArcLength( cxGroup[e], cd1Group[e], cxGroup[e + 1], cd1Group[e + 1]) arcLengthOfGroupsAlong.append(arcLength) if i == 0: cx = cxGroup cd1 = cd1Group cd2 = cd2Group cd3 = cd3Group cd12 = cd12Group cd13 = cd13Group del tmpRegion # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves( cx, cd1, elementsCountAlong) sd2, sd12 = interp.interpolateSampleCubicHermite( cd2, cd12, se, sxi, ssf) sd3, sd13 = interp.interpolateSampleCubicHermite( cd3, cd13, se, sxi, ssf) centralPathLength = arcLengthOfGroupsAlong[0] elementAlongLength = centralPathLength / elementsCountAlong elementsCountAlongGroups = [] groupLength = 0.0 e = 0 elementsCount = 1 length = elementAlongLength for i in range(1, len(esophagusTermsAlong)): groupLength += arcLengthOfGroupsAlong[i] if e == elementsCountAlong - 2: elementsCount += 1 elementsCountAlongGroups.append(elementsCount) else: while length < groupLength: elementsCount += 1 e += 1 length += elementAlongLength # check which end is grouplength closer to distToUpperEnd = abs(length - groupLength) distToLowerEnd = abs(groupLength - (length - elementsCountAlong)) if distToLowerEnd < distToUpperEnd: elementsCount -= 1 elementsCountAlongGroups.append(elementsCount) e -= 1 length -= elementAlongLength else: elementsCountAlongGroups.append(elementsCount) elementsCount = 0 majorRadiusElementList = sd2 minorRadiusElementList = sd3 # Create annotation groups along esophagus esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) cervicalGroup = AnnotationGroup( region, get_esophagus_term("cervical part of esophagus")) thoracicGroup = AnnotationGroup( region, get_esophagus_term("thoracic part of esophagus")) abdominalGroup = AnnotationGroup( region, get_esophagus_term("abdominal part of esophagus")) annotationGroupAlong = [[esophagusGroup, cervicalGroup], [esophagusGroup, thoracicGroup], [esophagusGroup, abdominalGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsAround = [] for i in range(elementsCountAround): annotationGroupsAround.append([]) # Groups through wall longitudinalMuscleGroup = AnnotationGroup( region, get_esophagus_term("esophagus smooth muscle longitudinal layer")) circularMuscleGroup = AnnotationGroup( region, get_esophagus_term("esophagus smooth muscle circular layer")) submucosaGroup = AnnotationGroup( region, get_esophagus_term("submucosa of esophagus")) mucosaGroup = AnnotationGroup(region, get_esophagus_term("esophagus mucosa")) if elementsCountThroughWall == 1: relativeThicknessList = [1.0] annotationGroupsThroughWall = [[]] else: relativeThicknessList = [ mucosaRelThickness, submucosaRelThickness, circularRelThickness, longitudinalRelThickness ] annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], [longitudinalMuscleGroup]] xToSample = [] d1ToSample = [] for n2 in range(elementsCountAlong + 1): # Create inner points cx = [0.0, 0.0, elementAlongLength * n2] axis1 = [vector.magnitude(majorRadiusElementList[n2]), 0.0, 0.0] axis2 = [0.0, vector.magnitude(minorRadiusElementList[n2]), 0.0] xInner, d1Inner = geometry.createEllipsePoints(cx, 2 * math.pi, axis1, axis2, elementsCountAround, startRadians=0.0) xToSample += xInner d1ToSample += d1Inner d2ToSample = [[0.0, 0.0, elementAlongLength] ] * (elementsCountAround * (elementsCountAlong + 1)) # Sample along length xInnerRaw = [] d2InnerRaw = [] xToWarp = [] d1ToWarp = [] d2ToWarp = [] flatWidthList = [] xiList = [] for n1 in range(elementsCountAround): xForSamplingAlong = [] d2ForSamplingAlong = [] for n2 in range(elementsCountAlong + 1): idx = n2 * elementsCountAround + n1 xForSamplingAlong.append(xToSample[idx]) d2ForSamplingAlong.append(d2ToSample[idx]) xSampled, d2Sampled = interp.sampleCubicHermiteCurves( xForSamplingAlong, d2ForSamplingAlong, elementsCountAlong, arcLengthDerivatives=True)[0:2] xInnerRaw.append(xSampled) d2InnerRaw.append(d2Sampled) # Re-arrange sample order & calculate dx_ds1 and dx_ds3 from dx_ds2 for n2 in range(elementsCountAlong + 1): xAround = [] d2Around = [] for n1 in range(elementsCountAround): x = xInnerRaw[n1][n2] d2 = d2InnerRaw[n1][n2] xAround.append(x) d2Around.append(d2) d1Around = [] for n1 in range(elementsCountAround): v1 = xAround[n1] v2 = xAround[(n1 + 1) % elementsCountAround] d1 = d2 = [v2[c] - v1[c] for c in range(3)] arcLengthAround = interp.computeCubicHermiteArcLength( v1, d1, v2, d2, True) dx_ds1 = [c * arcLengthAround for c in vector.normalise(d1)] d1Around.append(dx_ds1) d1Smoothed = interp.smoothCubicHermiteDerivativesLoop( xAround, d1Around) xToWarp += xAround d1ToWarp += d1Smoothed d2ToWarp += d2Around # Flat width and xi flatWidth = 0.0 xiFace = [] for n1 in range(elementsCountAround): v1 = xAround[n1] d1 = d1Smoothed[n1] v2 = xAround[(n1 + 1) % elementsCountAround] d2 = d1Smoothed[(n1 + 1) % elementsCountAround] flatWidth += interp.getCubicHermiteArcLength(v1, d1, v2, d2) flatWidthList.append(flatWidth) for n1 in range(elementsCountAround + 1): xi = 1.0 / elementsCountAround * n1 xiFace.append(xi) xiList.append(xiFace) # Project reference point for warping onto central path sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, centralPathLength, sx, sd1, sd2, sd12) # Warp points segmentAxis = [0.0, 0.0, 1.0] closedProximalEnd = False innerRadiusAlong = [] for n2 in range(elementsCountAlong + 1): firstNodeAlong = xToWarp[n2 * elementsCountAround] midptSegmentAxis = [0.0, 0.0, elementAlongLength * n2] radius = vector.magnitude(firstNodeAlong[c] - midptSegmentAxis[c] for c in range(3)) innerRadiusAlong.append(radius) xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = \ tubemesh.warpSegmentPoints(xToWarp, d1ToWarp, d2ToWarp, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlong, zRefList, innerRadiusAlong, closedProximalEnd) # Create coordinates and derivatives transitElementList = [0] * elementsCountAround xList, d1List, d2List, d3List, curvatureList = \ tubemesh.getCoordinatesFromInner(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, [wallThickness]*(elementsCountAlong+1), relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create flat coordinates xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( xiList, flatWidthList, length, wallThickness, relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements xOrgan = [] d1Organ = [] d2Organ = [] nodeIdentifier, elementIdentifier, annotationGroups = \ tubemesh.createNodesAndElements(region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) # annotation fiducial points fm = region.getFieldmodule() fm.beginChange() mesh = fm.findMeshByDimension(3) cache = fm.createFieldcache() 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) markerNames = [ "proximodorsal midpoint on serosa of upper esophageal sphincter", "proximoventral midpoint on serosa of upper esophageal sphincter", "distal point of lower esophageal sphincter serosa on the greater curvature of stomach", "distal point of lower esophageal sphincter serosa on the lesser curvature of stomach" ] totalElements = elementIdentifier radPerElementAround = math.pi * 2.0 / elementsCountAround elementAroundHalfPi = int(0.25 * elementsCountAround) xi1HalfPi = (math.pi * 0.5 - radPerElementAround * elementAroundHalfPi) / radPerElementAround elementAroundPi = int(0.5 * elementsCountAround) xi1Pi = (math.pi - radPerElementAround * elementAroundPi) / radPerElementAround markerElementIdentifiers = [ elementsCountAround * elementsCountThroughWall - elementAroundHalfPi, elementAroundHalfPi + 1 + elementsCountAround * (elementsCountThroughWall - 1), totalElements - elementsCountAround, totalElements - elementsCountAround + elementAroundPi ] markerXis = [[1.0 - xi1HalfPi, 0.0, 1.0], [xi1HalfPi, 0.0, 1.0], [0.0, 1.0, 1.0], [xi1Pi, 1.0, 1.0]] for n in range(len(markerNames)): markerGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_esophagus_term(markerNames[n])) markerElement = mesh.findElementByIdentifier( markerElementIdentifiers[n]) markerXi = markerXis[n] cache.setMeshLocation(markerElement, markerXi) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) markerName.assignString(cache, markerGroup.getName()) markerLocation.assignMeshLocation(cache, markerElement, markerXi) for group in [esophagusGroup, markerGroup]: group.getNodesetGroup(nodes).addNode(markerPoint) fm.endChange() 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. See also generateMesh(). Optional extra parameters allow centre and axes to be set. :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :param baseCentre: Centre of valve on ventriculo-arterial junction. :param axisSide: Unit vector in first side direction where angle around starts. :param axisUp: Unit vector in outflow direction of valve. :return: list of AnnotationGroup """ unitScale = options['Unit scale'] outerHeight = unitScale * options['Outer height'] innerDepth = unitScale * options['Inner depth'] cuspHeight = unitScale * options['Cusp height'] innerRadius = unitScale * 0.5 * options['Inner diameter'] sinusRadialDisplacement = unitScale * options[ 'Sinus radial displacement'] wallThickness = unitScale * options['Wall thickness'] cuspThickness = unitScale * options['Cusp thickness'] aorticNotPulmonary = options['Aortic not pulmonary'] useCrossDerivatives = False fm = region.getFieldmodule() fm.beginChange() coordinates = zinc_utils.getOrCreateCoordinateField(fm) cache = fm.createFieldcache() if aorticNotPulmonary: arterialRootGroup = AnnotationGroup(region, 'root of aorta', FMANumber=3740, lyphID='Lyph ID unknown') cuspGroups = [ AnnotationGroup(region, 'posterior cusp of aortic valve', FMANumber=7253, lyphID='Lyph ID unknown'), AnnotationGroup(region, 'right cusp of aortic valve', FMANumber=7252, lyphID='Lyph ID unknown'), AnnotationGroup(region, 'left cusp of aortic valve', FMANumber=7251, lyphID='Lyph ID unknown') ] else: arterialRootGroup = AnnotationGroup(region, 'root of pulmonary trunk', FMANumber=8612, lyphID='Lyph ID unknown') cuspGroups = [ AnnotationGroup(region, 'right cusp of pulmonary valve', FMANumber=7250, lyphID='Lyph ID unknown'), AnnotationGroup(region, 'anterior cusp of pulmonary valve', FMANumber=7249, lyphID='Lyph ID unknown'), AnnotationGroup(region, 'left cusp of pulmonary valve', FMANumber=7247, lyphID='Lyph ID unknown') ] allGroups = [arterialRootGroup ] # groups that all elements in scaffold will go in annotationGroups = allGroups + cuspGroups # annotation fiducial points fiducialGroup = zinc_utils.getOrCreateGroupField(fm, 'fiducial') fiducialCoordinates = zinc_utils.getOrCreateCoordinateField( fm, 'fiducial_coordinates') fiducialLabel = zinc_utils.getOrCreateLabelField(fm, 'fiducial_label') #fiducialElementXi = zinc_utils.getOrCreateElementXiField(fm, 'fiducial_element_xi') datapoints = fm.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) fiducialPoints = zinc_utils.getOrCreateNodesetGroup( fiducialGroup, datapoints) datapointTemplateExternal = datapoints.createNodetemplate() datapointTemplateExternal.defineField(fiducialCoordinates) datapointTemplateExternal.defineField(fiducialLabel) ################# # Create nodes ################# nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) nodetemplate = nodes.createNodetemplate() nodetemplate.defineField(coordinates) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) # most nodes in this scaffold do not have a DS3 derivative nodetemplateLinearS3 = nodes.createNodetemplate() nodetemplateLinearS3.defineField(coordinates) nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) # several only have a DS1 derivative nodetemplateLinearS2S3 = nodes.createNodetemplate() nodetemplateLinearS2S3.defineField(coordinates) nodetemplateLinearS2S3.setValueNumberOfVersions( coordinates, -1, Node.VALUE_LABEL_VALUE, 1) nodetemplateLinearS2S3.setValueNumberOfVersions( coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) nodeIdentifier = max(1, zinc_utils.getMaximumNodeIdentifier(nodes) + 1) elementsCountAround = 6 radiansPerElementAround = 2.0 * math.pi / elementsCountAround axisSide2 = vector.crossproduct3(axisUp, axisSide1) outerRadius = innerRadius + wallThickness cuspOuterLength2 = 0.5 * getApproximateEllipsePerimeter( innerRadius, cuspHeight) cuspOuterWallArcLength = cuspOuterLength2 * innerRadius / ( innerRadius + cuspHeight) noduleOuterAxialArcLength = cuspOuterLength2 - cuspOuterWallArcLength noduleOuterRadialArcLength = innerRadius cuspOuterWalld1 = interp.interpolateLagrangeHermiteDerivative( [innerRadius, outerHeight + innerDepth - cuspHeight], [0.0, 0.0], [-innerRadius, 0.0], 0.0) sin60 = math.sin(math.pi / 3.0) cuspThicknessLowerFactor = 4.5 # GRC fudge factor cuspInnerLength2 = 0.5 * getApproximateEllipsePerimeter( innerRadius - cuspThickness / sin60, cuspHeight - cuspThicknessLowerFactor * cuspThickness) noduleInnerAxialArcLength = cuspInnerLength2 * ( cuspHeight - cuspThicknessLowerFactor * cuspThickness) / ( innerRadius - cuspThickness / sin60 + cuspHeight - cuspThicknessLowerFactor * cuspThickness) noduleInnerRadialArcLength = innerRadius - cuspThickness / math.tan( math.pi / 3.0) nMidCusp = 0 if aorticNotPulmonary else 1 # lower points ix, id1 = createCirclePoints( [(baseCentre[c] - axisUp[c] * innerDepth) for c in range(3)], [axisSide1[c] * innerRadius for c in range(3)], [axisSide2[c] * innerRadius for c in range(3)], elementsCountAround) ox, od1 = getSemilunarValveSinusPoints(baseCentre, axisSide1, axisSide2, outerRadius, sinusRadialDisplacement, startMidCusp=aorticNotPulmonary) lowerx, lowerd1 = [ix, ox], [id1, od1] # upper points topCentre = [(baseCentre[c] + axisUp[c] * outerHeight) for c in range(3)] # twice as many on inner: ix, id1 = createCirclePoints( topCentre, [axisSide1[c] * innerRadius for c in range(3)], [axisSide2[c] * innerRadius for c in range(3)], elementsCountAround * 2) # tweak inner points so elements attached to cusps are narrower cuspRadiansFactor = 0.25 # GRC fudge factor midDerivativeFactor = 1.0 + 0.5 * (1.0 - cuspRadiansFactor ) # GRC test compromise cuspAttachmentRadians = cuspRadiansFactor * radiansPerElementAround cuspAttachmentRadialDisplacement = wallThickness * 0.333 # GRC fudge factor cuspAttachmentRadius = innerRadius - cuspAttachmentRadialDisplacement for cusp in range(3): n1 = cusp * 2 - 1 + nMidCusp n2 = n1 * 2 id1[n2 + 2] = [2.0 * d for d in id1[n2 + 2]] # side 1 radiansAround = n1 * radiansPerElementAround + cuspAttachmentRadians rcosRadiansAround = cuspAttachmentRadius * math.cos(radiansAround) rsinRadiansAround = cuspAttachmentRadius * math.sin(radiansAround) ix[n2 + 1] = [(topCentre[c] + rcosRadiansAround * axisSide1[c] + rsinRadiansAround * axisSide2[c]) for c in range(3)] id1[n2 + 1] = interp.interpolateLagrangeHermiteDerivative( ix[n2 + 1], ix[n2 + 2], id1[n2 + 2], 0.0) # side 2 n1 = ((cusp + 1) * 2 - 1 + nMidCusp) % elementsCountAround n2 = n1 * 2 radiansAround = n1 * radiansPerElementAround - cuspAttachmentRadians rcosRadiansAround = cuspAttachmentRadius * math.cos(radiansAround) rsinRadiansAround = cuspAttachmentRadius * math.sin(radiansAround) ix[n2 - 1] = [(topCentre[c] + rcosRadiansAround * axisSide1[c] + rsinRadiansAround * axisSide2[c]) for c in range(3)] id1[n2 - 1] = interp.interpolateHermiteLagrangeDerivative( ix[n2 - 2], id1[n2 - 2], ix[n2 - 1], 1.0) ox, od1 = createCirclePoints( topCentre, [axisSide1[c] * outerRadius for c in range(3)], [axisSide2[c] * outerRadius for c in range(3)], elementsCountAround) upperx, upperd1 = [ix, ox], [id1, od1] # get lower and upper derivative 2 zero = [0.0, 0.0, 0.0] upperd2factor = outerHeight upd2 = [d * upperd2factor for d in axisUp] lowerOuterd2 = interp.smoothCubicHermiteDerivativesLine( [lowerx[1][nMidCusp], upperx[1][nMidCusp]], [upd2, upd2], fixStartDirection=True, fixEndDerivative=True)[0] lowerd2factor = 2.0 * (outerHeight + innerDepth) - upperd2factor lowerInnerd2 = [d * lowerd2factor for d in axisUp] lowerd2 = [[lowerInnerd2] * elementsCountAround, [lowerOuterd2] * elementsCountAround ] # some lowerd2[0] to be fitted below upperd2 = [[upd2] * (elementsCountAround * 2), [upd2] * elementsCountAround] # get lower and upper derivative 1 or 2 pointing to/from cusps for n1 in range(elementsCountAround): radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) if (n1 % 2) == nMidCusp: lowerd2[0][n1] = [ -cuspOuterWallArcLength * (cosRadiansAround * axisSide1[c] + sinRadiansAround * axisSide2[c]) for c in range(3) ] else: upperd1[0][n1 * 2] = [ (cuspOuterWalld1[0] * (cosRadiansAround * axisSide1[c] + sinRadiansAround * axisSide2[c]) + cuspOuterWalld1[1] * axisUp[c]) for c in range(3) ] # inner wall and mid sinus points; only every second one is used sinusDepth = innerDepth - cuspThicknessLowerFactor * cuspThickness # GRC test sinusCentre = [(baseCentre[c] - sinusDepth * axisUp[c]) for c in range(3)] sinusx, sinusd1 = createCirclePoints( sinusCentre, [axisSide1[c] * innerRadius for c in range(3)], [axisSide2[c] * innerRadius for c in range(3)], elementsCountAround) # get sinusd2, parallel to lower inclined lines sd2 = interp.smoothCubicHermiteDerivativesLine( [[innerRadius, -sinusDepth], [innerRadius, outerHeight]], [[wallThickness + sinusRadialDisplacement, innerDepth], [0.0, upperd2factor]], fixStartDirection=True, fixEndDerivative=True)[0] sinusd2 = [None] * elementsCountAround for cusp in range(3): n1 = cusp * 2 + nMidCusp radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) sinusd2[n1] = [(sd2[0] * (cosRadiansAround * axisSide1[c] + sinRadiansAround * axisSide2[c]) + sd2[1] * axisUp[c]) for c in range(3)] # get points on arc between mid sinus and upper cusp points arcx = [] arcd1 = [] scaled1 = 2.5 # GRC fudge factor for cusp in range(3): n1 = cusp * 2 + nMidCusp n1m = n1 - 1 n1p = (n1 + 1) % elementsCountAround n2m = n1m * 2 + 1 n2p = n1p * 2 - 1 ax, ad1 = interp.sampleCubicHermiteCurves( [upperx[0][n2m], sinusx[n1]], [[-scaled1 * d for d in upperd2[0][n2m]], [scaled1 * d for d in sinusd1[n1]]], elementsCountOut=2, addLengthStart=0.5 * vector.magnitude(upperd2[0][n2m]), lengthFractionStart=0.5, addLengthEnd=0.5 * vector.magnitude(sinusd1[n1]), lengthFractionEnd=0.5, arcLengthDerivatives=False)[0:2] arcx.append(ax[1]) arcd1.append(ad1[1]) ax, ad1 = interp.sampleCubicHermiteCurves( [ sinusx[n1], upperx[0][n2p], ], [[scaled1 * d for d in sinusd1[n1]], [scaled1 * d for d in upperd2[0][n2p]]], elementsCountOut=2, addLengthStart=0.5 * vector.magnitude(sinusd1[n1]), lengthFractionStart=0.5, addLengthEnd=0.5 * vector.magnitude(upperd2[0][n2p]), lengthFractionEnd=0.5, arcLengthDerivatives=False)[0:2] arcx.append(ax[1]) arcd1.append(ad1[1]) if nMidCusp == 0: arcx.append(arcx.pop(0)) arcd1.append(arcd1.pop(0)) # cusp nodule points noduleCentre = [(baseCentre[c] + axisUp[c] * (cuspHeight - innerDepth)) for c in range(3)] nodulex = [[], []] noduled1 = [[], []] noduled2 = [[], []] noduled3 = [[], []] cuspRadialThickness = cuspThickness / sin60 for i in range(3): nodulex[0].append(noduleCentre) n1 = i * 2 + nMidCusp radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) nodulex[1].append([(noduleCentre[c] + cuspRadialThickness * (cosRadiansAround * axisSide1[c] + sinRadiansAround * axisSide2[c])) for c in range(3)]) n1 = i * 2 - 1 + nMidCusp radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) noduled1[0].append([ noduleOuterRadialArcLength * (cosRadiansAround * axisSide1[c] + sinRadiansAround * axisSide2[c]) for c in range(3) ]) noduled1[1].append( vector.setMagnitude(noduled1[0][i], noduleInnerRadialArcLength)) n1 = i * 2 + 1 + nMidCusp radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) noduled2[0].append([ noduleOuterRadialArcLength * (cosRadiansAround * axisSide1[c] + sinRadiansAround * axisSide2[c]) for c in range(3) ]) noduled2[1].append( vector.setMagnitude(noduled2[0][i], noduleInnerRadialArcLength)) noduled3[0].append( [noduleOuterAxialArcLength * axisUp[c] for c in range(3)]) noduled3[1].append( [noduleInnerAxialArcLength * axisUp[c] for c in range(3)]) # Create nodes lowerNodeId = [[], []] for n3 in range(2): for n1 in range(elementsCountAround): node = nodes.createNode(nodeIdentifier, nodetemplateLinearS3) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, lowerx[n3][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, lowerd1[n3][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, lowerd2[n3][n1]) lowerNodeId[n3].append(nodeIdentifier) nodeIdentifier += 1 sinusNodeId = [] for n1 in range(elementsCountAround): if (n1 % 2) != nMidCusp: sinusNodeId.append(None) continue node = nodes.createNode(nodeIdentifier, nodetemplateLinearS3) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sinusx[n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sinusd1[n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sinusd2[n1]) sinusNodeId.append(nodeIdentifier) nodeIdentifier += 1 arcNodeId = [] for n1 in range(elementsCountAround): node = nodes.createNode(nodeIdentifier, nodetemplateLinearS2S3) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, arcx[n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, arcd1[n1]) arcNodeId.append(nodeIdentifier) nodeIdentifier += 1 noduleNodeId = [[], []] for n3 in range(2): for n1 in range(3): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nodulex[n3][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, noduled1[n3][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, noduled2[n3][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, noduled3[n3][n1]) noduleNodeId[n3].append(nodeIdentifier) nodeIdentifier += 1 upperNodeId = [[], []] for n3 in range(2): for n1 in range(len(upperx[n3])): node = nodes.createNode(nodeIdentifier, nodetemplateLinearS3) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, upperx[n3][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, upperd1[n3][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, upperd2[n3][n1]) upperNodeId[n3].append(nodeIdentifier) nodeIdentifier += 1 ################# # Create elements ################# mesh = fm.findMeshByDimension(3) allMeshGroups = [allGroup.getMeshGroup(mesh) for allGroup in allGroups] cuspMeshGroups = [ cuspGroup.getMeshGroup(mesh) for cuspGroup in cuspGroups ] linearHermiteLinearBasis = fm.createElementbasis( 3, Elementbasis.FUNCTION_TYPE_LINEAR_LAGRANGE) linearHermiteLinearBasis.setFunctionType( 2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) hermiteLinearLinearBasis = fm.createElementbasis( 3, Elementbasis.FUNCTION_TYPE_LINEAR_LAGRANGE) hermiteLinearLinearBasis.setFunctionType( 1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) bicubichermitelinear = eftfactory_bicubichermitelinear( mesh, useCrossDerivatives) eftDefault = bicubichermitelinear.createEftNoCrossDerivatives() elementIdentifier = max( 1, zinc_utils.getMaximumElementIdentifier(mesh) + 1) elementtemplate1 = mesh.createElementtemplate() elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) # wall elements for cusp in range(3): n1 = cusp * 2 - 1 + nMidCusp n2 = n1 * 2 for e in range(6): eft1 = None scalefactors = None if (e == 0) or (e == 5): # 6 node linear-hermite-linear collapsed wedge element expanding from zero width on outer wall of root, attaching to vertical part of cusp eft1 = mesh.createElementfieldtemplate( linearHermiteLinearBasis) # switch mappings to use DS2 instead of default DS1 remapEftNodeValueLabel(eft1, [1, 2, 3, 4, 5, 6, 7, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) if e == 0: nids = [ lowerNodeId[0][n1], arcNodeId[n1], upperNodeId[0][n2], upperNodeId[0][n2 + 1], lowerNodeId[1][n1], upperNodeId[1][n1] ] setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel(eft1, [2], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) else: nids = [ arcNodeId[n1 + 1], lowerNodeId[0][n1 - 4], upperNodeId[0][n2 + 3], upperNodeId[0][n2 - 8], lowerNodeId[1][n1 - 4], upperNodeId[1][n1 - 4] ] remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) ln_map = [1, 2, 3, 4, 5, 5, 6, 6] remapEftLocalNodes(eft1, 6, ln_map) elif (e == 1) or (e == 4): # 6 node hermite-linear-linear collapsed wedge element on lower wall eft1 = mesh.createElementfieldtemplate( hermiteLinearLinearBasis) if e == 1: nids = [ lowerNodeId[0][n1], lowerNodeId[0][n1 + 1], arcNodeId[n1], sinusNodeId[n1 + 1], lowerNodeId[1][n1], lowerNodeId[1][n1 + 1] ] else: nids = [ lowerNodeId[0][n1 + 1], lowerNodeId[0][n1 - 4], sinusNodeId[n1 + 1], arcNodeId[n1 + 1], lowerNodeId[1][n1 + 1], lowerNodeId[1][n1 - 4] ] ln_map = [1, 2, 3, 4, 5, 6, 5, 6] remapEftLocalNodes(eft1, 6, ln_map) else: # 8 node elements with wedges on two sides if e == 2: eft1 = bicubichermitelinear.createEftNoCrossDerivatives( ) setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] nids = [ arcNodeId[n1], sinusNodeId[n1 + 1], upperNodeId[0][n2 + 1], upperNodeId[0][n2 + 2], lowerNodeId[1][n1], lowerNodeId[1][n1 + 1], upperNodeId[1][n1], upperNodeId[1][n1 + 1] ] remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) else: eft1 = eftDefault nids = [ sinusNodeId[n1 + 1], arcNodeId[n1 + 1], upperNodeId[0][n2 + 2], upperNodeId[0][n2 + 3], lowerNodeId[1][n1 + 1], lowerNodeId[1][n1 - 4], upperNodeId[1][n1 + 1], upperNodeId[1][n1 - 4] ] remapEftNodeValueLabel(eft1, [2], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) result = elementtemplate1.defineField(coordinates, -1, eft1) element = mesh.createElement(elementIdentifier, elementtemplate1) result2 = element.setNodesByIdentifier(eft1, nids) if scalefactors: result3 = element.setScaleFactors(eft1, scalefactors) else: result3 = 7 #print('create arterial root wall', cusp, e, 'element',elementIdentifier, result, result2, result3, nids) elementIdentifier += 1 for meshGroup in allMeshGroups: meshGroup.addElement(element) # cusps (leaflets) for cusp in range(3): n1 = cusp * 2 - 1 + nMidCusp n2 = n1 * 2 meshGroups = allMeshGroups + [cuspMeshGroups[cusp]] for e in range(2): eft1 = bicubichermitelinear.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] if e == 0: nids = [ lowerNodeId[0][n1], lowerNodeId[0][n1 + 1], upperNodeId[0][n2], noduleNodeId[0][cusp], arcNodeId[n1], sinusNodeId[n1 + 1], upperNodeId[0][n2 + 1], noduleNodeId[1][cusp] ] remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) else: nids = [ lowerNodeId[0][n1 + 1], lowerNodeId[0][n1 - 4], noduleNodeId[0][cusp], upperNodeId[0][n2 - 8], sinusNodeId[n1 + 1], arcNodeId[n1 + 1], noduleNodeId[1][cusp], upperNodeId[0][n2 + 3] ] remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) result = elementtemplate1.defineField(coordinates, -1, eft1) element = mesh.createElement(elementIdentifier, elementtemplate1) result2 = element.setNodesByIdentifier(eft1, nids) if scalefactors: result3 = element.setScaleFactors(eft1, scalefactors) else: result3 = 7 #print('create semilunar cusp', cusp, e, 'element',elementIdentifier, result, result2, result3, nids) elementIdentifier += 1 for meshGroup in meshGroups: meshGroup.addElement(element) # create annotation points datapoint = fiducialPoints.createNode(-1, datapointTemplateExternal) cache.setNode(datapoint) fiducialCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, noduleCentre) fiducialLabel.assignString( cache, 'aortic valve ctr' if aorticNotPulmonary else 'pulmonary valve ctr') fm.endChange() return annotationGroups
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
def generateBaseMesh(cls, region, options): ''' Generate the base bicubic Hermite mesh. :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: list of AnnotationGroup ''' elementsCountUpNeck = options['Number of elements up neck'] elementsCountUpBody = options['Number of elements up body'] elementsCountAround = options['Number of elements around'] height = options['Height'] majorDiameter = options['Major diameter'] minorDiameter = options['Minor diameter'] radius = 0.5 * options['Urethra diameter'] bladderWallThickness = options['Bladder wall thickness'] useCrossDerivatives = options['Use cross derivatives'] elementsCountAroundOstium = options['Number of elements around ostium'] elementsCountAnnulusRadially = options['Number of elements radially on annulus'] ostiumPositionAround = options['Ostium position around'] ostiumPositionUp = options['Ostium position up'] ostiumOptions = options['Ureter'] ostiumDefaultOptions = ostiumOptions.getScaffoldSettings() fm = region.getFieldmodule() fm.beginChange() coordinates = findOrCreateFieldCoordinates(fm) cache = fm.createFieldcache() mesh = fm.findMeshByDimension(3) nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) nodetemplateApex = nodes.createNodetemplate() nodetemplateApex.defineField(coordinates) nodetemplateApex.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) nodetemplateApex.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) nodetemplateApex.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) if useCrossDerivatives: 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_D2_DS1DS2, 1) else: nodetemplate = nodetemplateApex eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) eft = eftfactory.createEftBasic() elementtemplate = mesh.createElementtemplate() elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementtemplate.defineField(coordinates, -1, eft) neckGroup = AnnotationGroup(region, get_bladder_term("neck of urinary bladder")) bodyGroup = AnnotationGroup(region, get_bladder_term("dome of the bladder")) urinaryBladderGroup = AnnotationGroup(region, get_bladder_term("urinary bladder")) annotationGroups = [neckGroup, bodyGroup, urinaryBladderGroup] neckMeshGroup = neckGroup.getMeshGroup(mesh) bodyMeshGroup = bodyGroup.getMeshGroup(mesh) urinaryBladderMeshGroup = urinaryBladderGroup.getMeshGroup(mesh) # create nodes # create neck of the bladder nodeIdentifier = 1 radiansPerElementAround = 2.0*math.pi/elementsCountAround radiansPerElementUpNeck = (math.pi/4)/elementsCountUpNeck # create lower part of the ellipsoidal neckHeight = height - height * math.cos(math.pi / 4) ellipsoidal_x = [] ellipsoidal_d1 = [] ellipsoidal_d2 = [] for n2 in range(0, elementsCountUpNeck+1): radiansUp = n2 * radiansPerElementUpNeck cosRadiansUp = math.cos(radiansUp) sinRadiansUp = math.sin(radiansUp) majorRadius = 0.5 * majorDiameter * sinRadiansUp minorRadius = 0.5 * minorDiameter * sinRadiansUp if n2 == 0: for n1 in range(elementsCountAround): radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) x = [ -majorRadius * sinRadiansAround, minorRadius * cosRadiansAround, -height - neckHeight ] dx_ds1 = [ -majorRadius * cosRadiansAround * radiansPerElementAround, minorRadius * -sinRadiansAround * radiansPerElementAround, 0.0 ] dx_ds2 = [ -0.5 * majorDiameter * sinRadiansAround * cosRadiansUp * radiansPerElementUpNeck, 0.5 * minorDiameter * cosRadiansAround * cosRadiansUp * radiansPerElementUpNeck, height * sinRadiansUp * radiansPerElementUpNeck ] ellipsoidal_x.append(x) ellipsoidal_d1.append(dx_ds1) ellipsoidal_d2.append(dx_ds2) else: for n1 in range(elementsCountAround): neckHeight = height - height * math.cos(math.pi/4) radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) x = [ -majorRadius * sinRadiansAround, minorRadius * cosRadiansAround, -height - neckHeight + n2 * 2 * neckHeight / elementsCountUpNeck ] dx_ds1 = [ -majorRadius * cosRadiansAround * radiansPerElementAround, minorRadius * -sinRadiansAround * radiansPerElementAround, 0.0 ] dx_ds2 = [ -0.5 * majorDiameter * sinRadiansAround * cosRadiansUp * radiansPerElementUpNeck, 0.5 * minorDiameter * cosRadiansAround * cosRadiansUp * radiansPerElementUpNeck, height * sinRadiansUp * radiansPerElementUpNeck ] ellipsoidal_x.append(x) ellipsoidal_d1.append(dx_ds1) ellipsoidal_d2.append(dx_ds2) # create tube nodes radiansPerElementAround = 2.0 * math.pi / elementsCountAround tube_x = [] tube_d1 = [] tube_d2 = [] for n2 in range(0, elementsCountUpNeck + 1): radiansUp = n2 * radiansPerElementUpNeck cosRadiansUp = math.cos(radiansUp) sinRadiansUp = math.sin(radiansUp) if n2 == 0: for n1 in range(elementsCountAround): radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) x = [ -radius * sinRadiansAround, radius * cosRadiansAround, -height - neckHeight ] dx_ds1 = [ -radiansPerElementAround * radius * cosRadiansAround, radiansPerElementAround * radius * -sinRadiansAround, 0.0 ] dx_ds2 = [0, 0, height / (2 * elementsCountUpNeck)] tube_x.append(x) tube_d1.append(dx_ds1) tube_d2.append(dx_ds2) else: for n1 in range(elementsCountAround): neckHeight = height - height* math.cos(math.pi/4) radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) x = [ -radius * sinRadiansAround, radius * cosRadiansAround, -height - neckHeight + n2 * 2 * neckHeight / elementsCountUpNeck ] dx_ds1 = [ -radiansPerElementAround * radius * cosRadiansAround, radiansPerElementAround * radius * -sinRadiansAround, 0.0 ] dx_ds2 = [0, 0, height / elementsCountUpNeck] tube_x.append(x) tube_d1.append(dx_ds1) tube_d2.append(dx_ds2) # interpolation between the lower part of the ellipsoidal and the tube m1 = 0 z_bottom = ellipsoidal_x[-1][2] z_top = ellipsoidal_x[0][2] delta_z = z_top - z_bottom interpolatedNodes = [] interpolatedNodes_d1 = [] interpolatedNodes_d2 = [] for n2 in range(elementsCountUpNeck+1): xi = 1.0 - (ellipsoidal_x[m1][2] - z_bottom) / delta_z for n1 in range(elementsCountAround): phi_inner, _, phi_outer, _ = getCubicHermiteBasis(xi) x = [(phi_inner*tube_x[m1][c] + phi_outer*ellipsoidal_x[m1][c]) for c in range(3)] d1 = [(phi_inner*tube_d1[m1][c] + phi_outer*ellipsoidal_d1[m1][c]) for c in range(3)] d2 = [(phi_inner*tube_d2[m1][c] + phi_outer*ellipsoidal_d2[m1][c]) for c in range(3)] interpolatedNodes.append(x) interpolatedNodes_d1.append(d1) interpolatedNodes_d2.append(d2) m1 += 1 # smoothing the derivatives sd2Raw = [] for n1 in range(elementsCountAround): lineSmoothingNodes = [] lineSmoothingNodes_d2 = [] for n2 in range(elementsCountUpNeck+1): lineSmoothingNodes.append(interpolatedNodes[n1 + n2 * elementsCountAround]) lineSmoothingNodes_d2.append(interpolatedNodes_d2[n1 + n2 * elementsCountAround]) sd2 = smoothCubicHermiteDerivativesLine(lineSmoothingNodes, lineSmoothingNodes_d2, fixAllDirections=False, fixStartDerivative=True, fixEndDerivative=True, fixStartDirection=False, fixEndDirection=False) sd2Raw.append(sd2) # re-arrange the derivatives order d2RearrangedList = [] for n2 in range(elementsCountUpNeck+1): for n1 in range(elementsCountAround): d2 = sd2Raw[n1][n2] d2RearrangedList.append(d2) # create tracksurface at the outer layer of the neck nodesOnTrackSurface = [] nodesOnTrackSurface_d1 = [] nodesOnTrackSurface_d2 = [] for n2 in range(elementsCountUpNeck+1): for n1 in range(elementsCountAround): if (n1 <= elementsCountAround / 2): nodesOnTrackSurface.append(interpolatedNodes[n2 * elementsCountAround + n1]) nodesOnTrackSurface_d1.append(interpolatedNodes_d1[n2 * elementsCountAround + n1]) nodesOnTrackSurface_d2.append(d2RearrangedList[n2 * elementsCountAround + n1]) # nodes and derivatives of the neck of the bladder listOuterNeck_x = [] listOuterNeck_d1 = [] listOuterNeck_d2 = [] elementsCount1 = elementsCountAround // 2 elementsCount2 = elementsCountUpNeck tracksurfaceOstium1 = TrackSurface(elementsCount1, elementsCount2, nodesOnTrackSurface, nodesOnTrackSurface_d1, nodesOnTrackSurface_d2) ostium1Position = tracksurfaceOstium1.createPositionProportion(ostiumPositionAround, ostiumPositionUp) ostium1Position.xi1 = 1.0 ostium1Position.xi2 = 1.0 ostiumElementPositionAround = ostium1Position.e1 ostiumElementPositionUp = ostium1Position.e2 for n2 in range(len(interpolatedNodes)): listOuterNeck_x.append(interpolatedNodes[n2]) listOuterNeck_d1.append(interpolatedNodes_d1[n2]) listOuterNeck_d2.append(d2RearrangedList[n2]) # create body of the bladder radiansPerElementAround = 2.0 * math.pi / elementsCountAround radiansPerElementUpBody = (3 * math.pi / 4) / elementsCountUpBody # create regular rows listOuterBody_x = [] listOuterBody_d1 = [] listOuterBody_d2 = [] for n2 in range(1, elementsCountUpBody): radiansUp = (math.pi / 4) + n2 * radiansPerElementUpBody cosRadiansUp = math.cos(radiansUp) sinRadiansUp = math.sin(radiansUp) majorRadius = 0.5 * majorDiameter * sinRadiansUp minorRadius = 0.5 * minorDiameter * sinRadiansUp for n1 in range(elementsCountAround): radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) x = [ -majorRadius * sinRadiansAround, minorRadius * cosRadiansAround, -height * cosRadiansUp ] dx_ds1 = [ -majorRadius * cosRadiansAround * radiansPerElementAround, minorRadius * -sinRadiansAround * radiansPerElementAround, 0.0 ] dx_ds2 = [ -0.5 * majorDiameter * sinRadiansAround * cosRadiansUp * radiansPerElementUpBody, 0.5 * minorDiameter * cosRadiansAround * cosRadiansUp * radiansPerElementUpBody, height*sinRadiansUp * radiansPerElementUpBody ] listOuterBody_x.append(x) listOuterBody_d1.append(dx_ds1) listOuterBody_d2.append(dx_ds2) # create outer apex node outerApexNode_x = [] outerApexNode_d1 = [] outerApexNode_d2 = [] x = [0.0, 0.0, height] dx_ds1 = [height*radiansPerElementUpBody/2, 0.0, 0.0] dx_ds2 = [0.0, height*radiansPerElementUpBody/2, 0.0] outerApexNode_x.append(x) outerApexNode_d1.append(dx_ds1) outerApexNode_d2.append(dx_ds2) # set nodes of outer layer of the bladder listTotalOuter_x = listOuterNeck_x + listOuterBody_x + outerApexNode_x listTotalOuter_d1 = listOuterNeck_d1 + listOuterBody_d1 + outerApexNode_d1 listTotalOuter_d2 = listOuterNeck_d2 + listOuterBody_d2 + outerApexNode_d2 outerLayer_x = [] outerLayer_d1 = [] outerLayer_d2 = [] for n2 in range(len(listTotalOuter_x)): if (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + ostiumElementPositionAround + 1) and\ (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 1): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, listTotalOuter_x[n2]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, listTotalOuter_d1[n2]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, listTotalOuter_d2[n2]) nodeIdentifier += 1 outerLayer_x.append(listTotalOuter_x[n2]) outerLayer_d1.append(listTotalOuter_d1[n2]) outerLayer_d2.append(listTotalOuter_d2[n2]) # create and set nodes of inner layer of the bladder listTotalInner_x = [] listTotalInner_d1 = [] listTotalInner_d2 = [] for n2 in range(elementsCountUpNeck + elementsCountUpBody): loop_x = [listTotalOuter_x[n2 * elementsCountAround + n1] for n1 in range(elementsCountAround)] loop_d1 = [listTotalOuter_d1[n2 * elementsCountAround + n1] for n1 in range(elementsCountAround)] loop_d2 = [listTotalOuter_d2[n2 * elementsCountAround + n1] for n1 in range(elementsCountAround)] for n1 in range(elementsCountAround): x, d1, _, _ = interp.projectHermiteCurvesThroughWall(loop_x, loop_d1, loop_d2, n1, -bladderWallThickness, loop=True) listTotalInner_x.append(x) listTotalInner_d1.append(d1) listInner_d2 = [] for n2 in range(elementsCountAround): nx = [listTotalOuter_x[n1 * elementsCountAround + n2] for n1 in range(elementsCountUpNeck + elementsCountUpBody)] nd1 = [listTotalOuter_d1[n1 * elementsCountAround + n2] for n1 in range(elementsCountUpNeck + elementsCountUpBody)] nd2 = [listTotalOuter_d2[n1 * elementsCountAround + n2] for n1 in range(elementsCountUpNeck + elementsCountUpBody)] for n1 in range(elementsCountUpNeck + elementsCountUpBody): _, d2, _, _ = interp.projectHermiteCurvesThroughWall(nx, nd2, nd1, n1, bladderWallThickness, loop=False) listInner_d2.append(d2) # re-arrange the derivatives order for n2 in range(elementsCountUpNeck + elementsCountUpBody): for n1 in range(elementsCountAround): rearranged_d2 = listInner_d2[n1 * (elementsCountUpNeck + elementsCountUpBody) + n2] listTotalInner_d2.append(rearranged_d2) innerLayer_x = [] innerLayer_d1 = [] innerLayer_d2 = [] for n2 in range(len(listTotalInner_x)): if (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + ostiumElementPositionAround + 1) and \ (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 1): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, listTotalInner_x[n2]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, listTotalInner_d1[n2]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, listTotalInner_d2[n2]) nodeIdentifier += 1 innerLayer_x.append(listTotalInner_x[n2]) innerLayer_d1.append(listTotalInner_d1[n2]) innerLayer_d2.append(listTotalInner_d2[n2]) # create inner apex node x = [0.0, 0.0, height - bladderWallThickness] dx_ds1 = [height*radiansPerElementUpBody/2, 0.0, 0.0] dx_ds2 = [0.0, height*radiansPerElementUpBody/2, 0.0] node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dx_ds1) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dx_ds2) listTotalInner_x.append(x) listTotalInner_d1.append(dx_ds1) listTotalInner_d2.append(dx_ds2) innerLayer_x.append(x) innerLayer_d1.append(dx_ds1) innerLayer_d2.append(dx_ds2) nodeIdentifier += 1 # create ureters on the surface elementIdentifier = 1 # ureter 1 centerUreter1_x, centerUreter1_d1, centerUreter1_d2 = tracksurfaceOstium1.evaluateCoordinates(ostium1Position, derivatives=True) td1, td2, td3 = calculate_surface_axes(centerUreter1_d1, centerUreter1_d2, [1.0, 0.0, 0.0]) m1 = ostiumElementPositionUp * elementsCountAround + ostiumElementPositionAround ureter1StartCornerx = listOuterNeck_x[m1] v1 = [(ureter1StartCornerx[c] - centerUreter1_x[c]) for c in range(3)] ostium1Direction = vector.crossproduct3(td3, v1) nodeIdentifier, elementIdentifier, (o1_x, o1_d1, o1_d2, _, o1_NodeId, o1_Positions) = \ generateOstiumMesh(region, ostiumDefaultOptions, tracksurfaceOstium1, ostium1Position, ostium1Direction, startNodeIdentifier=nodeIdentifier, startElementIdentifier=elementIdentifier) # ureter 2 tracksurfaceOstium2 = tracksurfaceOstium1.createMirrorX() ostium2Position = TrackSurfacePosition(elementsCountAround - ostiumElementPositionAround, ostiumElementPositionUp - 1, 0.0, 1.0) centerUreter2_x, centerUreter2_d1, centerUreter2_d2 = tracksurfaceOstium2.evaluateCoordinates(ostium2Position, derivatives =True) ad1, ad2, ad3 = calculate_surface_axes(centerUreter2_d1, centerUreter2_d2, [1.0, 0.0, 0.0]) if elementsCountAroundOstium == 4: m2 = ostiumElementPositionUp * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 1 else: m2 = ostiumElementPositionUp * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 2 ureter2StartCornerx = listOuterNeck_x[m2] v2 = [(ureter2StartCornerx[c] - centerUreter2_x[c]) for c in range(3)] ostium2Direction = vector.crossproduct3(ad3, v2) nodeIdentifier, elementIdentifier, (o2_x, o2_d1, o2_d2, _, o2_NodeId, o2_Positions) = \ generateOstiumMesh(region, ostiumDefaultOptions, tracksurfaceOstium2, ostium2Position, ostium2Direction, startNodeIdentifier=nodeIdentifier, startElementIdentifier=elementIdentifier) # create annulus mesh around ostium endPoints1_x = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endPoints1_d1 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endPoints1_d2 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endNode1_Id = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endDerivativesMap = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endPoints2_x = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endPoints2_d1 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endPoints2_d2 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] endNode2_Id = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] nodeCountsEachWallLayer = (elementsCountUpNeck + elementsCountUpBody) * elementsCountAround - 1 for n3 in range(2): n1 = 0 endNode1_Id[n3][n1] = ((1 - n3) * nodeCountsEachWallLayer) + (ostiumElementPositionUp * elementsCountAround) + ostiumElementPositionAround + 1 endNode1_Id[n3][n1 + 1] = endNode1_Id[n3][n1] + elementsCountAround endNode1_Id[n3][n1 + 2] = endNode1_Id[n3][n1 + 1] + elementsCountAround - 2 endNode1_Id[n3][n1 + 3] = endNode1_Id[n3][n1 + 2] + 1 endNode1_Id[n3][n1 + 4] = endNode1_Id[n3][n1 + 3] + 1 endNode1_Id[n3][n1 + 5] = endNode1_Id[n3][n1 + 1] + 1 endNode1_Id[n3][n1 + 6] = endNode1_Id[n3][n1] + 2 endNode1_Id[n3][n1 + 7] = endNode1_Id[n3][n1] + 1 if ostiumElementPositionAround == 0: endNode2_Id[n3][n1] = ((1 - n3) * nodeCountsEachWallLayer) + (ostiumElementPositionUp * elementsCountAround)\ + elementsCountAround - ostiumElementPositionAround - 1 endNode2_Id[n3][n1 + 1] = endNode2_Id[n3][n1] + elementsCountAround - 1 endNode2_Id[n3][n1 + 2] = endNode2_Id[n3][n1 + 1] + elementsCountAround - 1 endNode2_Id[n3][n1 + 3] = endNode2_Id[n3][n1 + 2] + 1 endNode2_Id[n3][n1 + 4] = endNode2_Id[n3][n1 + 3] - elementsCountAround + 1 endNode2_Id[n3][n1 + 5] = endNode2_Id[n3][n1 + 4] - elementsCountAround + 2 endNode2_Id[n3][n1 + 6] = endNode2_Id[n3][n1 + 5] - elementsCountAround endNode2_Id[n3][n1 + 7] = endNode2_Id[n3][n1] + 1 else: endNode2_Id[n3][n1] = ((1 - n3) * nodeCountsEachWallLayer) + (ostiumElementPositionUp * elementsCountAround)\ + elementsCountAround - ostiumElementPositionAround - 1 endNode2_Id[n3][n1 + 1] = endNode2_Id[n3][n1] + elementsCountAround - 1 endNode2_Id[n3][n1 + 2] = endNode2_Id[n3][n1 + 1] + elementsCountAround - 1 endNode2_Id[n3][n1 + 3] = endNode2_Id[n3][n1 + 2] + 1 endNode2_Id[n3][n1 + 4] = endNode2_Id[n3][n1 + 3] + 1 endNode2_Id[n3][n1 + 5] = endNode2_Id[n3][n1 + 1] + 1 endNode2_Id[n3][n1 + 6] = endNode2_Id[n3][n1] + 2 endNode2_Id[n3][n1 + 7] = endNode2_Id[n3][n1] + 1 for n3 in range(2): for n1 in range(elementsCountAroundOstium): nc1 = endNode1_Id[n3][n1] - (1 - n3) * nodeCountsEachWallLayer - 1 endPoints1_x[n3][n1] = innerLayer_x[nc1] endPoints1_d1[n3][n1] = innerLayer_d1[nc1] endPoints1_d2[n3][n1] = [innerLayer_d2[nc1][c] for c in range(3)] nc2 = endNode2_Id[n3][n1] - (1 - n3) * nodeCountsEachWallLayer - 1 endPoints2_x[n3][n1] = innerLayer_x[nc2] endPoints2_d1[n3][n1] = innerLayer_d1[nc2] endPoints2_d2[n3][n1] = innerLayer_d2[nc2] for n1 in range(elementsCountAroundOstium): if n1 == 0: endDerivativesMap[0][n1] = ((-1, 0, 0), (-1, -1, 0), None, (0, 1, 0)) endDerivativesMap[1][n1] = ((-1, 0, 0), (-1, -1, 0), None, (0, 1, 0)) elif n1 == 1: endDerivativesMap[0][n1] = ((0, 1, 0), (-1, 0, 0), None) endDerivativesMap[1][n1] = ((0, 1, 0), (-1, 0, 0), None) elif n1 == 2: endDerivativesMap[0][n1] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) endDerivativesMap[1][n1] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) elif n1 == 3: endDerivativesMap[0][n1] = ((1, 0, 0), (0, 1, 0), None) endDerivativesMap[1][n1] = ((1, 0, 0), (0, 1, 0), None) elif n1 == 4: endDerivativesMap[0][n1] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) endDerivativesMap[1][n1] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) elif n1 == 5: endDerivativesMap[0][n1] = ((0, -1, 0), (1, 0, 0), None) endDerivativesMap[1][n1] = ((0, -1, 0), (1, 0, 0), None) elif n1 == 6: endDerivativesMap[0][n1] = ((0, -1, 0), (1, -1, 0), None, (-1, 0, 0)) endDerivativesMap[1][n1] = ((0, -1, 0), (1, -1, 0), None, (-1, 0, 0)) else: endDerivativesMap[0][n1] = ((-1, 0, 0), (0, -1, 0), None) endDerivativesMap[1][n1] = ((-1, 0, 0), (0, -1, 0), None) nodeIdentifier, elementIdentifier = createAnnulusMesh3d( nodes, mesh, nodeIdentifier, elementIdentifier, o1_x, o1_d1, o1_d2, None, o1_NodeId, None, endPoints1_x, endPoints1_d1, endPoints1_d2, None, endNode1_Id, endDerivativesMap, elementsCountRadial=elementsCountAnnulusRadially, meshGroups=[neckMeshGroup, urinaryBladderMeshGroup]) nodeIdentifier, elementIdentifier = createAnnulusMesh3d( nodes, mesh, nodeIdentifier, elementIdentifier, o2_x, o2_d1, o2_d2, None, o2_NodeId, None, endPoints2_x, endPoints2_d1, endPoints2_d2, None, endNode2_Id, endDerivativesMap, elementsCountRadial=elementsCountAnnulusRadially, meshGroups=[neckMeshGroup, urinaryBladderMeshGroup]) # create elements for e3 in range(1): newl = (e3 + 1) * ((elementsCountUpNeck + elementsCountUpBody) * elementsCountAround - 1) # create bladder neck elements for e2 in range(elementsCountUpNeck): for e1 in range(elementsCountAround): if e2 == ostiumElementPositionUp: if (e1 == ostiumElementPositionAround or e1 == ostiumElementPositionAround + 1): pass elif (e1 == elementsCountAround - ostiumElementPositionAround - 2 or e1 == elementsCountAround - 1 - ostiumElementPositionAround): pass else: bni1 = e2 * elementsCountAround + e1 + 1 bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 if e1 < ostiumElementPositionAround: bni3 = bni1 + elementsCountAround bni4 = bni2 + elementsCountAround elif (ostiumElementPositionAround + 1 < e1 < elementsCountAround - ostiumElementPositionAround - 2): bni3 = bni1 + elementsCountAround - 1 bni4 = bni2 + elementsCountAround - 1 elif e1 > elementsCountAround - ostiumElementPositionAround - 1: bni3 = bni1 + elementsCountAround - 2 if e1 == elementsCountAround - 1: bni4 = bni2 + elementsCountAround else: bni4 = bni2 + elementsCountAround - 2 element = mesh.createElement(elementIdentifier, elementtemplate) nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, bni1, bni2, bni3, bni4] result = element.setNodesByIdentifier(eft, nodeIdentifiers) neckMeshGroup.addElement(element) urinaryBladderMeshGroup.addElement(element) elementIdentifier += 1 elif e2 == ostiumElementPositionUp + 1: if (e1 == ostiumElementPositionAround or e1 == ostiumElementPositionAround + 1): pass elif (e1 == elementsCountAround - ostiumElementPositionAround - 2 or e1 == elementsCountAround - 1 - ostiumElementPositionAround): pass else: if e1 < ostiumElementPositionAround: bni1 = e2 * elementsCountAround + e1 + 1 bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 bni3 = bni1 + elementsCountAround - 2 bni4 = bni2 + elementsCountAround - 2 elif (ostiumElementPositionAround + 1 < e1 < elementsCountAround - ostiumElementPositionAround - 2): bni1 = e2 * elementsCountAround + e1 bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround bni3 = bni1 + elementsCountAround - 1 bni4 = bni2 + elementsCountAround - 1 elif e1 > elementsCountAround - ostiumElementPositionAround - 1: bni1 = e2 * elementsCountAround + e1 - 1 bni3 = bni1 + elementsCountAround if e1 == elementsCountAround - 1: bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 bni4 = bni2 + elementsCountAround - 2 else: bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround - 1 bni4 = bni2 + elementsCountAround element = mesh.createElement(elementIdentifier, elementtemplate) nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, bni1, bni2, bni3, bni4] result = element.setNodesByIdentifier(eft, nodeIdentifiers) neckMeshGroup.addElement(element) urinaryBladderMeshGroup.addElement(element) elementIdentifier += 1 elif e2 > ostiumElementPositionUp + 1: element = mesh.createElement(elementIdentifier, elementtemplate) bni1 = e2 * elementsCountAround + e1 - 1 bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround - 1 bni3 = bni1 + elementsCountAround bni4 = bni2 + elementsCountAround nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, bni1, bni2, bni3, bni4] result = element.setNodesByIdentifier(eft, nodeIdentifiers) neckMeshGroup.addElement(element) urinaryBladderMeshGroup.addElement(element) elementIdentifier += 1 else: element = mesh.createElement(elementIdentifier, elementtemplate) bni1 = e2 * elementsCountAround + e1 + 1 bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 bni3 = bni1 + elementsCountAround bni4 = bni2 + elementsCountAround nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, bni1, bni2, bni3, bni4] result = element.setNodesByIdentifier(eft, nodeIdentifiers) neckMeshGroup.addElement(element) urinaryBladderMeshGroup.addElement(element) elementIdentifier += 1 # create bladder body elements for e2 in range(elementsCountUpNeck, (elementsCountUpNeck + elementsCountUpBody - 1)): for e1 in range(elementsCountAround): element = mesh.createElement(elementIdentifier, elementtemplate) bni1 = e2 * elementsCountAround + e1 - 1 bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround - 1 bni3 = bni1 + elementsCountAround bni4 = bni2 + elementsCountAround nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, bni1, bni2, bni3, bni4] result = element.setNodesByIdentifier(eft, nodeIdentifiers) bodyMeshGroup.addElement(element) urinaryBladderMeshGroup.addElement(element) elementIdentifier += 1 # create apex elements bni3 = (elementsCountUpNeck + elementsCountUpBody) * elementsCountAround - 1 elementtemplateApex = mesh.createElementtemplate() elementtemplateApex.setElementShapeType(Element.SHAPE_TYPE_CUBE) for e1 in range(elementsCountAround): va = e1 vb = (e1 + 1) % elementsCountAround eftApex = eftfactory.createEftShellPoleTop(va, vb) elementtemplateApex.defineField(coordinates, -1, eftApex) # redefine field in template for changes to eftApex: element = mesh.createElement(elementIdentifier, elementtemplateApex) bni1 = bni3 - elementsCountAround + e1 bni2 = bni3 - elementsCountAround + (e1 + 1) % elementsCountAround nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni1, bni2, bni3] result = element.setNodesByIdentifier(eftApex, nodeIdentifiers) bodyMeshGroup.addElement(element) urinaryBladderMeshGroup.addElement(element) elementIdentifier += 1 fm.endChange() return annotationGroups
def __init__(self, sourceRegion, targetRegion, sourceAnnotationGroups=[]): ''' Assumes targetRegion is empty. :param sourceAnnotationGroups: List of AnnotationGroup for source mesh in sourceRegion. A copy containing the refined elements is created by the MeshRefinement. ''' self._sourceRegion = sourceRegion self._sourceFm = sourceRegion.getFieldmodule() self._sourceCache = self._sourceFm.createFieldcache() self._sourceCoordinates = getOrCreateCoordinateField(self._sourceFm) # get range of source coordinates for octree range self._sourceFm.beginChange() sourceNodes = self._sourceFm.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) minimumsField = self._sourceFm.createFieldNodesetMinimum( self._sourceCoordinates, sourceNodes) result, minimums = minimumsField.evaluateReal(self._sourceCache, 3) assert result == ZINC_OK, 'MeshRefinement failed to get minimum coordinates' maximumsField = self._sourceFm.createFieldNodesetMaximum( self._sourceCoordinates, sourceNodes) result, maximums = maximumsField.evaluateReal(self._sourceCache, 3) assert result == ZINC_OK, 'MeshRefinement failed to get maximum coordinates' xrange = [(maximums[i] - minimums[i]) for i in range(3)] edgeTolerance = 0.5 * (max(xrange)) if edgeTolerance == 0.0: edgeTolerance = 1.0 minimums = [(minimums[i] - edgeTolerance) for i in range(3)] maximums = [(maximums[i] + edgeTolerance) for i in range(3)] minimumsField = None maximumsField = None self._sourceFm.endChange() self._sourceMesh = self._sourceFm.findMeshByDimension(3) self._sourceElementiterator = self._sourceMesh.createElementiterator() self._octree = Octree(minimums, maximums) self._targetRegion = targetRegion self._targetFm = targetRegion.getFieldmodule() self._targetFm.beginChange() self._targetCache = self._targetFm.createFieldcache() self._targetCoordinates = getOrCreateCoordinateField(self._targetFm) self._targetNodes = self._targetFm.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self._nodetemplate = self._targetNodes.createNodetemplate() self._nodetemplate.defineField(self._targetCoordinates) self._targetMesh = self._targetFm.findMeshByDimension(3) self._targetBasis = self._targetFm.createElementbasis( 3, Elementbasis.FUNCTION_TYPE_LINEAR_LAGRANGE) self._targetEft = self._targetMesh.createElementfieldtemplate( self._targetBasis) self._targetElementtemplate = self._targetMesh.createElementtemplate() self._targetElementtemplate.setElementShapeType( Element.SHAPE_TYPE_CUBE) result = self._targetElementtemplate.defineField( self._targetCoordinates, -1, self._targetEft) self._nodeIdentifier = 1 self._elementIdentifier = 1 self._annotationGroups = [] self._sourceAndTargetMeshGroups = [] for sourceAnnotationGroup in sourceAnnotationGroups: sourceMeshGroup = sourceAnnotationGroup.getMeshGroup( self._sourceMesh) targetAnnotationGroup = AnnotationGroup(self._targetRegion, \ sourceAnnotationGroup.getName(), sourceAnnotationGroup.getFMANumber(), sourceAnnotationGroup.getLyphID()) targetMeshGroup = targetAnnotationGroup.getMeshGroup( self._targetMesh) self._annotationGroups.append(targetAnnotationGroup) self._sourceAndTargetMeshGroups.append( (sourceMeshGroup, targetMeshGroup))
def generateBaseMesh(region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: None """ elementsCountAcrossAxis1 = options['Number of elements across axis 1'] elementsCountAcrossAxis2 = options['Number of elements across axis 2'] elementsCountAcrossAxis3 = options['Number of elements across axis 3'] elementsCountAcrossShell = options['Number of elements across shell'] elementsCountAcrossTransition = options[ 'Number of elements across transition'] shellProportion = options['Shell element thickness proportion'] radius = [options['Radius1'], options['Radius2'], options['Radius3']] useCrossDerivatives = options['Use cross derivatives'] rangeOfRequiredElements = [ options['Range of elements required in direction 1'], options['Range of elements required in direction 2'], options['Range of elements required in direction 3'] ] sphereBoxDerivatives = [ -options['Box derivatives'][0], options['Box derivatives'][1], options['Box derivatives'][2] ] # To make the values more intuitive for the user but # consistent with [back, right, up] # sphereBoxDerivatives = [1, 3, 2] # consistent with default derivatives of cylinder mesh. # This is the default value that is used for base sphere. sphere_shape = SphereShape.SPHERE_SHAPE_FULL fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) mesh = fm.findMeshByDimension(3) boxGroup = AnnotationGroup(region, ("box group", "")) boxMeshGroup = boxGroup.getMeshGroup(mesh) transitionGroup = AnnotationGroup(region, ("transition group", "")) transitionMeshGroup = transitionGroup.getMeshGroup(mesh) meshGroups = [boxMeshGroup, transitionMeshGroup] annotationGroups = [boxGroup, transitionGroup] centre = [0.0, 0.0, 0.0] axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] axis3 = [0.0, 0.0, 1.0] axes = [ vector.scaleVector(axis1, radius[0]), vector.scaleVector(axis2, radius[1]), vector.scaleVector(axis3, radius[2]) ] elementsCountAcross = [ elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3 ] sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=sphere_shape, rangeOfRequiredElements=rangeOfRequiredElements, boxDerivatives=sphereBoxDerivatives, useCrossDerivatives=False, meshGroups=meshGroups) 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 zinc_write_element_xi_marker_file(region, allMarkers, xiNodeInfo, regionD, nodeIdentifierStart, coordinates, outFile=[]): fm = region.getFieldmodule() if outFile: fm.beginChange() # if xiNodeInfo['nodeType'] == 'nodes': nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) mesh = fm.findMeshByDimension(3) mesh1d = fm.findMeshByDimension(1) cache = fm.createFieldcache() xiNodeName = findOrCreateFieldStoredString(fm, name=xiNodeInfo['nameStr']) xiNodeLocation = findOrCreateFieldStoredMeshLocation( fm, mesh, name="elementxi_location") xiNodeTemplate = nodes.createNodetemplate() xiNodeTemplate.defineField(xiNodeLocation) xiNodeTemplate.defineField(coordinates) xiNodeTemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) xiNodeTemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) xiNodeTemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) xiNodeTemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) xiMeshGroup = AnnotationGroup( region, ('tracts_xi_elements', None)).getMeshGroup(mesh1d) nodeIdentifier = nodeIdentifierStart for key in allMarkers: xiNodeGroup = findOrCreateFieldGroup( fm, xiNodeInfo['groupName'] + '_' + key) xiNodePoints = findOrCreateFieldNodeGroup(xiNodeGroup, nodes).getNodesetGroup() addxiNode = {"name": key, "xi": allMarkers[key]["xi"]} xiNodePoint = xiNodePoints.createNode(nodeIdentifier, xiNodeTemplate) xiNodePoint.merge(xiNodeTemplate) cache.setNode(xiNodePoint) elementID = allMarkers[key]["elementID"] element = mesh.findElementByIdentifier(elementID) result = xiNodeLocation.assignMeshLocation(cache, element, addxiNode["xi"]) result = coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, list(regionD[key]['centre'])) try: result = coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS1, 1, list(regionD[key]['axes'][0])) result = coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS2, 1, list(regionD[key]['axes'][1])) result = coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS3, 1, list(regionD[key]['axes'][2])) except: result = coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [1, 0, 0]) result = coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0, 1, 0]) result = coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0, 0, 1]) nodeIdentifier += 1 # write 1D elements between embedded nodes if True: mesh1d = fm.findMeshByDimension(1) elementIdentifier = 55555555 basis1d = fm.createElementbasis( 1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) eft1d = mesh1d.createElementfieldtemplate(basis1d) elementtemplate = mesh1d.createElementtemplate() elementtemplate.setElementShapeType(Element.SHAPE_TYPE_LINE) result = elementtemplate.defineField(coordinates, -1, eft1d) element = mesh1d.createElement(elementIdentifier, elementtemplate) result = element.setNodesByIdentifier( eft1d, [nodeIdentifierStart, nodeIdentifier - 1]) xiMeshGroup.addElement(element) if outFile: fm.endChange() region.writeFile(outFile) return region
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: annotationGroups ''' fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) nodetemplate = nodes.createNodetemplate() nodetemplate.defineField(coordinates) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) mesh = fm.findMeshByDimension(3) cache = fm.createFieldcache() elementsCount1 = 2 elementsCount2 = 4 elementsCount3 = 4 # Annotation fiducial point 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 = 1 lNodeIds = [] d1 = [0.5, 0.0, 0.0] d2 = [0.0, 0.5, 0.0] d3 = [0.0, 0.0, 1.0] for n3 in range(elementsCount3 + 1): lNodeIds.append([]) for n2 in range(elementsCount2 + 1): lNodeIds[n3].append([]) for n1 in range(elementsCount1 + 1): lNodeIds[n3][n2].append([]) if n3 < elementsCount3: if (n1 == 0) and ((n2 == 0) or (n2 == elementsCount2)): continue else: if (n2 == 0) or (n2 == elementsCount2) or (n1 == 0): continue node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) x = [0.5 * (n1 - 1), 0.5 * (n2 - 1), 1.0 * n3] coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3) lNodeIds[n3][n2][n1] = nodeIdentifier nodeIdentifier += 1 # Create elements mesh = fm.findMeshByDimension(3) eftfactory = eftfactory_tricubichermite(mesh, None) eftRegular = eftfactory.createEftBasic() elementtemplateRegular = mesh.createElementtemplate() elementtemplateRegular.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementtemplateRegular.defineField(coordinates, -1, eftRegular) elementtemplateCustom = mesh.createElementtemplate() elementtemplateCustom.setElementShapeType(Element.SHAPE_TYPE_CUBE) lungGroup = AnnotationGroup(region, get_lung_term("lung")) leftLungGroup = AnnotationGroup(region, get_lung_term("left lung")) rightLungGroup = AnnotationGroup(region, get_lung_term("right lung")) annotationGroups = [leftLungGroup, rightLungGroup, lungGroup] lungMeshGroup = lungGroup.getMeshGroup(mesh) leftLungMeshGroup = leftLungGroup.getMeshGroup(mesh) rightLungMeshGroup = rightLungGroup.getMeshGroup(mesh) eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) eft2 = eftfactory.createEftWedgeCollapseXi1Quadrant([3, 7]) eft3 = eftfactory.createEftWedgeCollapseXi2Quadrant([5, 6]) eft4 = eftfactory.createEftWedgeCollapseXi2Quadrant([7, 8]) eft5 = eftfactory.createEftWedgeCollapseXi1Quadrant([5, 7]) eft6 = eftfactory.createEftTetrahedronCollapseXi1Xi2Quadrant(8, 2) eft7 = eftfactory.createEftTetrahedronCollapseXi1Xi2Quadrant(6, 3) elementIdentifier = 1 for e3 in range(elementsCount3): for e2 in range(elementsCount2): for e1 in range(elementsCount1): eft = eftRegular nodeIdentifiers = [ lNodeIds[e3][e2][e1], lNodeIds[e3][e2][e1 + 1], lNodeIds[e3][e2 + 1][e1], lNodeIds[e3][e2 + 1][e1 + 1], lNodeIds[e3 + 1][e2][e1], lNodeIds[e3 + 1][e2][e1 + 1], lNodeIds[e3 + 1][e2 + 1][e1], lNodeIds[e3 + 1][e2 + 1][e1 + 1] ] scalefactors = None if (e3 < elementsCount3 - 1): if (e2 == 0) and (e1 == 0): # Back wedge elements nodeIdentifiers.pop(4) nodeIdentifiers.pop(0) eft = eft1 scalefactors = [-1.0] elif (e2 == elementsCount2 - 1) and (e1 == 0): # Front wedge elements nodeIdentifiers.pop(6) nodeIdentifiers.pop(2) eft = eft2 else: if (e2 == 0) and (e1 == 1): # Top back wedge elements nodeIdentifiers.pop(5) nodeIdentifiers.pop(4) eft = eft3 elif (e2 == elementsCount2 - 1) and (e1 == 1): # Top front wedge elements nodeIdentifiers.pop(7) nodeIdentifiers.pop(6) eft = eft4 scalefactors = [-1.0] elif (e2 == 1) and (e1 == 0): # Top middle back wedge element nodeIdentifiers.pop(6) nodeIdentifiers.pop(4) eft = eft5 elif (e2 == 2) and (e1 == 0): # Top middle front wedge element nodeIdentifiers.pop(6) nodeIdentifiers.pop(4) eft = eft5 if (e2 == 0) and (e1 == 0): # Top back tetrahedron element nodeIdentifiers.pop(6) nodeIdentifiers.pop(5) nodeIdentifiers.pop(4) nodeIdentifiers.pop(0) eft = eft6 scalefactors = [-1.0] if (e2 == elementsCount2 - 1) and (e1 == 0): # Top front tetrahedron element nodeIdentifiers.pop(7) nodeIdentifiers.pop(6) nodeIdentifiers.pop(4) nodeIdentifiers.pop(2) eft = eft7 scalefactors = [-1.0] if eft is eftRegular: element = mesh.createElement(elementIdentifier, elementtemplateRegular) else: elementtemplateCustom.defineField(coordinates, -1, eft) element = mesh.createElement(elementIdentifier, elementtemplateCustom) element.setNodesByIdentifier(eft, nodeIdentifiers) if scalefactors: element.setScaleFactors(eft, scalefactors) elementIdentifier += 1 leftLungMeshGroup.addElement(element) lungMeshGroup.addElement(element) # Apex annotation point idx = elementsCount1 * elementsCount2 * ( elementsCount3 - 1) + elementsCount1 * (elementsCount2 // 2) element1 = mesh.findElementByIdentifier(idx) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) markerName.assignString(cache, 'apex of left lung') markerLocation.assignMeshLocation(cache, element1, [1.0, 1.0, 1.0]) 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: annotationGroups """ centralPath = options['Central path'] segmentProfile = options['Segment profile'] segmentCount = options['Number of segments'] startPhase = options['Start phase'] % 360.0 proximalLength = options['Proximal length'] transverseLength = options['Transverse length'] proximalInnerRadius = options['Proximal inner radius'] proximalTCWidth = options['Proximal tenia coli width'] proximalTransverseInnerRadius = options['Proximal-transverse inner radius'] proximalTransverseTCWidth = options['Proximal-transverse tenia coli width'] transverseDistalInnerRadius = options['Transverse-distal inner radius'] transverseDistalTCWidth = options['Transverse-distal tenia coli width'] distalInnerRadius = options['Distal inner radius'] distalTCWidth = options['Distal tenia coli width'] segmentSettings = segmentProfile.getScaffoldSettings() elementsCountAroundTC = segmentSettings['Number of elements around tenia coli'] elementsCountAroundHaustrum = segmentSettings['Number of elements around haustrum'] cornerInnerRadiusFactor = segmentSettings['Corner inner radius factor'] haustrumInnerRadiusFactor = segmentSettings['Haustrum inner radius factor'] segmentLengthEndDerivativeFactor = segmentSettings['Segment length end derivative factor'] segmentLengthMidDerivativeFactor = segmentSettings['Segment length mid derivative factor'] tcCount = segmentSettings['Number of tenia coli'] tcThickness = segmentSettings['Tenia coli thickness'] elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum)*tcCount elementsCountAlongSegment = segmentSettings['Number of elements along segment'] elementsCountThroughWall = segmentSettings['Number of elements through wall'] wallThickness = segmentSettings['Wall thickness'] useCrossDerivatives = segmentSettings['Use cross derivatives'] useCubicHermiteThroughWall = not(segmentSettings['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment*segmentCount) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections = True, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength(cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount # print('Length = ', length) elementAlongLength = length / elementsCountAlong # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) # Generate variation of radius & tc width along length lengthList = [0.0, proximalLength, proximalLength + transverseLength, length] innerRadiusList = [proximalInnerRadius, proximalTransverseInnerRadius, transverseDistalInnerRadius, distalInnerRadius] innerRadiusAlongElementList, dInnerRadiusAlongElementList = interp.sampleParameterAlongLine(lengthList, innerRadiusList, elementsCountAlong) tcWidthList = [proximalTCWidth, proximalTransverseTCWidth, transverseDistalTCWidth, distalTCWidth] tcWidthAlongElementList, dTCWidthAlongElementList = interp.sampleParameterAlongLine(lengthList, tcWidthList, elementsCountAlong) # Account for reduced haustrum appearance in transverse and distal pig colon if tcCount == 2: haustrumInnerRadiusFactorList = [haustrumInnerRadiusFactor, haustrumInnerRadiusFactor*0.75, haustrumInnerRadiusFactor*0.5, haustrumInnerRadiusFactor*0.2] haustrumInnerRadiusFactorAlongElementList = \ interp.sampleParameterAlongLine(lengthList, haustrumInnerRadiusFactorList, elementsCountAlong)[0] else: haustrumInnerRadiusFactorAlongElementList = [haustrumInnerRadiusFactor]*(elementsCountAlong+1) # Create annotation groups for colon sections elementsAlongInProximal = round(proximalLength/elementAlongLength) elementsAlongInTransverse = round(transverseLength/elementAlongLength) elementsAlongInDistal = elementsCountAlong - elementsAlongInProximal - elementsAlongInTransverse elementsCountAlongGroups = [elementsAlongInProximal, elementsAlongInTransverse, elementsAlongInDistal] colonGroup = AnnotationGroup(region, get_colon_term("colon")) if tcCount == 1: proximalGroup = AnnotationGroup(region, get_colon_term("proximal colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) distalGroup = AnnotationGroup(region, get_colon_term("distal colon")) annotationGroupAlong = [[colonGroup, proximalGroup], [colonGroup, transverseGroup], [colonGroup, distalGroup]] elif tcCount == 2: spiralGroup = AnnotationGroup(region, get_colon_term("spiral colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) distalGroup = AnnotationGroup(region, get_colon_term("distal colon")) annotationGroupAlong = [[colonGroup, spiralGroup], [colonGroup, transverseGroup], [colonGroup, distalGroup]] elif tcCount == 3: ascendingGroup = AnnotationGroup(region, get_colon_term("ascending colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) descendingGroup = AnnotationGroup(region, get_colon_term("descending colon")) annotationGroupAlong = [[colonGroup, ascendingGroup], [colonGroup, transverseGroup], [colonGroup, descendingGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsThroughWall = [] for i in range(elementsCountThroughWall): annotationGroupsThroughWall.append([ ]) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] sxRefExtrudeList = [] # Create object colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongElementList, innerRadiusAlongElementList, dInnerRadiusAlongElementList, tcWidthAlongElementList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) # Project reference point for warping onto central path start = nSegment * elementsCountAlongSegment end = (nSegment + 1) * elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xInner, elementsCountAround, elementsCountAlongSegment, segmentLength, sx[start:end], sd1[start:end], sd2[start:end], sd12[start:end]) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList, innerRadiusAlongElementList[start:end], closedProximalEnd=False) # Store points along length xExtrude += xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:] d1Extrude += d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:] d2Extrude += d2WarpedList if nSegment == 0 else d2WarpedList[elementsCountAround:] d3UnitExtrude += d3WarpedUnitList if nSegment == 0 else d3WarpedUnitList[elementsCountAround:] sxRefExtrudeList += sxRefList if nSegment == 0 else sxRefList[elementsCountAround:] contractedWallThicknessList = colonSegmentTubeMeshInnerPoints.getContractedWallThicknessList() # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, contractedWallThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) relaxedLengthList, xiList = colonSegmentTubeMeshInnerPoints.getRelaxedLengthAndXiList() closedProximalEnd = False if tcThickness > 0: tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() xList, d1List, d2List, d3List, annotationArrayAround = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tubeTCWidthList, tcThickness, sxRefExtrudeList, annotationGroupsAround, closedProximalEnd) # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = createFlatAndTextureCoordinatesTeniaColi( xiList, relaxedLengthList, length, wallThickness, tcCount, tcThickness, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, transitElementList, closedProximalEnd) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) else: # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, relaxedLengthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) 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'] isDefault = 'Default' in parameterSetName isMouse = 'Mouse' in parameterSetName isMean = 'mean' in parameterSetName fm = region.getFieldmodule() nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) coordinates = findOrCreateFieldCoordinates(fm) mesh = fm.findMeshByDimension(3) cache = fm.createFieldcache() nodetemplate = nodes.createNodetemplate() nodetemplate.defineField(coordinates) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) armCount = 3 elementLengthCentral = options['Element width central'] elementLengths = [ options['Element length along arm'], options['Element width across arm'], options['Element thickness'] ] elementsCountsAlongArms = options['Numbers of elements along arms'] elementsCount2 = 2 elementsCount3 = 1 useCrossDerivatives = False # arm group annotations for user armTerms, _ = getAutomaticArmFaceTerms(armCount) armGroups = [AnnotationGroup(region, armTerm) for armTerm in armTerms] stellateTerm = get_stellate_term( "cervicothoracic ganglion") if isMouse else ("stellate", None) stellateGroup = AnnotationGroup(region, stellateTerm) annotationGroups = [stellateGroup] + armGroups armMeshGroups = [a.getMeshGroup(mesh) for a in armGroups] stellateMeshGroup = stellateGroup.getMeshGroup(mesh) # markers with element number and xi position allMarkers = {} if isMouse: xProportion = {} xProportion['ICN'] = 0.9 xProportion['VA'] = 0.9 xProportion['DA'] = 0.9 xProportion['C8'] = 0.9 xProportion['T1'] = 0.25 xProportion['T2'] = 0.5 xProportion['T3'] = 0.75 xProportion['TST'] = 1 armNumber = {} armNumber['ICN'] = 2 armNumber['VA'] = 2 armNumber['DA'] = 3 armNumber['C8'] = 3 armNumber['T1'] = 1 armNumber['T2'] = 1 armNumber['T3'] = 1 armNumber['TST'] = 1 nerveAbbrev = list(xProportion.keys()) elementIndex = {} xi1 = {} for nerve in nerveAbbrev: elementIndex[nerve] = int( xProportion[nerve] * elementsCountsAlongArms[armNumber[nerve] - 1]) xi1[nerve] = 1 if xProportion[nerve] == 1 else xProportion[ nerve] * elementsCountsAlongArms[armNumber[nerve] - 1] - elementIndex[nerve] elementIndex[nerve] += 1 if xProportion[nerve] < 1 else 0 allMarkers = { "Inferior cardiac nerve": { "elementID": elementIndex['ICN'] + 2 * elementsCountsAlongArms[0], "xi": [xi1['ICN'], 0.0, 0.5] }, "Ventral ansa subclavia": { "elementID": elementIndex['VA'] + 2 * elementsCountsAlongArms[0] + elementsCountsAlongArms[1], "xi": [xi1['VA'], 1.0, 0.5] }, "Dorsal ansa subclavia": { "elementID": elementIndex['DA'] + 2 * (elementsCountsAlongArms[0] + elementsCountsAlongArms[1]), "xi": [xi1['DA'], 0.0, 0.5] }, "Cervical spinal nerve 8": { "elementID": elementIndex['C8'] + 2 * (elementsCountsAlongArms[0] + elementsCountsAlongArms[1]) + elementsCountsAlongArms[2], "xi": [xi1['C8'], 1.0, 0.5] }, "Thoracic spinal nerve 1": { "elementID": elementIndex['T1'], "xi": [xi1['T1'], 0.0, 0.5] }, "Thoracic spinal nerve 2": { "elementID": elementIndex['T2'], "xi": [xi1['T2'], 0.0, 0.5] }, "Thoracic spinal nerve 3": { "elementID": elementIndex['T3'], "xi": [xi1['T3'], 0.0, 0.5] }, "Thoracic sympathetic nerve trunk": { "elementID": elementIndex['TST'], "xi": [xi1['TST'], 1.0, 0.5] }, } markerGroup = findOrCreateFieldGroup(fm, "marker") markerName = findOrCreateFieldStoredString(fm, name="marker_name") markerLocation = findOrCreateFieldStoredMeshLocation( fm, mesh, name="marker_location") markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() markerTemplateInternal = nodes.createNodetemplate() markerTemplateInternal.defineField(markerName) markerTemplateInternal.defineField(markerLocation) # Create nodes nodeIdentifier = 1 minArmAngle = 2 * math.pi / armCount halfArmArcAngleRadians = minArmAngle / 2 if not isMean: dipMultiplier = 1 for na in range(armCount): elementsCount_i = [ elementsCountsAlongArms[na], elementsCount2, elementsCount3 ] x, ds1, ds2, nWheelEdge = createArm(halfArmArcAngleRadians, elementLengths, elementLengthCentral, elementsCount_i, dipMultiplier, armCount, na) for ix in range(len(x)): if na == 0 or ix not in nWheelEdge: node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x[ix]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, ds1[ix]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, ds2[ix]) nodeIdentifier += 1 else: x_dx_all = cls.mouseMeanMesh['meshEdits'] xyz_all = [x[0] for x in x_dx_all] dxyz = [[x[1], x[2]] for x in x_dx_all] nodeIdentifier = 1 for i, nx in enumerate(xyz_all): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dxyz[i][0]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dxyz[i][1]) nodeIdentifier += 1 nodesCountsPerArm = [0] + [((elementsCount2 + 1) * e + 1) * 2 for e in elementsCountsAlongArms] # Create elements bicubichermitelinear = eftfactory_bicubichermitelinear( mesh, useCrossDerivatives) eft = bicubichermitelinear.createEftNoCrossDerivatives( ) #createEftBasic() elementtemplate = mesh.createElementtemplate() elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementtemplate.defineField(coordinates, -1, eft) elementtemplateX = mesh.createElementtemplate() elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementIdentifier = 1 cumNodesCountsPerArm = [ sum(nodesCountsPerArm[:i + 1]) for i in range(len(nodesCountsPerArm)) ] nCentre = [ elementsCountsAlongArms[0] + 1, int(nodesCountsPerArm[1] / 2) + elementsCountsAlongArms[0] + 1 ] for na in range(armCount): for e3 in range(elementsCount3): for e2 in range(elementsCount2): for e1 in range(elementsCountsAlongArms[na]): scalefactors = None ### NODES ### no2 = (elementsCountsAlongArms[na] + 1) no3 = (elementsCount2 + 1) * no2 - 2 offset = (cumNodesCountsPerArm[na]) bni = e3 * no3 + e2 * no2 + e1 + 1 + offset if e2 == 0: if e1 == 0 and na > 0: # and na < armCount -1: # wheelSouth nWh = cumNodesCountsPerArm[na - 1] + ( 2 * elementsCountsAlongArms[na - 1]) + 2 nplUq = int( nodesCountsPerArm[na + 1] / 2 ) - elementsCountsAlongArms[ na] # unused nodes at centre and shared edge npl = int( nodesCountsPerArm[na + 1] / 2) # nodes at centre and shared edge if na < armCount - 1: cn = cumNodesCountsPerArm[ na] + elementsCountsAlongArms[na] - 2 no2 = cumNodesCountsPerArm[na] em = elementsCountsAlongArms[na] nwPrev = [ nWh, nWh + int(nodesCountsPerArm[na] / 2) ] # previous arm's edge, depends on armCount. nodeIdentifiers = [ nwPrev[0], no2 + 1, nCentre[0], no2 + em, nwPrev[1], no2 + em - 1 + nplUq, nCentre[1], bni + (4 * em) - 2 ] else: nplPrev = int( nodesCountsPerArm[na] / 2) - 2 no2 = elementsCountsAlongArms[na] - 1 no3 = int( nodesCountsPerArm[na + 1] / 2) - 3 nwPrev = [ cumNodesCountsPerArm[na - 1] + 2 * (elementsCountsAlongArms[na - 1]), cumNodesCountsPerArm[na - 1] + 2 * (elementsCountsAlongArms[na - 1]) + nplPrev ] start = cumNodesCountsPerArm[na] - 3 nodeIdentifiers = [ nwPrev[0], start, nCentre[0], start + no2, nwPrev[1], start + no3, nCentre[1], start + no2 + no3 ] elif e1 == elementsCountsAlongArms[ na] - 1: # armEnd, south if na == 0: nodeIdentifiers = [ bni, bni + no2 - 1, bni + no2, bni + no3, bni + no2 + no3 - 1, bni + no2 + no3 ] else: no3 = armCount * elementsCountsAlongArms[ na] - 1 no2 = elementsCountsAlongArms[na] if na > 1: bni -= 4 no3 -= 1 nodeIdentifiers = [ bni - 1, bni + no2 - 2, bni + no2 - 1, bni + no3 - 1, bni + no2 - 2 + no3, bni + no2 + no3 - 1 ] elif na > 0 and e1 > 0: # [na=1+, e1=1+, e2=0] for len=3+ bni -= 1 + ((armCount + 1) * (na - 1)) no2 = elementsCountsAlongArms[na] no3 = armCount * no2 - (na - 1) - 1 nodeIdentifiers = [ bni, bni + 1, bni + no2 - 1, bni + no2, bni + no3, bni + no3 + 1, bni + no2 + no3 - 1, bni + no2 + no3 ] else: nodeIdentifiers = [ bni, bni + 1, bni + no2 - 1, bni + no2, bni + no3, bni + no3 + 1, bni + no2 + no3 - 1, bni + no2 + no3 ] else: if e1 == 0 and na > 0: # and na < armCount -1: # wheelNorth if na < armCount - 1: bni -= armCount npl = int( nodesCountsPerArm[na + 1] / 2) - 2 no2 = elementsCountsAlongArms[na] nodeIdentifiers = [ nCentre[0], bni + 1, bni + no2 + 1, bni + no2 + 2, nCentre[1], bni + npl + 1, bni + npl + no2 + 1, bni + npl + no2 + 2 ] else: # last arm bni = cumNodesCountsPerArm[na] - 2 - ( armCount - elementsCountsAlongArms[na]) nodeIdentifiers = [ nCentre[0], bni + 1, 1, bni + no2, nCentre[1], bni + no3 - 2, int(nodesCountsPerArm[1] / 2) + 1, bni + no2 + no3 - armCount ] elif e1 == elementsCountsAlongArms[ na] - 1: # armEnd north if na > 0: no2 = elementsCountsAlongArms[na] nplUq = int( nodesCountsPerArm[na + 1] / 2) - 2 if na > 1: adj = na - 1 bni -= armCount * na + ( armCount - elementsCountsAlongArms[na]) + 1 if elementsCountsAlongArms[na] < 3: bni += 1 if elementsCountsAlongArms[na] > 3: bni -= elementsCountsAlongArms[ na] - 3 no2 += 1 - adj no3 = nplUq - adj nodeIdentifiers = [ bni, bni + 1, bni + no2, bni + no3, bni + no3 + 1, bni + no2 + no3 ] else: bni -= armCount nodeIdentifiers = [ bni, bni + 1, bni + no2 + 1, bni + nplUq, bni + nplUq + 1, bni + no2 + nplUq + 1 ] else: nodeIdentifiers = [ bni - 1, bni, bni + no2 - 1, bni + no3 - 1, bni + no3, bni + no2 + no3 - 1 ] elif na > 0 and e1 > 0: # [na=1+, e1=1+, e2=1] for len=3+ adj = na - 1 bni -= armCount * na + adj no2 -= adj k = armCount * elementsCountsAlongArms[na] - na nodeIdentifiers = [ bni, bni + 1, bni + no2, bni + no2 + 1, bni + k, bni + k + 1, bni + no2 + k, bni + no2 + k + 1 ] else: nodeIdentifiers = [ bni - 1, bni, bni + no2 - 1, bni + no2, bni + no3 - 1, bni + no3, bni + no2 + no3 - 1, bni + no2 + no3 ] if e1 == 0: # wheel eft1 = bicubichermitelinear.createEftNoCrossDerivatives( ) if armCount == 3: if e2 == 0: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] scaleEftNodeValueLabels( eft1, [1, 5], [ Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2 ], [1]) ns = [3, 7] else: ns = [1, 5] if na == 0: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) if e2 == 0: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) elif na == 1: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) if e2 == 0: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [1])]) elif e2 == 1: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) elif na == 2: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) if e2 == 0: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elif e2 == 1: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elif armCount == 4: if e2 == 0: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] scaleEftNodeValueLabels( eft1, [1, 5], [ Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2 ], [1]) ns = [3, 7] else: ns = [1, 5] if na == 0: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) if e2 == 0: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) elif na == 1: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) if e2 == 0: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [1])]) else: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) elif na == 2: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) if e2 == 0: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) else: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [1])]) elif na == 3: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) if e2 == 0: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [])]) else: remapEftNodeValueLabel( eft1, ns, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elif e1 < (elementsCountsAlongArms[na] - 1): eft1 = eft elementtemplate1 = elementtemplate else: # rounded ends of arms. Collapse xi2 at xi1 = 1 eft1 = bicubichermitelinear.createEftNoCrossDerivatives( ) remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS2, []) if e2 == 0: remapEftNodeValueLabel( eft1, [2, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) nodeIdentifiers = [ nodeIdentifiers[0], nodeIdentifiers[2], nodeIdentifiers[1], nodeIdentifiers[3], nodeIdentifiers[5], nodeIdentifiers[4] ] else: # e2 == 1 setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] remapEftNodeValueLabel( eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) ln_map = [1, 2, 3, 2, 4, 5, 6, 5] remapEftLocalNodes(eft1, 6, ln_map) if eft1 is not eft: elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX element = mesh.createElement(elementIdentifier, elementtemplate1) result = element.setNodesByIdentifier( eft1, nodeIdentifiers) result3 = element.setScaleFactors( eft1, scalefactors) if scalefactors else None # add to meshGroup stellateMeshGroup.addElement(element) armMeshGroups[na].addElement(element) elementIdentifier += 1 # annotation fiducial points if isMouse: for key in allMarkers: xi = allMarkers[key]["xi"] addMarker = {"name": key, "xi": allMarkers[key]["xi"]} markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) markerName.assignString(cache, addMarker["name"]) elementID = allMarkers[key]["elementID"] element = mesh.findElementByIdentifier(elementID) markerLocation.assignMeshLocation(cache, element, addMarker["xi"]) return annotationGroups
def generateBaseMesh(cls, region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ centralPath = options['Central path'] segmentCount = options['Number of segments'] elementsCountAround = options['Number of elements around'] elementsCountAlongSegment = options['Number of elements along segment'] elementsCountThroughWall = options['Number of elements through wall'] duodenumLength = options['Duodenum length'] jejunumLength = options['Jejunum length'] duodenumInnerRadius = options['Duodenum inner radius'] duodenumJejunumInnerRadius = options['Duodenum-jejunum inner radius'] jejunumIleumInnerRadius = options['Jejunum-ileum inner radius'] ileumInnerRadius = options['Ileum inner radius'] wallThickness = options['Wall thickness'] useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not(options['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment*segmentCount) startPhase = 0.0 firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i],',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections = True, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength(cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount elementAlongLength = length / elementsCountAlong # print('Length = ', length) # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongSegment*segmentCount) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) # Generate variation of radius & tc width along length lengthList = [0.0, duodenumLength, duodenumLength + jejunumLength, length] innerRadiusList = [duodenumInnerRadius, duodenumJejunumInnerRadius, jejunumIleumInnerRadius, ileumInnerRadius] innerRadiusSegmentList, dInnerRadiusSegmentList = interp.sampleParameterAlongLine(lengthList, innerRadiusList, segmentCount) # Create annotation groups for small intestine sections elementsAlongDuodenum = round(duodenumLength / elementAlongLength) elementsAlongJejunum = round(jejunumLength / elementAlongLength) elementsAlongIleum = elementsCountAlong - elementsAlongDuodenum - elementsAlongJejunum elementsCountAlongGroups = [elementsAlongDuodenum, elementsAlongJejunum, elementsAlongIleum] smallintestineGroup = AnnotationGroup(region, get_smallintestine_term("small intestine")) duodenumGroup = AnnotationGroup(region, get_smallintestine_term("duodenum")) jejunumGroup = AnnotationGroup(region, get_smallintestine_term("jejunum")) ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) annotationGroupAlong = [[smallintestineGroup, duodenumGroup], [smallintestineGroup, jejunumGroup], [smallintestineGroup, ileumGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsAround = [] for i in range(elementsCountAround): annotationGroupsAround.append([ ]) annotationGroupsThroughWall = [] for i in range(elementsCountThroughWall): annotationGroupsThroughWall.append([ ]) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] # Create object smallIntestineSegmentTubeMeshInnerPoints = CylindricalSegmentTubeMeshInnerPoints( elementsCountAround, elementsCountAlongSegment, segmentLength, wallThickness, innerRadiusSegmentList, dInnerRadiusSegmentList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, radiusAlongSegmentList = \ smallIntestineSegmentTubeMeshInnerPoints.getCylindricalSegmentTubeMeshInnerPoints(nSegment) # Project reference point for warping onto central path start = nSegment*elementsCountAlongSegment end = (nSegment + 1)*elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xInner, elementsCountAround, elementsCountAlongSegment, segmentLength, sx[start:end], sd1[start:end], sd2[start:end], sd12[start:end]) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList, radiusAlongSegmentList, closedProximalEnd=False) # Store points along length xExtrude = xExtrude + (xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:]) d1Extrude = d1Extrude + (d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:]) # Smooth d2 for nodes between segments and recalculate d3 if nSegment == 0: d2Extrude = d2Extrude + (d2WarpedList[:-elementsCountAround]) d3UnitExtrude = d3UnitExtrude + (d3WarpedUnitList[:-elementsCountAround]) else: xSecondFace = xWarpedList[elementsCountAround:elementsCountAround*2] d2SecondFace = d2WarpedList[elementsCountAround:elementsCountAround*2] for n1 in range(elementsCountAround): nx = [xLastTwoFaces[n1], xLastTwoFaces[n1 + elementsCountAround], xSecondFace[n1]] nd2 = [d2LastTwoFaces[n1], d2LastTwoFaces[n1 + elementsCountAround], d2SecondFace[n1]] d2 = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixStartDerivative = True, fixEndDerivative = True)[1] d2Extrude.append(d2) d3Unit = vector.normalise(vector.crossproduct3(vector.normalise(d1LastTwoFaces[n1 + elementsCountAround]), vector.normalise(d2))) d3UnitExtrude.append(d3Unit) d2Extrude = d2Extrude + \ (d2WarpedList[elementsCountAround:-elementsCountAround] if nSegment < segmentCount - 1 else d2WarpedList[elementsCountAround:]) d3UnitExtrude = d3UnitExtrude + \ (d3WarpedUnitList[elementsCountAround:-elementsCountAround] if nSegment < segmentCount - 1 else d3WarpedUnitList[elementsCountAround:]) xLastTwoFaces = xWarpedList[-elementsCountAround*2:] d1LastTwoFaces = d1WarpedList[-elementsCountAround*2:] d2LastTwoFaces = d2WarpedList[-elementsCountAround*2:] # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, [wallThickness]*(elementsCountAlong+1), elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) flatWidthList, xiList = smallIntestineSegmentTubeMeshInnerPoints.getFlatWidthAndXiList() # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, flatWidthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=False) 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 __init__(self, sourceRegion, targetRegion, sourceAnnotationGroups=[]): ''' Assumes targetRegion is empty. :param sourceAnnotationGroups: List of AnnotationGroup for source mesh in sourceRegion. A copy containing the refined elements is created by the MeshRefinement. ''' self._sourceRegion = sourceRegion self._sourceFm = sourceRegion.getFieldmodule() self._sourceCache = self._sourceFm.createFieldcache() self._sourceCoordinates = findOrCreateFieldCoordinates(self._sourceFm) # get range of source coordinates for octree range self._sourceFm.beginChange() sourceNodes = self._sourceFm.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) minimumsField = self._sourceFm.createFieldNodesetMinimum( self._sourceCoordinates, sourceNodes) result, minimums = minimumsField.evaluateReal(self._sourceCache, 3) assert result == ZINC_OK, 'MeshRefinement failed to get minimum coordinates' maximumsField = self._sourceFm.createFieldNodesetMaximum( self._sourceCoordinates, sourceNodes) result, maximums = maximumsField.evaluateReal(self._sourceCache, 3) assert result == ZINC_OK, 'MeshRefinement failed to get maximum coordinates' xrange = [(maximums[i] - minimums[i]) for i in range(3)] edgeTolerance = 0.5 * (max(xrange)) if edgeTolerance == 0.0: edgeTolerance = 1.0 minimums = [(minimums[i] - edgeTolerance) for i in range(3)] maximums = [(maximums[i] + edgeTolerance) for i in range(3)] minimumsField = None maximumsField = None self._sourceMesh = self._sourceFm.findMeshByDimension(3) self._sourceNodes = self._sourceFm.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self._sourceElementiterator = self._sourceMesh.createElementiterator() self._octree = Octree(minimums, maximums) self._targetRegion = targetRegion self._targetFm = targetRegion.getFieldmodule() self._targetFm.beginChange() self._targetCache = self._targetFm.createFieldcache() self._targetCoordinates = findOrCreateFieldCoordinates(self._targetFm) self._targetNodes = self._targetFm.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self._nodetemplate = self._targetNodes.createNodetemplate() self._nodetemplate.defineField(self._targetCoordinates) self._targetMesh = self._targetFm.findMeshByDimension(3) self._targetBasis = self._targetFm.createElementbasis( 3, Elementbasis.FUNCTION_TYPE_LINEAR_LAGRANGE) self._targetEft = self._targetMesh.createElementfieldtemplate( self._targetBasis) self._targetElementtemplate = self._targetMesh.createElementtemplate() self._targetElementtemplate.setElementShapeType( Element.SHAPE_TYPE_CUBE) result = self._targetElementtemplate.defineField( self._targetCoordinates, -1, self._targetEft) self._nodeIdentifier = 1 self._elementIdentifier = 1 # prepare annotation group map self._sourceAnnotationGroups = sourceAnnotationGroups self._annotationGroups = [] self._sourceAndTargetMeshGroups = [] self._sourceAndTargetNodesetGroups = [] for sourceAnnotationGroup in sourceAnnotationGroups: targetAnnotationGroup = AnnotationGroup( self._targetRegion, sourceAnnotationGroup.getTerm()) self._annotationGroups.append(targetAnnotationGroup) # assume have only highest dimension element or node/point annotation groups: if sourceAnnotationGroup.hasMeshGroup(self._sourceMesh): self._sourceAndTargetMeshGroups.append( (sourceAnnotationGroup.getMeshGroup(self._sourceMesh), targetAnnotationGroup.getMeshGroup(self._targetMesh))) else: self._sourceAndTargetNodesetGroups.append( (sourceAnnotationGroup.getNodesetGroup(self._sourceNodes), targetAnnotationGroup.getNodesetGroup(self._targetNodes))) # prepare element -> marker point list map self.elementMarkerMap = {} sourceMarkerGroup = findOrCreateFieldGroup(self._sourceFm, "marker") sourceMarkerName = findOrCreateFieldStoredString(self._sourceFm, name="marker_name") sourceMarkerLocation = findOrCreateFieldStoredMeshLocation( self._sourceFm, self._sourceMesh, name="marker_location") sourceMarkerNodes = findOrCreateFieldNodeGroup( sourceMarkerGroup, sourceNodes).getNodesetGroup() nodeIter = sourceMarkerNodes.createNodeiterator() node = nodeIter.next() while node.isValid(): self._sourceCache.setNode(node) element, xi = sourceMarkerLocation.evaluateMeshLocation( self._sourceCache, self._sourceMesh.getDimension()) if element.isValid(): elementIdentifier = element.getIdentifier() markerName = sourceMarkerName.evaluateString(self._sourceCache) markerList = self.elementMarkerMap.get(elementIdentifier) if not markerList: markerList = [] self.elementMarkerMap[elementIdentifier] = markerList markerList.append((markerName, xi, node.getIdentifier())) node = nodeIter.next() if self.elementMarkerMap: self._targetMarkerGroup = findOrCreateFieldGroup( self._targetFm, "marker") self._targetMarkerName = findOrCreateFieldStoredString( self._targetFm, name="marker_name") self._targetMarkerLocation = findOrCreateFieldStoredMeshLocation( self._targetFm, self._targetMesh, name="marker_location") self._targetMarkerNodes = findOrCreateFieldNodeGroup( self._targetMarkerGroup, self._targetNodes).getNodesetGroup() self._targetMarkerTemplate = self._targetMarkerNodes.createNodetemplate( ) self._targetMarkerTemplate.defineField(self._targetMarkerName) self._targetMarkerTemplate.defineField(self._targetMarkerLocation)
def test_sphere1(self): """ Test creation of Sphere scaffold. """ scaffold = MeshType_3d_solidsphere2 parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default"]) options = scaffold.getDefaultOptions("Default") self.assertEqual(16, len(options)) self.assertEqual(4, options.get("Number of elements across axis 1")) self.assertEqual(4, options.get("Number of elements across axis 2")) self.assertEqual(4, options.get("Number of elements across axis 3")) self.assertEqual(0, options.get("Number of elements across shell")) self.assertEqual(1, options.get("Number of elements across transition")) self.assertEqual(1.0, options.get("Radius1")) self.assertEqual(1.0, options.get("Radius2")) self.assertEqual(1.0, options.get("Radius3")) self.assertEqual(1.0, options.get("Shell element thickness proportion")) self.assertEqual( [0, 4], options.get("Range of elements required in direction 1")) self.assertEqual( [0, 4], options.get("Range of elements required in direction 2")) self.assertEqual( [0, 4], options.get("Range of elements required in direction 3")) self.assertEqual([1, 2, 3], options.get("Box derivatives")) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = scaffold.generateMesh(region, options) self.assertEqual(2, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) self.assertEqual(32, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) self.assertEqual(108, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(128, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self.assertEqual(53, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) # check coordinates range, sphere volume coordinates = fieldmodule.findFieldByName( "coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) assertAlmostEqualList(self, minimums, [-1.0, -1.0, -1.0], 1.0E-6) assertAlmostEqualList(self, maximums, [1.0, 1.0, 1.0], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) surfaceGroup = AnnotationGroup(region, ("sphere surface", "")) is_exterior = fieldmodule.createFieldIsExterior() surfaceMeshGroup = surfaceGroup.getMeshGroup(mesh2d) surfaceMeshGroup.addElementsConditional(is_exterior) surfaceAreaField = fieldmodule.createFieldMeshIntegral( one, coordinates, surfaceMeshGroup) 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, 12.460033954564986, delta=2.0E-1) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 4.132033912594377, delta=1.0E-3) # check some annotationGroups: expectedSizes3d = { "box group": 8, "transition group": 24, } for name in expectedSizes3d: group = getAnnotationGroupForTerm(annotationGroups, (name, '')) size = group.getMeshGroup(mesh3d).getSize() self.assertEqual(expectedSizes3d[name], size, name) # refine 8x8x8 and check result refineRegion = region.createRegion() refineFieldmodule = refineRegion.getFieldmodule() options['Refine number of elements'] = 2 meshrefinement = MeshRefinement(region, refineRegion, []) scaffold.refineMesh(meshrefinement, options) refineCoordinates = refineFieldmodule.findFieldByName( "coordinates").castFiniteElement() refineFieldmodule.defineAllFaces() mesh3d = refineFieldmodule.findMeshByDimension(3) self.assertEqual(256, mesh3d.getSize()) mesh2d = refineFieldmodule.findMeshByDimension(2) self.assertEqual(816, mesh2d.getSize()) mesh1d = refineFieldmodule.findMeshByDimension(1) self.assertEqual(880, mesh1d.getSize()) nodes = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self.assertEqual(321, nodes.getSize()) datapoints = refineFieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) # obtain surface area and volume again. If they are the same as previous, mesh is conform. with ChangeManager(refineFieldmodule): one = refineFieldmodule.createFieldConstant(1.0) surfaceGroup = AnnotationGroup(refineRegion, ("sphere surface", "")) is_exterior = refineFieldmodule.createFieldIsExterior() surfaceMeshGroup = surfaceGroup.getMeshGroup(mesh2d) surfaceMeshGroup.addElementsConditional(is_exterior) surfaceAreaField = refineFieldmodule.createFieldMeshIntegral( one, refineCoordinates, surfaceMeshGroup) surfaceAreaField.setNumbersOfPoints(4) volumeField = refineFieldmodule.createFieldMeshIntegral( one, refineCoordinates, mesh3d) volumeField.setNumbersOfPoints(3) refineFieldcache = refineFieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal( refineFieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(surfaceArea, 12.460033954564986, delta=5.0E-1) result, volume = volumeField.evaluateReal(refineFieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 4.132033912594377, delta=3.0E-1) # check ellipsoid. scaffold1 = MeshType_3d_solidsphere2 parameterSetNames = scaffold1.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default"]) options = scaffold1.getDefaultOptions("Default") options['Number of elements across axis 1'] = 4 options['Number of elements across axis 2'] = 6 options['Number of elements across axis 3'] = 8 options['Range of elements required in direction 1'] = [0, 4] options['Range of elements required in direction 2'] = [0, 6] options['Range of elements required in direction 3'] = [0, 8] options['Radius1'] = 0.5 options['Radius2'] = 0.8 options['Radius3'] = 1.0 context2 = Context("Test2") region = context2.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = scaffold1.generateMesh(region, options) self.assertEqual(2, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) self.assertEqual(136, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) self.assertEqual(452, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(510, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_NODES) self.assertEqual(195, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType( Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) # check coordinates range, sphere volume coordinates = fieldmodule.findFieldByName( "coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) assertAlmostEqualList(self, minimums, [-0.5, -0.8, -1.0], 1.0E-6) assertAlmostEqualList(self, maximums, [0.5, 0.8, 1.0], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) surfaceGroup = AnnotationGroup(region, ("sphere surface", "")) is_exterior = fieldmodule.createFieldIsExterior() surfaceMeshGroup = surfaceGroup.getMeshGroup(mesh2d) surfaceMeshGroup.addElementsConditional(is_exterior) surfaceAreaField = fieldmodule.createFieldMeshIntegral( one, coordinates, surfaceMeshGroup) 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, 7.3015173697377245, delta=2.0E-1) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 1.6741674010981926, delta=1.0E-3)
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: 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() fm.beginChange() coordinates = zinc_utils.getOrCreateCoordinateField(fm) cache = fm.createFieldcache() # generate heartventriclesbase1 model and put atria1 on it annotationGroups = MeshType_3d_heartventriclesbase1.generateBaseMesh(region, options) annotationGroups += MeshType_3d_heartatria1.generateBaseMesh(region, options) lFibrousRingGroup = AnnotationGroup(region, 'left fibrous ring', FMANumber = 77124, lyphID = 'Lyph ID unknown') rFibrousRingGroup = AnnotationGroup(region, 'right fibrous ring', FMANumber = 77125, lyphID = 'Lyph ID unknown') annotationGroups += [ lFibrousRingGroup, rFibrousRingGroup ] # annotation fiducial points fiducialGroup = zinc_utils.getOrCreateGroupField(fm, 'fiducial') fiducialCoordinates = zinc_utils.getOrCreateCoordinateField(fm, 'fiducial_coordinates') fiducialLabel = zinc_utils.getOrCreateLabelField(fm, 'fiducial_label') fiducialElementXi = zinc_utils.getOrCreateElementXiField(fm, 'fiducial_element_xi') datapoints = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) fiducialPoints = zinc_utils.getOrCreateNodesetGroup(fiducialGroup, datapoints) datapointTemplateInternal = datapoints.createNodetemplate() datapointTemplateInternal.defineField(fiducialCoordinates) datapointTemplateInternal.defineField(fiducialLabel) datapointTemplateInternal.defineField(fiducialElementXi) ############## # Create nodes ############## nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) # 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 ################# mesh = fm.findMeshByDimension(3) lFibrousRingMeshGroup = lFibrousRingGroup.getMeshGroup(mesh) rFibrousRingMeshGroup = rFibrousRingGroup.getMeshGroup(mesh) elementIdentifier = startElementIdentifier = zinc_utils.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) if scalefactors: result3 = element.setScaleFactors(eft1, scalefactors) else: result3 = 7 #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) if scalefactors: result3 = element.setScaleFactors(eft1, scalefactors) else: result3 = 7 #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) if scalefactors: result3 = element.setScaleFactors(eft1, scalefactors) else: result3 = 7 #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.0, 0.5, 1.0 ] cache.setMeshLocation(cruxElement, cruxXi) result, cruxCoordinates = coordinates.evaluateReal(cache, 3) datapoint = fiducialPoints.createNode(-1, datapointTemplateInternal) cache.setNode(datapoint) fiducialCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cruxCoordinates) fiducialLabel.assignString(cache, 'crux') fiducialElementXi.assignMeshLocation(cache, cruxElement, cruxXi) fm.endChange() return annotationGroups