def evaluateArcLength(self, nodes, field, fieldcache): componentsCount = field.getNumberOfComponents() self._parameters = [] for expression in self._expressions: sumx = None for term in expression: nodeIdentifier, nodeValueLabel, nodeVersion, scaleFactor = term fieldcache.setNode(nodes.findNodeByIdentifier(nodeIdentifier)) result, x = field.getNodeParameters(fieldcache, -1, nodeValueLabel, nodeVersion, componentsCount) if scaleFactor: x = [ v*scaleFactor for v in x ] if sumx: sumx = [ (sumx[c] + x[c]) for c in range(componentsCount) ] else: sumx = x self._parameters.append(sumx) self._arcLength = getCubicHermiteArcLength(*self._parameters) return self._arcLength
def createAnnulusMesh3d(nodes, mesh, nextNodeIdentifier, nextElementIdentifier, startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap, endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap, forceStartLinearXi3=False, forceMidLinearXi3=False, forceEndLinearXi3=False, maxStartThickness=None, maxEndThickness=None, useCrossDerivatives=False, elementsCountRadial=1, meshGroups=None, wallAnnotationGroups=None, tracksurface=None, startProportions=None, endProportions=None, rescaleStartDerivatives=False, rescaleEndDerivatives=False, sampleBlend=0.0): """ Create an annulus mesh from a loop of start points/nodes with specified derivative mappings to a loop of end points/nodes with specified derivative mappings. Derivative d3 is through the wall. Currently limited to single element layer through wall. Points/nodes order cycles fastest around the annulus, then through the wall. Note doesn't support cross derivatives. Arrays are indexed by n3 (node through wall, size 2), n2 (node along/radial), n1 (node around, variable size) and coordinate component c. :param nodes: The nodeset to create nodes in. :param mesh: The mesh to create elements in. :param nextNodeIdentifier, nextElementIdentifier: Next identifiers to use and increment. :param startPointsx, startPointsd1, startPointsd2, startPointsd3, endPointsx, endPointsd1, endPointsd2, endPointsd3: List array[n3][n1][c] or start/point coordinates and derivatives. To linearise through the wall, pass None to d3. If both ends are linear through the wall, interior points are linear through the wall. :param startNodeId, endNodeId: List array [n3][n1] of existing node identifiers to use at start/end. Pass None for argument if no nodes are specified at end. These arguments are 'all or nothing'. :param startDerivativesMap, endDerivativesMap: List array[n3][n1] of mappings for d/dxi1, d/dxi2, d/dxi3 at start/end of form: ( (1, -1, 0), (1, 0, 0), None ) where the first tuple means d/dxi1 = d/ds1 - d/ds2. Only 0, 1 and -1 may be used. None means use default e.g. d/dxi2 = d/ds2. Pass None for the entire argument to use the defaults d/dxi1 = d/ds1, d/dxi2 = d/ds2, d/dxi3 = d/ds3. Pass a 4th mapping to apply to d/dxi1 on other side of node; if not supplied first mapping applies both sides. :param forceStartLinearXi3, forceMidLinearXi3, forceEndLinearXi3: Force start, middle or end elements to be linear through the wall, even if d3 is supplied at either end. Can only use forceMidLinearXi3 only if at least one end is linear in d3. :param maxStartThickness, maxEndThickness: Optional maximum override on start/end thicknesses. :param useCrossDerivatives: May only be True if no derivatives maps are in use. :param elementsCountRadial: Optional number of elements in radial direction between start and end. :param meshGroups: Optional sequence of Zinc MeshGroup for adding all new elements to, or a sequence of length elementsCountRadial containing sequences of mesh groups to add rows of radial elements to from start to end. :param wallAnnotationGroups: Annotation groups for adding all new elements to a sequence of groups to add to elements through wall. :param tracksurface: Description for outer surface representation used for creating annulus mesh. Provides information for creating radial nodes on annulus that sit on tracksurface. Need startProportions and endProportions to work. :param startProportions: Proportion around and along of startPoints on tracksurface. These vary with nodes around as for startPoints. Values only given for tracksurface for outer layer (xi3 == 1). :param endProportions: Proportion around and along of endPoints on track surface. These vary with nodes around as for endPoints. Values only given for tracksurface for outer layer (xi3 == 1). :param rescaleStartDerivatives, rescaleEndDerivatives: Optional flags to compute and multiply additional scale factors on start, end or both radial derivatives to fit arc length, needed if derivatives are of the wrong scale for the radial distances and the chosen elementsCountRadial. If either is True, derivatives and sampled radial nodes are spaced for a gradual change of derivative from that at the other end. If both are True, scaling is set to give even sampling and arclength derivatives. :param sampleBlend: Real value varying from 0.0 to 1.0 controlling weighting of start and end derivatives when interpolating extra points in-between, where 0.0 = sample with equal end derivatives, and 1.0 = proportional to current magnitudes, interpolated in between. :return: Final values of nextNodeIdentifier, nextElementIdentifier """ assert (elementsCountRadial >= 1), 'createAnnulusMesh3d: Invalid number of radial elements' startLinearXi3 = (not startPointsd3) or forceStartLinearXi3 endLinearXi3 = (not endPointsd3) or forceEndLinearXi3 midLinearXi3 = (startLinearXi3 and endLinearXi3) or ( (startLinearXi3 or endLinearXi3) and forceMidLinearXi3) # get list whether each row of nodes in elements is linear in Xi3 # this is for element use; start/end nodes may have d3 even if element is linear rowLinearXi3 = [ startLinearXi3 ] + [midLinearXi3] * (elementsCountRadial - 1) + [endLinearXi3] assert (not useCrossDerivatives) or ((not startDerivativesMap) and (not endDerivativesMap)), \ 'createAnnulusMesh3d: Cannot use cross derivatives with derivatives map' nodesCountWall = len(startPointsx) assert (len(startPointsd1) == nodesCountWall) and (len(startPointsd2) == nodesCountWall) and \ (startLinearXi3 or (len(startPointsd3) == nodesCountWall)) and \ (len(endPointsx) == nodesCountWall) and (len(endPointsd1) == nodesCountWall) and \ (len(endPointsd2) == nodesCountWall) and (endLinearXi3 or (len(endPointsd3) == nodesCountWall)) and \ ((startNodeId is None) or (len(startNodeId) == nodesCountWall)) and \ ((endNodeId is None) or (len(endNodeId) == nodesCountWall)) and \ ((startDerivativesMap is None) or (len(startDerivativesMap) == nodesCountWall)) and \ ((endDerivativesMap is None) or (len(endDerivativesMap) == nodesCountWall)),\ 'createAnnulusMesh3d: Mismatch in number of layers through wall' elementsCountAround = nodesCountAround = len(startPointsx[0]) assert ( nodesCountAround > 1 ), 'createAnnulusMesh3d: Invalid number of points/nodes around annulus' for n3 in range(nodesCountWall): assert (len(startPointsx[n3]) == nodesCountAround) and (len(startPointsd1[n3]) == nodesCountAround) and \ (len(startPointsd2[n3]) == nodesCountAround) and \ (startLinearXi3 or (len(startPointsd3[n3]) == nodesCountAround)) and\ (len(endPointsx[n3]) == nodesCountAround) and (len(endPointsd1[n3]) == nodesCountAround) and \ (len(endPointsd2[n3]) == nodesCountAround) and \ (endLinearXi3 or (len(endPointsd3[n3]) == nodesCountAround)) and \ ((startNodeId is None) or (len(startNodeId[n3]) == nodesCountAround)) and\ ((endNodeId is None) or (len(endNodeId[n3]) == nodesCountAround)) and \ ((startDerivativesMap is None) or (len(startDerivativesMap[n3]) == nodesCountAround)) and \ ((endDerivativesMap is None) or (len(endDerivativesMap[n3]) == nodesCountAround)), \ 'createAnnulusMesh3d: Mismatch in number of points/nodes in layers through wall' rowMeshGroups = meshGroups if meshGroups: assert isinstance( meshGroups, Sequence), 'createAnnulusMesh3d: Mesh groups is not a sequence' if (len(meshGroups) == 0) or (not isinstance(meshGroups[0], Sequence)): rowMeshGroups = [meshGroups] * elementsCountRadial else: assert len(meshGroups) == elementsCountRadial, \ 'createAnnulusMesh3d: Length of meshGroups sequence does not equal elementsCountRadial' if wallAnnotationGroups: assert len(wallAnnotationGroups) == nodesCountWall - 1, \ 'createAnnulusMesh3d: Length of wallAnnotationGroups sequence does not equal elementsCountThroughWall' if tracksurface: assert startProportions and endProportions, \ 'createAnnulusMesh3d: Missing start and/or end proportions for use with tracksurface' assert len(startProportions) == nodesCountAround, \ 'createAnnulusMesh3d: Length of startProportions does not equal nodesCountAround' assert len(endProportions) == nodesCountAround, \ 'createAnnulusMesh3d: Length of endProportions does not equal nodesCountAround' fm = mesh.getFieldmodule() fm.beginChange() cache = fm.createFieldcache() coordinates = findOrCreateFieldCoordinates(fm) # Build arrays of points from start to end px = [[] for n3 in range(nodesCountWall)] pd1 = [[] for n3 in range(nodesCountWall)] pd2 = [[] for n3 in range(nodesCountWall)] pd3 = [[] for n3 in range(nodesCountWall)] # Find total wall thickness thicknessProportions = [] thicknesses = [] thicknesses.append([ vector.magnitude([ (startPointsx[nodesCountWall - 1][n1][c] - startPointsx[0][n1][c]) for c in range(3) ]) for n1 in range(nodesCountAround) ]) for n2 in range(1, elementsCountRadial): thicknesses.append([None] * nodesCountAround) thicknesses.append([ vector.magnitude([ (endPointsx[nodesCountWall - 1][n1][c] - endPointsx[0][n1][c]) for c in range(3) ]) for n1 in range(nodesCountAround) ]) for n3 in range(nodesCountWall): px[n3] = [startPointsx[n3], endPointsx[n3]] pd1[n3] = [startPointsd1[n3], endPointsd1[n3]] pd2[n3] = [startPointsd2[n3], endPointsd2[n3]] pd3[n3] = [ startPointsd3[n3] if (startPointsd3 is not None) else None, endPointsd3[n3] if (endPointsd3 is not None) else None ] startThicknessList = \ [vector.magnitude([(startPointsx[n3][n1][c] - startPointsx[n3 - (1 if n3 > 0 else 0)][n1][c]) for c in range(3)]) for n1 in range(len(startPointsx[n3]))] endThicknessList = \ [vector.magnitude([(endPointsx[n3][n1][c] - endPointsx[n3 - (1 if n3 > 0 else 0)][n1][c]) for c in range(3)]) for n1 in range(len(endPointsx[n3]))] thicknessList = [startThicknessList, endThicknessList] # thickness of each layer startThicknessProportions = [ thicknessList[0][c] / thicknesses[0][c] for c in range(nodesCountAround) ] endThicknessProportions = [ thicknessList[1][c] / thicknesses[-1][c] for c in range(nodesCountAround) ] thicknessProportions.append( [startThicknessProportions, endThicknessProportions]) if rescaleStartDerivatives: scaleFactorMapStart = [[] for n3 in range(nodesCountWall)] if rescaleEndDerivatives: scaleFactorMapEnd = [[] for n3 in range(nodesCountWall)] # following code adds in-between points, but also handles rescaling for 1 radial element for n3 in range(nodesCountWall): for n2 in range(1, elementsCountRadial): px[n3].insert(n2, [None] * nodesCountAround) pd1[n3].insert(n2, [None] * nodesCountAround) pd2[n3].insert(n2, [None] * nodesCountAround) pd3[n3].insert(n2, None if midLinearXi3 else [None] * nodesCountAround) thicknessProportions[n3].insert(n2, [None] * nodesCountAround) if maxStartThickness: for n1 in range(nodesCountAround): thicknesses[0][n1] = min(thicknesses[0][n1], maxStartThickness) if maxEndThickness: for n1 in range(nodesCountAround): thicknesses[-1][n1] = min(thicknesses[-1][n1], maxEndThickness) n3 = nodesCountWall - 1 for n1 in range(nodesCountAround): ax = startPointsx[n3][n1] ad1, ad2 = getMappedD1D2( [startPointsd1[n3][n1], startPointsd2[n3][n1]] + ([startPointsd3[n3][n1]] if startPointsd3 else []), startDerivativesMap[n3][n1] if startDerivativesMap else None) bx = endPointsx[n3][n1] bd1, bd2 = getMappedD1D2( [endPointsd1[n3][n1], endPointsd2[n3][n1]] + ([endPointsd3[n3][n1]] if endPointsd3 else []), endDerivativesMap[n3][n1] if endDerivativesMap else None) # sample between start and end points and derivatives # scaling end derivatives to arc length gives even curvature along the curve aMag = vector.magnitude(ad2) bMag = vector.magnitude(bd2) ad2Scaled = vector.setMagnitude( ad2, 0.5 * ((1.0 + sampleBlend) * aMag + (1.0 - sampleBlend) * bMag)) bd2Scaled = vector.setMagnitude( bd2, 0.5 * ((1.0 + sampleBlend) * bMag + (1.0 - sampleBlend) * aMag)) scaling = interp.computeCubicHermiteDerivativeScaling( ax, ad2Scaled, bx, bd2Scaled) ad2Scaled = [d * scaling for d in ad2Scaled] bd2Scaled = [d * scaling for d in bd2Scaled] derivativeMagnitudeStart = None if rescaleStartDerivatives else vector.magnitude( ad2) derivativeMagnitudeEnd = None if rescaleEndDerivatives else vector.magnitude( bd2) if tracksurface: mx, md2, md1, md3, mProportions = \ tracksurface.createHermiteCurvePoints(startProportions[n1][0], startProportions[n1][1], endProportions[n1][0], endProportions[n1][1], elementsCountRadial, derivativeStart=[d / elementsCountRadial for d in ad2Scaled], derivativeEnd=[d / elementsCountRadial for d in bd2Scaled]) mx, md2, md1 = \ tracksurface.resampleHermiteCurvePointsSmooth(mx, md2, md1, md3, mProportions, derivativeMagnitudeStart, derivativeMagnitudeEnd)[0:3] # interpolate thicknesses using xi calculated from radial arclength distances to points arcLengthInsideToRadialPoint = \ [0.0] + [interp.getCubicHermiteArcLength(mx[n2], md2[n2], mx[n2 + 1], md2[n2 + 1]) for n2 in range(elementsCountRadial)] arclengthInsideToOutside = sum(arcLengthInsideToRadialPoint) thi = [] for n2 in range(elementsCountRadial + 1): xi2 = arcLengthInsideToRadialPoint[ n2 - 1] / arclengthInsideToOutside thi.append(thicknesses[-1][n1] * xi2 + thicknesses[0][n1] * (1.0 - xi2)) thiProportion = [] for m3 in range(nodesCountWall): thiProportionRadial = [] for n2 in range(elementsCountRadial + 1): xi2 = arcLengthInsideToRadialPoint[ n2 - 1] / arclengthInsideToOutside thiProportionRadial.append( thicknessProportions[m3][-1][n1] * xi2 + thicknessProportions[m3][0][n1] * (1.0 - xi2)) thiProportion.append(thiProportionRadial) else: mx, md2, me, mxi = interp.sampleCubicHermiteCurvesSmooth( [ax, bx], [ad2Scaled, bd2Scaled], elementsCountRadial, derivativeMagnitudeStart, derivativeMagnitudeEnd)[0:4] md1 = interp.interpolateSampleLinear([ad1, bd1], me, mxi) thi = interp.interpolateSampleLinear( [thicknesses[0][n1], thicknesses[-1][n1]], me, mxi) thiProportion = [] for m3 in range(nodesCountWall): thiProportion.append( interp.interpolateSampleLinear([ thicknessProportions[m3][0][n1], thicknessProportions[m3][-1][n1] ], me, mxi)) # set scalefactors if rescaling, make same on inside for now if rescaleStartDerivatives: scaleFactor = vector.magnitude(md2[0]) / vector.magnitude(ad2) scaleFactorMapStart[n3].append(scaleFactor) if rescaleEndDerivatives: scaleFactor = vector.magnitude(md2[-1]) / vector.magnitude(bd2) scaleFactorMapEnd[n3].append(scaleFactor) for n2 in range(1, elementsCountRadial): px[n3][n2][n1] = mx[n2] pd1[n3][n2][n1] = md1[n2] pd2[n3][n2][n1] = md2[n2] thicknesses[n2][n1] = thi[n2] for m3 in range(nodesCountWall): thicknessProportions[m3][n2][n1] = thiProportion[m3][n2] xi3List = [[[[] for n1 in range(nodesCountAround)] for n2 in range(elementsCountRadial + 1)] for n3 in range(nodesCountWall)] for n1 in range(nodesCountAround): for n2 in range(elementsCountRadial + 1): xi3 = 0.0 for n3 in range(nodesCountWall): xi3 += thicknessProportions[n3][n2][n1] xi3List[n3][n2][n1] = xi3 # now get inner positions from normal and thickness, derivatives from curvature for n2 in range(1, elementsCountRadial): # first smooth derivative 1 around outer loop pd1[-1][n2] = \ interp.smoothCubicHermiteDerivativesLoop(px[-1][n2], pd1[-1][n2], magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN) for n3 in range(0, nodesCountWall - 1): for n1 in range(nodesCountAround): xi3 = 1 - xi3List[n3][n2][n1] normal = vector.normalise( vector.crossproduct3(pd1[-1][n2][n1], pd2[-1][n2][n1])) thickness = thicknesses[n2][n1] * xi3 d3 = [d * thickness for d in normal] px[n3][n2][n1] = [(px[-1][n2][n1][c] - d3[c]) for c in range(3)] # calculate inner d1 from curvature around n1m = n1 - 1 n1p = (n1 + 1) % nodesCountAround curvature = 0.5 * (interp.getCubicHermiteCurvature( px[-1][n2][n1m], pd1[-1][n2][n1m], px[-1][n2][n1], pd1[-1] [n2][n1], normal, 1.0) + interp.getCubicHermiteCurvature( px[-1][n2][n1], pd1[-1][n2][n1], px[-1][n2][n1p], pd1[-1][n2][n1p], normal, 0.0)) factor = 1.0 + curvature * thickness pd1[n3][n2][n1] = [factor * d for d in pd1[-1][n2][n1]] # calculate inner d2 from curvature radially n2m = n2 - 1 n2p = n2 + 1 curvature = 0.5 * (interp.getCubicHermiteCurvature( px[-1][n2m][n1], pd2[-1][n2m][n1], px[-1][n2][n1], pd2[-1] [n2][n1], normal, 1.0) + interp.getCubicHermiteCurvature( px[-1][n2][n1], pd2[-1][n2][n1], px[-1][n2p][n1], pd2[-1][n2p][n1], normal, 0.0)) factor = 1.0 + curvature * thickness pd2[n3][n2][n1] = [factor * d for d in pd2[-1][n2][n1]] d2Scaled = [factor * d for d in pd2[-1][n2][n1]] if vector.dotproduct(vector.normalise(pd2[-1][n2][n1]), vector.normalise(d2Scaled)) == -1: pd2[n3][n2][n1] = [-factor * d for d in pd2[-1][n2][n1]] if not midLinearXi3: pd3[n3][n2][n1] = pd3[-1][n2][n1] = \ [d * thicknesses[n2][n1] * thicknessProportions[n3 + 1][n2][n1] for d in normal] # smooth derivative 1 around inner loop pd1[n3][n2] = interp.smoothCubicHermiteDerivativesLoop( px[n3][n2], pd1[n3][n2], magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN ) for n3 in range(0, nodesCountWall): # smooth derivative 2 radially/along annulus for n1 in range(nodesCountAround): mx = [px[n3][n2][n1] for n2 in range(elementsCountRadial + 1)] md2 = [pd2[n3][n2][n1] for n2 in range(elementsCountRadial + 1)] # replace mapped start/end d2 md2[0] = getMappedD1D2( [startPointsd1[n3][n1], startPointsd2[n3][n1]] + ([startPointsd3[n3][n1]] if startPointsd3 else []), startDerivativesMap[n3][n1] if startDerivativesMap else None)[1] md2[-1] = getMappedD1D2( [endPointsd1[n3][n1], endPointsd2[n3][n1]] + ([endPointsd3[n3][n1]] if endPointsd3 else []), endDerivativesMap[n3][n1] if endDerivativesMap else None)[1] sd2 = interp.smoothCubicHermiteDerivativesLine( mx, md2, fixAllDirections=True, fixStartDerivative=not rescaleStartDerivatives, fixStartDirection=rescaleStartDerivatives, fixEndDerivative=not rescaleEndDerivatives, fixEndDirection=rescaleEndDerivatives, magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN ) if rescaleStartDerivatives: scaleFactor = vector.magnitude(sd2[0]) / vector.magnitude( md2[0]) scaleFactorMapStart[n3].append(scaleFactor) if rescaleEndDerivatives: scaleFactor = vector.magnitude(sd2[-1]) / vector.magnitude( md2[-1]) scaleFactorMapEnd[n3].append(scaleFactor) for n2 in range(1, elementsCountRadial): pd2[n3][n2][n1] = sd2[n2] ############## # Create nodes ############## nodetemplate = nodes.createNodetemplate() nodetemplate.defineField(coordinates) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) if useCrossDerivatives: nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) if useCrossDerivatives: nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) 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) if useCrossDerivatives: nodetemplateLinearS3.setValueNumberOfVersions( coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) nodeIdentifier = nextNodeIdentifier nodeId = [[] for n3 in range(nodesCountWall)] for n2 in range(elementsCountRadial + 1): for n3 in range(nodesCountWall): if (n2 == 0) and (startNodeId is not None): rowNodeId = copy.deepcopy(startNodeId[n3]) elif (n2 == elementsCountRadial) and (endNodeId is not None): rowNodeId = copy.deepcopy(endNodeId[n3]) else: rowNodeId = [] nodetemplate1 = nodetemplate if pd3[n3][ n2] else nodetemplateLinearS3 for n1 in range(nodesCountAround): node = nodes.createNode(nodeIdentifier, nodetemplate1) rowNodeId.append(nodeIdentifier) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, px[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd1[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd2[n3][n2][n1]) if pd3[n3][n2]: coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, pd3[n3][n2][n1]) nodeIdentifier = nodeIdentifier + 1 nodeId[n3].append(rowNodeId) ################# # Create elements ################# tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) bicubichermitelinear = eftfactory_bicubichermitelinear( mesh, useCrossDerivatives) elementIdentifier = nextElementIdentifier elementtemplateStandard = mesh.createElementtemplate() elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementtemplateX = mesh.createElementtemplate() elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementsCountWall = nodesCountWall - 1 for e2 in range(elementsCountRadial): nonlinearXi3 = (not rowLinearXi3[e2]) or (not rowLinearXi3[e2 + 1]) eftFactory = tricubichermite if nonlinearXi3 else bicubichermitelinear eftStandard = eftFactory.createEftBasic() elementtemplateStandard.defineField(coordinates, -1, eftStandard) mapStartDerivatives = (e2 == 0) and (startDerivativesMap or rescaleStartDerivatives) mapStartLinearDerivativeXi3 = nonlinearXi3 and rowLinearXi3[e2] mapEndDerivatives = (e2 == (elementsCountRadial - 1)) and ( endDerivativesMap or rescaleEndDerivatives) mapEndLinearDerivativeXi3 = nonlinearXi3 and rowLinearXi3[e2 + 1] mapDerivatives = mapStartDerivatives or mapStartLinearDerivativeXi3 or \ mapEndDerivatives or mapEndLinearDerivativeXi3 for e3 in range(elementsCountWall): for e1 in range(elementsCountAround): en = (e1 + 1) % elementsCountAround nids = [ nodeId[e3][e2][e1], nodeId[e3][e2][en], nodeId[e3][e2 + 1][e1], nodeId[e3][e2 + 1][en], nodeId[e3 + 1][e2][e1], nodeId[e3 + 1][e2][en], nodeId[e3 + 1][e2 + 1][e1], nodeId[e3 + 1][e2 + 1][en] ] scaleFactors = [] if mapDerivatives: eft1 = eftFactory.createEftNoCrossDerivatives() # work out if scaling by global -1 scaleMinus1 = mapStartLinearDerivativeXi3 or mapEndLinearDerivativeXi3 if (not scaleMinus1 ) and mapStartDerivatives and startDerivativesMap: for n3 in range(2): n3Idx = n3 + e3 # need to handle 3 or 4 maps (e1 uses last 3, en uses first 3) for map in startDerivativesMap[n3Idx][e1][-3:]: if map and (-1 in map): scaleMinus1 = True break for map in startDerivativesMap[n3Idx][en][:3]: if map and (-1 in map): scaleMinus1 = True break if (not scaleMinus1 ) and mapEndDerivatives and endDerivativesMap: for n3 in range(2): n3Idx = n3 + e3 # need to handle 3 or 4 maps (e1 uses last 3, en uses first 3) for map in endDerivativesMap[n3Idx][e1][-3:]: if map and (-1 in map): scaleMinus1 = True break for map in endDerivativesMap[n3Idx][en][:3]: if map and (-1 in map): scaleMinus1 = True break # make node scale factors vary fastest by local node varying across lower xi nodeScaleFactorIds = [] for n3 in range(2): n3Idx = n3 + e3 if mapStartDerivatives and rescaleStartDerivatives: for i in range(2): derivativesMap = ( startDerivativesMap[n3Idx][e1][1] if (i == 0) else startDerivativesMap[n3Idx] [en][1]) if startDerivativesMap else None nodeScaleFactorIds.append( getQuadrantID(derivativesMap if derivativesMap else (0, 1, 0))) if mapEndDerivatives and rescaleEndDerivatives: for i in range(2): derivativesMap = ( endDerivativesMap[n3Idx][e1][1] if (i == 0) else endDerivativesMap[n3Idx][en] [1]) if endDerivativesMap else None nodeScaleFactorIds.append( getQuadrantID(derivativesMap if derivativesMap else (0, 1, 0))) setEftScaleFactorIds(eft1, [1] if scaleMinus1 else [], nodeScaleFactorIds) firstNodeScaleFactorIndex = 2 if scaleMinus1 else 1 firstStartNodeScaleFactorIndex = \ firstNodeScaleFactorIndex if (mapStartDerivatives and rescaleStartDerivatives) else None firstEndNodeScaleFactorIndex = \ (firstNodeScaleFactorIndex + (2 if firstStartNodeScaleFactorIndex else 0)) \ if (mapEndDerivatives and rescaleEndDerivatives) else None layerNodeScaleFactorIndexOffset = \ 4 if (firstStartNodeScaleFactorIndex and firstEndNodeScaleFactorIndex) else 2 if scaleMinus1: scaleFactors.append(-1.0) for n3 in range(2): n3Idx = n3 + e3 if firstStartNodeScaleFactorIndex: scaleFactors.append(scaleFactorMapStart[n3Idx][e1]) scaleFactors.append(scaleFactorMapStart[n3Idx][en]) if firstEndNodeScaleFactorIndex: scaleFactors.append(scaleFactorMapEnd[n3Idx][e1]) scaleFactors.append(scaleFactorMapEnd[n3Idx][en]) if mapStartLinearDerivativeXi3: eftFactory.setEftLinearDerivative2( eft1, [1, 5, 2, 6], Node.VALUE_LABEL_D_DS3, [Node.VALUE_LABEL_D2_DS1DS3]) if mapStartDerivatives: for i in range(2): lns = [1, 5] if (i == 0) else [2, 6] for n3 in range(2): n3Idx = n3 + e3 derivativesMap = \ (startDerivativesMap[n3Idx][e1] if (i == 0) else startDerivativesMap[n3Idx][en]) \ if startDerivativesMap else (None, None, None) # handle different d1 on each side of node d1Map = \ derivativesMap[0] if ((i == 1) or (len(derivativesMap) < 4)) else derivativesMap[3] d2Map = derivativesMap[1] if derivativesMap[ 1] else (0, 1, 0) d3Map = derivativesMap[2] # use temporary to safely swap DS1 and DS2: ln = [lns[n3]] if d1Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D2_DS1DS2, [])]) if d3Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) if d2Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D_DS2, derivativeSignsToExpressionTerms( (Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3), d2Map, (firstStartNodeScaleFactorIndex + i + n3 * layerNodeScaleFactorIndexOffset) if rescaleStartDerivatives else None)) if d1Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D2_DS1DS2, derivativeSignsToExpressionTerms( (Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3), d1Map)) if d3Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D2_DS2DS3, derivativeSignsToExpressionTerms( (Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3), d3Map)) if mapEndLinearDerivativeXi3: eftFactory.setEftLinearDerivative2( eft1, [3, 7, 4, 8], Node.VALUE_LABEL_D_DS3, [Node.VALUE_LABEL_D2_DS1DS3]) if mapEndDerivatives: for i in range(2): lns = [3, 7] if (i == 0) else [4, 8] for n3 in range(2): n3Idx = n3 + e3 derivativesMap = \ (endDerivativesMap[n3Idx][e1] if (i == 0) else endDerivativesMap[n3Idx][en]) \ if endDerivativesMap else (None, None, None) # handle different d1 on each side of node d1Map = derivativesMap[0] if ((i == 1) or (len(derivativesMap) < 4)) else \ derivativesMap[3] d2Map = derivativesMap[1] if derivativesMap[ 1] else (0, 1, 0) d3Map = derivativesMap[2] # use temporary to safely swap DS1 and DS2: ln = [lns[n3]] if d1Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D2_DS1DS2, [])]) if d3Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) if d2Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D_DS2, derivativeSignsToExpressionTerms( (Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3), d2Map, (firstEndNodeScaleFactorIndex + i + n3 * layerNodeScaleFactorIndexOffset) if rescaleEndDerivatives else None)) if d1Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D2_DS1DS2, derivativeSignsToExpressionTerms( (Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3), d1Map)) if d3Map: remapEftNodeValueLabel( eft1, ln, Node.VALUE_LABEL_D2_DS2DS3, derivativeSignsToExpressionTerms( (Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3), d3Map)) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX else: eft1 = eftStandard elementtemplate1 = elementtemplateStandard element = mesh.createElement(elementIdentifier, elementtemplate1) result2 = element.setNodesByIdentifier(eft1, nids) if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) # print('create element annulus', element.isValid(), elementIdentifier, eft1.validate(), # result2, result3 if scaleFactors else None, nids) elementIdentifier += 1 if rowMeshGroups: for meshGroup in rowMeshGroups[e2]: meshGroup.addElement(element) if wallAnnotationGroups: for annotationGroup in wallAnnotationGroups[e3]: meshGroup = annotationGroup.getMeshGroup(mesh) meshGroup.addElement(element) fm.endChange() return nodeIdentifier, elementIdentifier
def generateBaseMesh(cls, region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: 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: 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): """ 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 """ bifurcationTreeScaffold = options['Bifurcation tree'] maxElementLength = options['Maximum element length'] elementsCountAroundRoot = options['Number of elements around root'] useCrossDerivatives = False fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) cache = fm.createFieldcache() ############## # Create nodes ############## bifurcationTree = bifurcationTreeScaffold.getScaffoldType( ).generateBifurcationTree( bifurcationTreeScaffold.getScaffoldSettings()) nodeIdentifier = bifurcationTree.generateZincModel(region)[0] 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) rootNode = bifurcationTree.getRootNode() child1 = rootNode.getChild(0) x1, xd1, r1, x2, xd2, r2 = child1.getChildCurve(0) rd1 = rd2 = (r2 - r1) curveLength = getCubicHermiteArcLength(x1, xd1, x2, xd2) elementsCount = max(2, math.ceil(curveLength / maxElementLength)) elementLength = curveLength / elementsCount side = [1.0, 0.0, 0.0] for i in range(elementsCount + 1): xi = i / elementsCount x, d1, d2 = get_curve_circle_points(x1, xd1, x2, xd2, r1, rd1, r2, rd2, xi, elementLength, side, elementsCountAroundRoot) for n in range(elementsCountAroundRoot): #print('node',nodeIdentifier,i,n,x[n],d1[n],d2[n]) node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x[n]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1[n]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2[n]) nodeIdentifier = nodeIdentifier + 1 ################# # Create elements ################# elementIdentifier = 1 return []
def trackVector(self, startPosition, direction, trackDistance): ''' Track from startPosition the given distance in the vector direction. Approximate, uses improved Euler method (mean of original & final gradient). :param startPosition: TrackSurfacePosition :param direction: 3-D vector (x, y, z) to track along. Projected onto surface. :param trackDistance: Distance to track along. Can be negative. :return: Final TrackSurfacePosition ''' #print('TrackSurface.trackVector start position', startPosition, 'direction', direction, 'distance', trackDistance) useDirection = direction useTrackDistance = trackDistance if trackDistance < 0.0: useDirection = [-d for d in direction] useTrackDistance = -trackDistance position = copy.deepcopy(startPosition) distance = 0.0 distanceLimit = 0.9999 * useTrackDistance max_mag_dxi = 0.02 # target/maximum magnitude of xi increment while distance < useTrackDistance: xi1 = position.xi1 xi2 = position.xi2 ax, ad1, ad2 = self.evaluateCoordinates(position, derivatives=True) adelta_xi1, adelta_xi2 = calculate_surface_delta_xi( ad1, ad2, useDirection) #print('adelta_xi', adelta_xi1, adelta_xi2) scale = max_mag_dxi / math.sqrt(adelta_xi1 * adelta_xi1 + adelta_xi2 * adelta_xi2) adxi1 = dxi1 = scale * adelta_xi1 adxi2 = dxi2 = scale * adelta_xi2 #print('adxi', adxi1, adxi2) for i in range(1): # can try more in future # can go slightly outside element to get predictor/correct position position.xi1 = xi1 + dxi1 position.xi2 = xi2 + dxi2 bx, bd1, bd2 = self.evaluateCoordinates(position, derivatives=True) bdelta_xi1, bdelta_xi2 = calculate_surface_delta_xi( bd1, bd2, useDirection) # use mean of start and end derivatives delta_xi1 = 0.5 * (adelta_xi1 + bdelta_xi1) delta_xi2 = 0.5 * (adelta_xi2 + bdelta_xi2) scale = max_mag_dxi / math.sqrt(delta_xi1 * delta_xi1 + delta_xi2 * delta_xi2) dxi1 = scale * delta_xi1 dxi2 = scale * delta_xi2 bxi1, bxi2, proportion, faceNumber = increment_xi_on_square( xi1, xi2, dxi1, dxi2) position.xi1 = bxi1 position.xi2 = bxi2 #print(distance, '-->', position) bx, bd1, bd2 = self.evaluateCoordinates(position, derivatives=True) bdelta_xi1, bdelta_xi2 = calculate_surface_delta_xi( bd1, bd2, useDirection) scale = max_mag_dxi / math.sqrt(bdelta_xi1 * bdelta_xi1 + bdelta_xi2 * bdelta_xi2) bdxi1 = scale * bdelta_xi1 bdxi2 = scale * bdelta_xi2 #print('bdxi', bdxi1, bdxi2) ad = [ proportion * (adxi1 * ad1[c] + adxi2 * ad2[c]) for c in range(3) ] bd = [ proportion * (bdxi1 * bd1[c] + bdxi2 * bd2[c]) for c in range(3) ] # GRC check: #arcLength = interp.computeCubicHermiteArcLength(ax, ad, bx, bd, rescaleDerivatives = True) arcLength = interp.getCubicHermiteArcLength(ax, ad, bx, bd) #print('scales', vector.magnitude([ (bx[c] - ax[c]) for c in range(3) ]), vector.magnitude(ad), vector.magnitude(bd), 'arc length', arcLength) if (distance + arcLength) >= distanceLimit: # limit to useTrackDistance, approximately, and finish r = proportion * (useTrackDistance - distance) / arcLength position.xi1 = xi1 + r * dxi1 position.xi2 = xi2 + r * dxi2 #print(distance, '-->', position, '(final)') break if (arcLength == 0.0) and (not faceNumber): print('TrackSurface.trackVector. No increment at', position, 'final distance', distance, 'of', useTrackDistance) break distance += arcLength if faceNumber: onBoundary = self.updatePositionTofaceNumber( position, faceNumber) if onBoundary: print('TrackSurface.trackVector: End on boundary at', position) break #print(' cross face', faceNumber, 'new position', position) return position
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: 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'] distalLength = options['Distal 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) # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves( cx, cd1, elementsCountAlongSegment * segmentCount) sd2 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf)[0] # 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) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] # Create object colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactor, innerRadiusAlongElementList, dInnerRadiusAlongElementList, tcWidthAlongElementList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroups, annotationArray, \ faceMidPointsZ = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, segmentLength, sx, sd1, sd2, elementsCountAround, elementsCountAlongSegment, nSegment, faceMidPointsZ) # Store points along length xExtrude = xExtrude + (xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:]) d1Extrude = d1Extrude + (d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:]) d2Extrude = d2Extrude + (d2WarpedList if nSegment == 0 else d2WarpedList[elementsCountAround:]) d3UnitExtrude = d3UnitExtrude + ( d3WarpedUnitList if nSegment == 0 else d3WarpedUnitList[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( ) if tcThickness > 0: tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList( ) xList, d1List, d2List, d3List, annotationGroups, annotationArray = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tubeTCWidthList, tcThickness, sx, annotationGroups, annotationArray) # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = createFlatAndTextureCoordinatesTeniaColi( xiList, relaxedLengthList, length, wallThickness, tcCount, tcThickness, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroups, annotationArray, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives) 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, annotationGroups, annotationArray, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives) return annotationGroups