def get_bifurcation_triple_point(p1x, p1d, p2x, p2d, p3x, p3d): ''' Get coordinates and derivatives of triple point between p1, p2 and p3 with derivatives. :param p1x..p3d: Point coordinates and derivatives, numbered anticlockwise around triple point. All derivatives point away from triple point. Returned d1 points from triple point to p2, d2 points from triple point to p3. :return: x, d1, d2 ''' trx1 = interpolateCubicHermite(p1x, mult(p1d, -2.0), p2x, mult(p2d, 2.0), 0.5) trx2 = interpolateCubicHermite(p2x, mult(p2d, -2.0), p3x, mult(p3d, 2.0), 0.5) trx3 = interpolateCubicHermite(p3x, mult(p3d, -2.0), p1x, mult(p1d, 2.0), 0.5) trx = [ (trx1[c] + trx2[c] + trx3[c])/3.0 for c in range(3) ] td1 = interpolateLagrangeHermiteDerivative(trx, p1x, p1d, 0.0) td2 = interpolateLagrangeHermiteDerivative(trx, p2x, p2d, 0.0) td3 = interpolateLagrangeHermiteDerivative(trx, p3x, p3d, 0.0) n12 = cross(td1, td2) n23 = cross(td2, td3) n31 = cross(td3, td1) norm = normalize([ (n12[c] + n23[c] + n31[c]) for c in range(3) ]) sd1 = smoothCubicHermiteDerivativesLine([ trx, p1x ], [ normalize(cross(norm, cross(td1, norm))), p1d ], fixStartDirection=True, fixEndDerivative=True)[0] sd2 = smoothCubicHermiteDerivativesLine([ trx, p2x ], [ normalize(cross(norm, cross(td2, norm))), p2d ], fixStartDirection=True, fixEndDerivative=True)[0] sd3 = smoothCubicHermiteDerivativesLine([ trx, p3x ], [ normalize(cross(norm, cross(td3, norm))), p3d ], fixStartDirection=True, fixEndDerivative=True)[0] trd1 = mult(sub(sd2, add(sd3, sd1)), 0.5) trd2 = mult(sub(sd3, add(sd1, sd2)), 0.5) return trx, trd1, trd2
def get_curve_circle_points(x1, xd1, x2, xd2, r1, rd1, r2, rd2, xi, dmag, side, elementsCountAround): ''' :param dmag: Magnitude of derivative on curve. :param side: Vector in side direction of first node around. Need not be unit or exactly normal to curve at xi. :return: x[], d1[] around, d2[] along ''' cx = interpolateCubicHermite(x1, xd1, x2, xd2, xi) cxd = interpolateCubicHermiteDerivative(x1, xd1, x2, xd2, xi) mag_cxd = magnitude(cxd) cxd2 = interpolateCubicHermiteSecondDerivative(x1, xd1, x2, xd2, xi) mag_cxd2 = magnitude(cxd2) r = interpolateCubicHermite([ r1 ], [ rd1 ], [ r2 ], [ rd2 ], xi)[0] rd = interpolateCubicHermiteDerivative([ r1 ], [ rd1 ], [ r2 ], [ rd2 ], xi)[0] axis1 = normalize(cxd) axis3 = normalize(cross(axis1, side)) axis2 = cross(axis3, axis1) x, d1 = createCirclePoints(cx, mult(axis2, r), mult(axis3, r), elementsCountAround) curvatureVector = mult(cxd2, 1.0/(mag_cxd*mag_cxd)) d2 = [] radialGrowth = rd/(mag_cxd*r) for e in range(elementsCountAround): radialVector = sub(x[e], cx) dmagFinal = dmag*(1.0 - dot(radialVector, curvatureVector)) # add curvature and radius change components: d2.append(add(mult(cxd, dmagFinal/mag_cxd), mult(radialVector, dmagFinal*radialGrowth))) return x, d1, d2
def interpolateNodesCubicHermite(cache, coordinates, xi, normal_scale, \ node1, derivative1, scale1, cross_derivative1, cross_scale1, \ node2, derivative2, scale2, cross_derivative2, cross_scale2): """ Interpolates position and first derivative with cubic Hermite basis. Interpolates cross derivative linearly. :param cache: Field cache to evaluate in. :param coordinates: Coordinates field. :param xi: Element coordinate to interpolate at. :param normal_scale: Magnitude of normal derivative to return. :param node1, node2: Start and end nodes. :param derivative1, derivative2: Node value label for derivatives. :param scale1, scale2: Real value scaling derivatives, to reverse if needed. :param cross_derivative1, cross_derivative2: Node value label for cross derivatives. :param cross_scale1, cross_scale2: Real value scaling cross_derivatives, to reverse if needed. :return: x, dx_ds, dx_ds_cross, dx_ds_normal """ cache.setNode(node1) result, v1 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, 3) result, d1 = coordinates.getNodeParameters(cache, -1, derivative1, 1, 3) result, d1c = coordinates.getNodeParameters(cache, -1, cross_derivative1, 1, 3) d1 = [scale1 * d for d in d1] d1c = [cross_scale1 * d for d in d1c] cache.setNode(node2) result, v2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, 3) result, d2 = coordinates.getNodeParameters(cache, -1, derivative2, 1, 3) result, d2c = coordinates.getNodeParameters(cache, -1, cross_derivative2, 1, 3) d2 = [scale2 * d for d in d2] d2c = [cross_scale2 * d for d in d2c] arcLength = interp.computeCubicHermiteArcLength(v1, d1, v2, d2, True) mag = arcLength / vector.magnitude(d1) d1 = [mag * d for d in d1] mag = arcLength / vector.magnitude(d2) d2 = [mag * d for d in d2] xr = 1.0 - xi x = interp.interpolateCubicHermite(v1, d1, v2, d2, xi) dx_ds = interp.interpolateCubicHermiteDerivative(v1, d1, v2, d2, xi) scale = min(xi, xr) dx_ds = [scale * d for d in dx_ds] dx_ds_cross = [(xr * d1c[c] + xi * d2c[c]) for c in range(3)] radialVector = vector.normalise(vector.crossproduct3(dx_ds_cross, dx_ds)) dx_ds_normal = [normal_scale * d for d in radialVector] return x, dx_ds, dx_ds_cross, dx_ds_normal
def make_tube_bifurcation_points(paCentre, pax, pad2, c1Centre, c1x, c1d2, c2Centre, c2x, c2d2): ''' Gets first ring of coordinates and derivatives between parent pa and children c1, c2, and over the crotch between c1 and c2. :return rox, rod1, rod2, cox, cod1, cod2 ''' paCount = len(pax) c1Count = len(c1x) c2Count = len(c2x) pac1Count, pac2Count, c1c2Count = get_tube_bifurcation_connection_elements_counts( paCount, c1Count, c2Count) # convert to number of nodes, includes both 6-way points pac1NodeCount = pac1Count + 1 pac2NodeCount = pac2Count + 1 c1c2NodeCount = c1c2Count + 1 paStartIndex = 0 c1StartIndex = 0 c2StartIndex = 0 pac1x = [None] * pac1NodeCount pac1d1 = [None] * pac1NodeCount pac1d2 = [None] * pac1NodeCount for n in range(pac1NodeCount): pan = (paStartIndex + n) % paCount c1n = (c1StartIndex + n) % c1Count x1, d1, x2, d2 = pax[pan], mult(pad2[pan], 2.0), c1x[c1n], mult(c1d2[c1n], 2.0) pac1x[n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5) pac1d1[n] = [0.0, 0.0, 0.0] pac1d2[n] = mult( interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5) paStartIndex2 = paStartIndex + pac1Count c1StartIndex2 = c1StartIndex + pac1Count c2StartIndex2 = c2StartIndex + c1c2Count pac2x = [None] * pac2NodeCount pac2d1 = [None] * pac2NodeCount pac2d2 = [None] * pac2NodeCount for n in range(pac2NodeCount): pan = (paStartIndex2 + n) % paCount c2n = (c2StartIndex2 + n) % c2Count x1, d1, x2, d2 = pax[pan], mult(pad2[pan], 2.0), c2x[c2n], mult(c2d2[c2n], 2.0) pac2x[n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5) pac2d1[n] = [0.0, 0.0, 0.0] pac2d2[n] = mult( interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5) c1c2x = [None] * c1c2NodeCount c1c2d1 = [None] * c1c2NodeCount c1c2d2 = [None] * c1c2NodeCount for n in range(c1c2NodeCount): c1n = (c1StartIndex2 + n) % c1Count c2n = (c2StartIndex2 - n) % c2Count # note: reversed x1, d1, x2, d2 = c2x[c2n], mult(c2d2[c2n], -2.0), c1x[c1n], mult(c1d2[c1n], 2.0) c1c2x[n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5) c1c2d1[n] = [0.0, 0.0, 0.0] c1c2d2[n] = mult( interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5) # get hex triple points hex1, hex1d1, hex1d2 = get_bifurcation_triple_point( pax[paStartIndex], mult(pad2[paStartIndex], -1.0), c1x[c1StartIndex], c1d2[c1StartIndex], c2x[c1StartIndex], c2d2[c2StartIndex]) hex2, hex2d1, hex2d2 = get_bifurcation_triple_point( pax[paStartIndex2], mult(pad2[paStartIndex2], -1.0), c2x[c2StartIndex2], c2d2[c2StartIndex2], c1x[c1StartIndex2], c1d2[c1StartIndex2]) # smooth around loops through hex points to get d1 loop1x = [hex2] + pac2x[1:-1] + [hex1] loop1d1 = [[-d for d in hex2d2]] + pac2d1[1:-1] + [hex1d1] loop2x = [hex1] + pac1x[1:-1] + [hex2] loop2d1 = [[-d for d in hex1d2]] + pac1d1[1:-1] + [hex2d1] loop1d1 = smoothCubicHermiteDerivativesLine( loop1x, loop1d1, fixStartDirection=True, fixEndDirection=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) loop2d1 = smoothCubicHermiteDerivativesLine( loop2x, loop2d1, fixStartDirection=True, fixEndDirection=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) # smooth over "crotch" between c1 and c2 crotchx = [hex2] + c1c2x[1:-1] + [hex1] crotchd1 = [add(hex2d1, hex2d2)] + c1c2d1[1:-1] + [[ (-hex1d1[c] - hex1d2[c]) for c in range(3) ]] crotchd1 = smoothCubicHermiteDerivativesLine( crotchx, crotchd1, fixStartDerivative=True, fixEndDerivative=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) rox = [hex1] + pac1x[1:-1] + [hex2] + pac2x[1:-1] rod1 = [loop1d1[-1]] + loop2d1[1:] + loop1d1[1:-1] rod2 = [[-d for d in loop2d1[0]] ] + pac1d2[1:-1] + [[-d for d in loop1d1[0]]] + pac2d2[1:-1] cox = crotchx[1:-1] cod1 = crotchd1[1:-1] cod2 = c1c2d2[1:-1] return rox, rod1, rod2, cox, cod1, cod2, paStartIndex, c1StartIndex, c2StartIndex
def generateBaseMesh(cls, region, options): """ :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: [] empty list of AnnotationGroup """ coordinateDimensions = options['Coordinate dimensions'] elementsCount1 = options['Number of elements 1'] elementsCount2 = options['Number of elements 2'] elementsCountThroughWall = options['Number of elements through wall'] elementsCountAround = 2*(elementsCount1 + elementsCount2) holeRadius = options['Hole diameter']*0.5 useCrossDerivatives = options['Use cross derivatives'] fm = region.getFieldmodule() fm.beginChange() coordinates = findOrCreateFieldCoordinates(fm, components_count=coordinateDimensions) 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) if useCrossDerivatives: nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) mesh = fm.findMeshByDimension(2) bicubicHermiteBasis = fm.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) if not useCrossDerivatives: for n in range(4): eft.setFunctionNumberOfTerms(n*4 + 4, 0) # note I'm cheating here by using element-based scale factors # i.e. not shared by neighbouring elements eftOuter1 = mesh.createElementfieldtemplate(bicubicHermiteBasis) eftOuter2 = mesh.createElementfieldtemplate(bicubicHermiteBasis) i = 0 for eftOuter in [ eftOuter1, eftOuter2 ]: i += 1 eftOuter.setNumberOfLocalScaleFactors(10) eft.setScaleFactorType(1, Elementfieldtemplate.SCALE_FACTOR_TYPE_GLOBAL_GENERAL) # GRC: allow scale factor identifier for global -1.0 to be prescribed eft.setScaleFactorIdentifier(1, 1) # Global scale factor 4.0 to subtract lateral derivative term from cross derivative to fix edges eft.setScaleFactorType(2, Elementfieldtemplate.SCALE_FACTOR_TYPE_GLOBAL_GENERAL) eft.setScaleFactorIdentifier(2, 2) nonCrossDerivativesNodes = [0, 1] if useCrossDerivatives else range(4) for n in nonCrossDerivativesNodes: eftOuter.setFunctionNumberOfTerms(n*4 + 4, 0) # nodes 1,2: general map dxi1, dsxi2 from ds1, ds2 for n in [0, 1]: ln = n + 1 sfo = (n % 2)*4 + 2 eftOuter.setFunctionNumberOfTerms(n*4 + 2, 2) eftOuter.setTermNodeParameter(n*4 + 2, 1, ln, Node.VALUE_LABEL_D_DS1, 1) eftOuter.setTermScaling(n*4 + 2, 1, [1 + sfo]) eftOuter.setTermNodeParameter(n*4 + 2, 2, ln, Node.VALUE_LABEL_D_DS2, 1) eftOuter.setTermScaling(n*4 + 2, 2, [2 + sfo]) eftOuter.setFunctionNumberOfTerms(n*4 + 3, 2) eftOuter.setTermNodeParameter(n*4 + 3, 1, ln, Node.VALUE_LABEL_D_DS1, 1) eftOuter.setTermScaling(n*4 + 3, 1, [3 + sfo]) eftOuter.setTermNodeParameter(n*4 + 3, 2, ln, Node.VALUE_LABEL_D_DS2, 1) eftOuter.setTermScaling(n*4 + 3, 2, [4 + sfo]) # map d2_dxi1dxi2 to subtract corner angle terms to fix edge continuity eftOuter.setFunctionNumberOfTerms(n*4 + 4, 1) if i == 1: eftOuter.setTermNodeParameter(n*4 + 4, 1, ln, Node.VALUE_LABEL_D_DS1, 1) if (n % 2) == 0: eftOuter.setTermScaling(n*4 + 4, 1, [1, 2, 3 + sfo]) else: eftOuter.setTermScaling(n*4 + 4, 1, [2, 3 + sfo]) else: eftOuter.setTermNodeParameter(n*4 + 4, 1, ln, Node.VALUE_LABEL_D_DS2, 1) if (n % 2) == 0: eftOuter.setTermScaling(n*4 + 4, 1, [1, 2, 4 + sfo]) else: eftOuter.setTermScaling(n*4 + 4, 1, [2, 4 + sfo]) elementtemplate = mesh.createElementtemplate() elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE) result = elementtemplate.defineField(coordinates, -1, eft) elementtemplateOuter1 = mesh.createElementtemplate() elementtemplateOuter1.setElementShapeType(Element.SHAPE_TYPE_SQUARE) result = elementtemplateOuter1.defineField(coordinates, -1, eftOuter1) elementtemplateOuter2 = mesh.createElementtemplate() elementtemplateOuter2.setElementShapeType(Element.SHAPE_TYPE_SQUARE) result = elementtemplateOuter2.defineField(coordinates, -1, eftOuter2) cache = fm.createFieldcache() # create nodes radiansPerElementAround = 2.0*math.pi/elementsCountAround wallThicknessMin = (0.5 - holeRadius) wallThicknessMax = math.sqrt(0.5) - holeRadius wallThicknessPerElement = wallThicknessMin/elementsCountThroughWall radius = holeRadius inner_x = [] inner_d1 = [] inner_d2 = [] startRadians = math.pi*(-0.5 - elementsCount1/elementsCountAround) for n1 in range(elementsCountAround): radiansAround = startRadians + n1*radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) inner_x.append((radius*cosRadiansAround, radius*sinRadiansAround)) inner_d1.append((radiansPerElementAround*radius*-sinRadiansAround, radiansPerElementAround*radius*cosRadiansAround)) #inner_d2.append((wallThicknessPerElement*cosRadiansAround, wallThicknessPerElement*sinRadiansAround)) inner_d2.append((wallThicknessMin*cosRadiansAround, wallThicknessMin*sinRadiansAround)) outer_x = [] outer_d1 = [] outer_d2 = [] mag = math.sqrt(elementsCount1*elementsCount1 + elementsCount2*elementsCount2) outer_dx1_ds1 = 1.0 / elementsCount1 outer_dx2_ds2 = 1.0 / elementsCount2 #cornerScale1 = 1.0 / max(elementsCount1 + 1, elementsCount2 + 1) #cornerScale1 = 1.0 / min(2, max(elementsCount1, elementsCount2)) cornerScale1 = 1.0 / max(elementsCount1 + elementsCountThroughWall, elementsCount2 + elementsCountThroughWall) sqrt05 = math.sqrt(0.5) wallThicknessMax = sqrt05 - holeRadius for n in range(elementsCount1): x = -0.5 + n/elementsCount1 outer_x.append((x, -0.5)) if n == 0: rx = x/sqrt05 ry = -0.5/sqrt05 scale2 = wallThicknessMax outer_d1.append((-ry*cornerScale1, rx*cornerScale1)) outer_d2.append((rx*scale2, ry*scale2)) else: scale2 = wallThicknessMin outer_d1.append((outer_dx1_ds1, 0.0)) outer_d2.append((0.0, -scale2)) for n in range(elementsCount2): y = -0.5 + n/elementsCount2 outer_x.append((0.5, y)) if n == 0: rx = 0.5/sqrt05 ry = y/sqrt05 scale2 = wallThicknessMax outer_d1.append((-ry*cornerScale1, rx*cornerScale1)) outer_d2.append((rx*scale2, ry*scale2)) else: scale2 = wallThicknessMin outer_d1.append((0.0, outer_dx2_ds2)) outer_d2.append((scale2, 0.0)) for n in range(elementsCount1): x = 0.5 - n/elementsCount1 outer_x.append((x, 0.5)) if n == 0: rx = x/sqrt05 ry = 0.5/sqrt05 scale2 = wallThicknessMax outer_d1.append((-ry*cornerScale1, rx*cornerScale1)) outer_d2.append((rx*scale2, ry*scale2)) else: scale2 = wallThicknessMin outer_d1.append((-outer_dx1_ds1, 0.0)) outer_d2.append((0.0, scale2)) for n in range(elementsCount2): y = 0.5 - n/elementsCount2 outer_x.append((-0.5, y)) if n == 0: rx = -0.5/sqrt05 ry = y/sqrt05 scale2 = wallThicknessMax outer_d1.append((-ry*cornerScale1, rx*cornerScale1)) outer_d2.append((rx*scale2, ry*scale2)) else: scale2 = wallThicknessMin outer_d1.append((0.0, -outer_dx2_ds2)) outer_d2.append((-scale2, 0.0)) nodeIdentifier = 1 x = [ 0.0, 0.0, 0.0 ] dx_ds1 = [ 0.0, 0.0, 0.0 ] dx_ds2 = [ 0.0, 0.0, 0.0 ] outer_dx_ds1 = [ 1.0 / elementsCount1, 0.0, 0.0 ] outer_dx_ds2 = [ 0.0, 1.0 / elementsCount2, 0.0 ] zero = [ 0.0, 0.0, 0.0 ] # outer nodes for n1 in range(elementsCountAround): x[0] = outer_x[n1][0] x[1] = outer_x[n1][1] 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, outer_dx_ds1) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, outer_dx_ds2) if useCrossDerivatives: coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) nodeIdentifier = nodeIdentifier + 1 # inner nodes for n2 in range(elementsCountThroughWall): xir = (n2 + 1)/elementsCountThroughWall xi = 1.0 - xir for n1 in range(elementsCountAround): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) v = interpolateCubicHermite(inner_x[n1], inner_d2[n1], outer_x[n1], outer_d2[n1], xi) x[0] = v[0] x[1] = v[1] dx_ds1[0] = xir*inner_d1[n1][0] + xi*outer_d1[n1][0] dx_ds1[1] = xir*inner_d1[n1][1] + xi*outer_d1[n1][1] d2 = interpolateCubicHermiteDerivative(inner_x[n1], inner_d2[n1], outer_x[n1], outer_d2[n1], xi) dx_ds2[0] = -d2[0]/elementsCountThroughWall dx_ds2[1] = -d2[1]/elementsCountThroughWall 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) if useCrossDerivatives: coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) nodeIdentifier = nodeIdentifier + 1 # create elements elementIdentifier = 1 # first row general maps ds1, ds2 to dxi1, dxi2 for e1 in range(elementsCountAround): en = (e1 + 1)%elementsCountAround onX = (e1 % (elementsCount1 + elementsCount2)) < elementsCount1 elementtemplateOuter = elementtemplateOuter1 if onX else elementtemplateOuter2 eftOuter = eftOuter1 if onX else eftOuter2 element = mesh.createElement(elementIdentifier, elementtemplateOuter) bni11 = e1 + 1 bni12 = en + 1 bni21 = elementsCountAround + e1 + 1 bni22 = elementsCountAround + en + 1 nodeIdentifiers = [ bni11, bni12, bni21, bni22 ] result = element.setNodesByIdentifier(eftOuter, nodeIdentifiers) rev = e1 >= (elementsCount1 + elementsCount2) one = -1.0 if rev else 1.0 vx = one if onX else 0.0 vy = 0.0 if onX else one scaleFactors = [ -1.0, 4.0, vx, vy, -outer_d2[e1][0]/outer_dx_ds1[0]/elementsCountThroughWall, -outer_d2[e1][1]/outer_dx_ds2[1]/elementsCountThroughWall, vx, vy, -outer_d2[en][0]/outer_dx_ds1[0]/elementsCountThroughWall, -outer_d2[en][1]/outer_dx_ds2[1]/elementsCountThroughWall ] element.setScaleFactors(eftOuter, scaleFactors) elementIdentifier = elementIdentifier + 1 # remaining rows for e2 in range(1, elementsCountThroughWall): for e1 in range(elementsCountAround): element = mesh.createElement(elementIdentifier, elementtemplate) bni11 = e2*elementsCountAround + e1 + 1 bni12 = e2*elementsCountAround + (e1 + 1)%elementsCountAround + 1 bni21 = (e2 + 1)*elementsCountAround + e1 + 1 bni22 = (e2 + 1)*elementsCountAround + (e1 + 1)%elementsCountAround + 1 nodeIdentifiers = [ bni11, bni12, bni21, bni22 ] result = element.setNodesByIdentifier(eft, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 fm.endChange() return []
def getCylindricalSegmentInnerPoints(elementsCountAround, elementsCountAlongSegment, segmentLength, wallThickness, startRadius, startRadiusDerivative, endRadius, endRadiusDerivative, startPhase): """ Generates a 3-D cylindrical segment mesh with variable numbers of elements around, along the central path, and through wall. :param elementsCountAround: Number of elements around. :param elementsCountAlongSegment: Number of elements along cylindrical segment. :param segmentLength: Length of a cylindrical segment. :param wallThickness: Thickness of wall. :param startRadius: Inner radius at proximal end. :param startRadiusDerivative: Rate of change of inner radius at proximal end. :param endRadius: Inner radius at distal end. :param endRadiusDerivative: Rate of change of inner radius at distal end. :param startPhase: Phase at start. :return coordinates, derivatives on inner surface of a cylindrical segment. :return transitElementList: stores true if element around is an element that transits between a big and small element. :return xiList: List of xi for each node around. xi refers to node position along the width when cylindrical segment is opened into a flat preparation, nominally in [0.0, 1.0]. :return flatWidthList: List of width around elements for each element along cylindrical segment when the segment is opened into a flat preparation. :return segmentAxis: Axis of segment. :return sRadiusAlongSegment: radius of each element along segment. """ transitElementList = [0] * elementsCountAround # create nodes segmentAxis = [0.0, 0.0, 1.0] xFinal = [] d1Final = [] d2Final = [] xiList = [] flatWidthList = [] sRadiusAlongSegment = [] for n2 in range(elementsCountAlongSegment + 1): phase = startPhase + n2 * 360.0 / elementsCountAlongSegment xi = (phase if phase <= 360.0 else phase - 360.0) / 360.0 radius = interp.interpolateCubicHermite([startRadius], [startRadiusDerivative], [endRadius], [endRadiusDerivative], xi)[0] sRadiusAlongSegment.append(radius) z = segmentLength / elementsCountAlongSegment * n2 + startPhase / 360.0 * segmentLength xLoop, d1Loop = createCirclePoints([0.0, 0.0, z], [radius, 0.0, 0.0], [0.0, radius, 0.0], elementsCountAround, startRadians=0.0) xFinal = xFinal + xLoop d1Final = d1Final + d1Loop # Smooth d2 for segment smoothd2Raw = [] for n1 in range(elementsCountAround): nx = [] nd2 = [] for n2 in range(elementsCountAlongSegment + 1): n = n2 * elementsCountAround + n1 nx.append(xFinal[n]) nd2.append(segmentAxis) smoothd2 = interp.smoothCubicHermiteDerivativesLine(nx, nd2) smoothd2Raw.append(smoothd2) # Re-arrange smoothd2 for n2 in range(elementsCountAlongSegment + 1): radius = sRadiusAlongSegment[n2] flatWidth = 2.0 * math.pi * (radius + wallThickness) flatWidthList.append(flatWidth) xiFace = [] for n1 in range(elementsCountAround): d2Final.append(smoothd2Raw[n1][n2]) for n1 in range(elementsCountAround + 1): xi = 1.0 / elementsCountAround * n1 xiFace.append(xi) xiList.append(xiFace) return xFinal, d1Final, d2Final, transitElementList, xiList, flatWidthList, segmentAxis, sRadiusAlongSegment
def getCoordinatesFromInner(xInner, d1Inner, d2Inner, d3Inner, wallThicknessList, relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList): """ Generates coordinates from inner to outer surface using coordinates and derivatives of inner surface. :param xInner: Coordinates on inner surface :param d1Inner: Derivatives on inner surface around tube :param d2Inner: Derivatives on inner surface along tube :param d3Inner: Derivatives on inner surface through wall :param wallThicknessList: Wall thickness for each element along tube :param relativeThicknessList: Relative wall thickness for each element through wall :param elementsCountAround: Number of elements around tube :param elementsCountAlong: Number of elements along tube :param elementsCountThroughWall: Number of elements through tube wall :param transitElementList: stores true if element around is a transition element that is between a big and a small element. return nodes and derivatives for mesh, and curvature along inner surface. """ xOuter = [] curvatureAroundInner = [] curvatureAlong = [] curvatureList = [] xList = [] d1List = [] d2List = [] d3List = [] if relativeThicknessList: xi3 = 0.0 xi3List = [0.0] for n3 in range(elementsCountThroughWall): xi3 += relativeThicknessList[n3] xi3List.append(xi3) relativeThicknessList.append(relativeThicknessList[-1]) for n2 in range(elementsCountAlong + 1): wallThickness = wallThicknessList[n2] for n1 in range(elementsCountAround): n = n2 * elementsCountAround + n1 norm = d3Inner[n] # Calculate outer coordinates x = [xInner[n][i] + norm[i] * wallThickness for i in range(3)] xOuter.append(x) # Calculate curvature along elements around prevIdx = n - 1 if ( n1 != 0) else (n2 + 1) * elementsCountAround - 1 nextIdx = n + 1 if ( n1 < elementsCountAround - 1) else n2 * elementsCountAround kappam = interp.getCubicHermiteCurvatureSimple( xInner[prevIdx], d1Inner[prevIdx], xInner[n], d1Inner[n], 1.0) kappap = interp.getCubicHermiteCurvatureSimple( xInner[n], d1Inner[n], xInner[nextIdx], d1Inner[nextIdx], 0.0) if not transitElementList[n1] and not transitElementList[ (n1 - 1) % elementsCountAround]: curvatureAround = 0.5 * (kappam + kappap) elif transitElementList[n1]: curvatureAround = kappam elif transitElementList[(n1 - 1) % elementsCountAround]: curvatureAround = kappap curvatureAroundInner.append(curvatureAround) # Calculate curvature along if n2 == 0: curvature = interp.getCubicHermiteCurvature( xInner[n], d2Inner[n], xInner[n + elementsCountAround], d2Inner[n + elementsCountAround], vector.normalise(d3Inner[n]), 0.0) elif n2 == elementsCountAlong: curvature = interp.getCubicHermiteCurvature( xInner[n - elementsCountAround], d2Inner[n - elementsCountAround], xInner[n], d2Inner[n], vector.normalise(d3Inner[n]), 1.0) else: curvature = 0.5 * (interp.getCubicHermiteCurvature( xInner[n - elementsCountAround], d2Inner[n - elementsCountAround], xInner[n], d2Inner[n], vector.normalise(d3Inner[n]), 1.0) + interp.getCubicHermiteCurvature( xInner[n], d2Inner[n], xInner[n + elementsCountAround], d2Inner[n + elementsCountAround], vector.normalise(d3Inner[n]), 0.0)) curvatureAlong.append(curvature) for n3 in range(elementsCountThroughWall + 1): xi3 = xi3List[ n3] if relativeThicknessList else 1.0 / elementsCountThroughWall * n3 for n1 in range(elementsCountAround): n = n2 * elementsCountAround + n1 norm = d3Inner[n] innerx = xInner[n] outerx = xOuter[n] dWall = [wallThickness * c for c in norm] # x x = interp.interpolateCubicHermite(innerx, dWall, outerx, dWall, xi3) xList.append(x) # dx_ds1 factor = 1.0 + wallThickness * xi3 * curvatureAroundInner[n] d1 = [factor * c for c in d1Inner[n]] d1List.append(d1) # dx_ds2 curvature = curvatureAlong[n] distance = vector.magnitude( [x[i] - xInner[n][i] for i in range(3)]) factor = 1.0 - curvature * distance d2 = [factor * c for c in d2Inner[n]] d2List.append(d2) curvatureList.append(curvature) #dx_ds3 d3 = [ c * wallThickness * (relativeThicknessList[n3] if relativeThicknessList else 1.0 / elementsCountThroughWall) for c in norm ] d3List.append(d3) return xList, d1List, d2List, d3List, curvatureList
def getPlaneProjectionOnCentralPath(x, elementsCountAround, elementsCountAlong, segmentLength, sx, sd1, sd2, sd12): """ Projects reference point used for warping onto the central path and find coordinates and derivatives at projected location. :param x: coordinates of nodes. :param elementsCountAround: number of elements around. :param elementsCountAlong: number of elements along. :param segmentLength: Length of segment. :param sx: coordinates of equally spaced points on central path. :param sd1: tangent of equally spaced points on central path. :param sd2: derivative representing cross axis at equally spaced points on central path. :param sd12: rate of change of cross axis at equally spaced points on central path. :return: coordinates and derivatives on project points and z-coordinates of reference points. """ # Use first node in each group of elements along as reference for warping later zRefList = [] for n2 in range(elementsCountAlong + 1): zFirstNodeAlong = x[n2 * elementsCountAround][2] zRefList.append(zFirstNodeAlong) # Find sx, sd1, sd2 at projection of reference points on central path lengthElementAlong = segmentLength / elementsCountAlong # Append values from first node on central path sxRefList = [] sd1RefList = [] sd2RefList = [] sxRefList.append(sx[0]) sd1RefList.append(sd1[0]) sd2RefList.append(sd2[0]) # Interpolate the ones in between for n2 in range(1, elementsCountAlong): ei = int(zRefList[n2] // lengthElementAlong + 1) xi = (zRefList[n2] - lengthElementAlong * (ei - 1)) / lengthElementAlong sxRef = interp.interpolateCubicHermite(sx[ei - 1], sd1[ei - 1], sx[ei], sd1[ei], xi) sd1Ref = interp.interpolateCubicHermiteDerivative( sx[ei - 1], sd1[ei - 1], sx[ei], sd1[ei], xi) sd2Ref = interp.interpolateCubicHermite(sd2[ei - 1], sd12[ei - 1], sd2[ei], sd12[ei], xi) sxRefList.append(sxRef) sd1RefList.append(sd1Ref) sd2RefList.append(sd2Ref) # Append values from last node on central path sxRefList.append(sx[-1]) sd1RefList.append(sd1[-1]) sd2RefList.append(sd2[-1]) # Project sd2 to plane orthogonal to sd1 sd2ProjectedListRef = [] for n in range(len(sd2RefList)): sd1Normalised = vector.normalise(sd1RefList[n]) dp = vector.dotproduct(sd2RefList[n], sd1Normalised) dpScaled = [dp * c for c in sd1Normalised] sd2Projected = vector.normalise( [sd2RefList[n][c] - dpScaled[c] for c in range(3)]) sd2ProjectedListRef.append(sd2Projected) return sxRefList, sd1RefList, sd2ProjectedListRef, zRefList
def generateBaseMesh(cls, region, options): """ Generate the base tricubic Hermite mesh. :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: [] empty list of AnnotationGroup """ elementsCountAround = options['Number of elements around'] elementsCountUp = options['Number of elements up'] elementsCountRadial = options['Number of elements radial'] useCrossDerivatives = options['Use cross derivatives'] radius = 0.5 * options['Diameter'] fm = region.getFieldmodule() fm.beginChange() coordinates = findOrCreateFieldCoordinates(fm) 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) nodetemplateApex.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 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) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) 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) else: nodetemplate = nodetemplateApex cache = fm.createFieldcache() ################# # Create nodes ################# nodeIdentifier = 1 radiansPerElementAround = 2.0 * math.pi / elementsCountAround radiansPerElementUp = math.pi / elementsCountUp x = [0.0, 0.0, 0.0] dx_ds1 = [0.0, 0.0, 0.0] dx_ds2 = [0.0, 0.0, 0.0] dx_ds3 = [0.0, 0.0, 0.0] zero = [0.0, 0.0, 0.0] cubicArcLengthList = [0.0] * (elementsCountUp + 1) # Pre-calculate cubicArcLength along elementsCountUp for n2 in range(1, elementsCountUp + 1): radiansUp = n2 * radiansPerElementUp cosRadiansUp = math.cos(radiansUp) sinRadiansUp = math.sin(radiansUp) # Calculate cubic hermite arclength linking point on axis to surface on sphere v1 = [0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp] d1 = [0.0, 1.0, 0.0] v2 = [ radius * math.cos(math.pi / 2.0) * sinRadiansUp, radius * math.sin(math.pi / 2.0) * sinRadiansUp, -radius * cosRadiansUp ] d2 = [ math.cos(math.pi / 2.0) * sinRadiansUp, math.sin(math.pi / 2.0) * sinRadiansUp, -cosRadiansUp ] cubicArcLengthList[n2] = interp.computeCubicHermiteArcLength( v1, d1, v2, d2, True) # Create node for bottom pole node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, [0.0, 0.0, -radius]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [radius * radiansPerElementUp, 0.0, 0.0]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, radius * radiansPerElementUp, 0.0]) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, -radius * 2.0 / elementsCountUp]) if useCrossDerivatives: coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nodeIdentifier = nodeIdentifier + 1 # Create nodes along axis between top and bottom poles for n2 in range(1, elementsCountUp): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_VALUE, 1, [0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp]) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS1, 1, [cubicArcLengthList[n2] / elementsCountRadial, 0.0, 0.0]) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, radius * 2.0 / elementsCountUp]) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, cubicArcLengthList[n2] / elementsCountRadial, 0.0]) if useCrossDerivatives: coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nodeIdentifier = nodeIdentifier + 1 # Create nodes for top pole node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, [0.0, 0.0, radius]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [radius * radiansPerElementUp, 0.0, 0.0]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, radius * radiansPerElementUp, 0.0]) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, radius * 2.0 / elementsCountUp]) if useCrossDerivatives: coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nodeIdentifier = nodeIdentifier + 1 # Create other nodes for n3 in range(1, elementsCountRadial + 1): xi = 1 / elementsCountRadial * n3 radiansUpArcOriginList = [0.0] * (elementsCountUp) # Pre-calculate RC for points on vertical arc running between top and bottom poles pt = [0.0, radius * xi, 0.0] arcOrigin = (radius * radius - pt[2] * pt[2] - pt[1] * pt[1]) / (-2.0 * pt[1]) RC = math.sqrt(arcOrigin * arcOrigin + radius * radius) radiansUpArcOriginList[0] = math.acos(-radius / RC) # Identify nodes on the vertical arc using radiansAround = pi/2 for n2 in range(1, elementsCountUp): radiansUp = n2 * radiansPerElementUp cosRadiansUp = math.cos(radiansUp) sinRadiansUp = math.sin(radiansUp) # Calculate node coordinates on arc using cubic hermite interpolation cubicArcLength = cubicArcLengthList[n2] v1 = [0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp] d1 = [math.cos(math.pi / 2.0), math.sin(math.pi / 2.0), 0.0] d1 = vector.normalise(d1) d1 = [d * cubicArcLength for d in d1] v2 = [ radius * math.cos(math.pi / 2.0) * sinRadiansUp, radius * math.sin(math.pi / 2.0) * sinRadiansUp, -radius * cosRadiansUp ] d2 = [ math.cos(math.pi / 2.0) * sinRadiansUp, math.sin(math.pi / 2.0) * sinRadiansUp, -cosRadiansUp ] d2 = vector.normalise(d2) d2 = [d * cubicArcLength for d in d2] x = interp.interpolateCubicHermite(v1, d1, v2, d2, xi) # Calculate radiansUp for each point wrt arcOrigin radiansUpArcOriginList[n2] = math.acos(x[2] / RC) for n2 in range(1, elementsCountUp): radiansUp = n2 * radiansPerElementUp cosRadiansUp = math.cos(radiansUp) sinRadiansUp = math.sin(radiansUp) for n1 in range(elementsCountAround): radiansAround = n1 * radiansPerElementAround cosRadiansAround = math.cos(radiansAround) sinRadiansAround = math.sin(radiansAround) cubicArcLength = cubicArcLengthList[n2] # Calculate node coordinates on arc using cubic hermite interpolation v1 = [ 0.0, 0.0, -radius + n2 * 2.0 * radius / elementsCountUp ] d1 = [cosRadiansAround, sinRadiansAround, 0.0] d1 = vector.normalise(d1) d1 = [d * cubicArcLength for d in d1] v2 = [ radius * cosRadiansAround * sinRadiansUp, radius * sinRadiansAround * sinRadiansUp, -radius * cosRadiansUp ] d2 = [ cosRadiansAround * sinRadiansUp, sinRadiansAround * sinRadiansUp, -cosRadiansUp ] d2 = vector.normalise(d2) d2 = [d * cubicArcLength for d in d2] x = interp.interpolateCubicHermite(v1, d1, v2, d2, xi) # For dx_ds1 - Calculate radius wrt origin where interpolated points lie on orthoRadius = vector.magnitude(x) orthoRadiansUp = math.pi - math.acos(x[2] / orthoRadius) sinOrthoRadiansUp = math.sin(orthoRadiansUp) cosOrthoRadiansUp = math.cos(orthoRadiansUp) # For dx_ds2 - Assign radiansUp from radiansUpArcOriginList and calculate diff between radiansUp as we move up radiansUpArcOrigin = radiansUpArcOriginList[n2] sinRadiansUpArcOrigin = math.sin(radiansUpArcOrigin) cosRadiansUpArcOrigin = math.cos(radiansUpArcOrigin) radiansPerElementUpArcOrigin = radiansUpArcOriginList[ n2] - radiansUpArcOriginList[n2 - 1] dx_ds1 = [ orthoRadius * -sinRadiansAround * sinOrthoRadiansUp * radiansPerElementAround, orthoRadius * cosRadiansAround * sinOrthoRadiansUp * radiansPerElementAround, 0.0 ] dx_ds2 = [ RC * cosRadiansAround * cosRadiansUpArcOrigin * radiansPerElementUpArcOrigin, RC * sinRadiansAround * cosRadiansUpArcOrigin * radiansPerElementUpArcOrigin, -RC * sinRadiansUpArcOrigin * radiansPerElementUpArcOrigin ] dx_ds3 = interp.interpolateCubicHermiteDerivative( v1, d1, v2, d2, xi) dx_ds3 = vector.normalise(dx_ds3) dx_ds3 = [ d * cubicArcLength / elementsCountRadial for d in dx_ds3 ] 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) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, dx_ds3) if useCrossDerivatives: coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) coordinates.setNodeParameters( cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nodeIdentifier = nodeIdentifier + 1 ################# # Create elements ################# mesh = fm.findMeshByDimension(3) tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) eft = tricubichermite.createEftBasic() tricubicHermiteBasis = fm.createElementbasis( 3, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) # Regular elements elementtemplate = mesh.createElementtemplate() elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementtemplate.defineField(coordinates, -1, eft) # Bottom tetrahedon elements elementtemplate1 = mesh.createElementtemplate() elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) # Axial elements elementtemplate2 = mesh.createElementtemplate() elementtemplate2.setElementShapeType(Element.SHAPE_TYPE_CUBE) # Top tetrahedron elements elementtemplate3 = mesh.createElementtemplate() elementtemplate3.setElementShapeType(Element.SHAPE_TYPE_CUBE) # Bottom pyramid elements elementtemplate4 = mesh.createElementtemplate() elementtemplate4.setElementShapeType(Element.SHAPE_TYPE_CUBE) # Top pyramid elements elementtemplate5 = mesh.createElementtemplate() elementtemplate5.setElementShapeType(Element.SHAPE_TYPE_CUBE) elementIdentifier = 1 no2 = elementsCountAround no3 = elementsCountAround * (elementsCountUp - 1) rni = (1 + elementsCountUp) - no3 - no2 + 1 # regular node identifier radiansPerElementAround = 2.0 * math.pi / elementsCountAround for e3 in range(elementsCountRadial): # Create elements on bottom pole radiansIncline = math.pi * 0.5 * e3 / elementsCountRadial radiansInclineNext = math.pi * 0.5 * (e3 + 1) / elementsCountRadial if e3 == 0: # Create tetrahedron elements on the bottom pole bni1 = elementsCountUp + 2 for e1 in range(elementsCountAround): va = e1 vb = (e1 + 1) % elementsCountAround eft1 = tricubichermite.createEftTetrahedronBottom( va * 100, vb * 100, 10000) elementtemplate1.defineField(coordinates, -1, eft1) element = mesh.createElement(elementIdentifier, elementtemplate1) nodeIdentifiers = [1, 2, bni1 + va, bni1 + vb] result1 = element.setNodesByIdentifier( eft1, nodeIdentifiers) # set general linear map coefficients radiansAround = va * radiansPerElementAround radiansAroundNext = vb * radiansPerElementAround scalefactors = [ -1.0, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround, math.cos(radiansIncline), math.sin(radiansIncline), math.cos(radiansInclineNext), math.sin(radiansInclineNext) ] result2 = element.setScaleFactors(eft1, scalefactors) # print('Tetrahedron Bottom element', elementIdentifier, result1, result2, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 else: # Create pyramid elements on the bottom pole bni4 = elementsCountUp + 1 + (e3 - 1) * no3 + 1 for e1 in range(elementsCountAround): va = e1 vb = (e1 + 1) % elementsCountAround eft4 = tricubichermite.createEftPyramidBottom( va * 100, vb * 100, 100000 + e3 * 2) elementtemplate4.defineField(coordinates, -1, eft4) element = mesh.createElement(elementIdentifier, elementtemplate4) nodeIdentifiers = [ 1, bni4 + va, bni4 + vb, bni4 + no3 + va, bni4 + no3 + vb ] result1 = element.setNodesByIdentifier( eft4, nodeIdentifiers) # set general linear map coefficients radiansAround = va * radiansPerElementAround radiansAroundNext = vb * radiansPerElementAround scalefactors = [ -1.0, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround, math.cos(radiansIncline), math.sin(radiansIncline), math.cos(radiansInclineNext), math.sin(radiansInclineNext) ] result2 = element.setScaleFactors(eft4, scalefactors) # print('pyramid bottom element', elementIdentifier, result1, result2, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 # create regular radial elements for e2 in range(1, elementsCountUp - 1): if e3 == 0: for e1 in range(elementsCountAround): # create central radial elements: 6 node wedges va = e1 vb = (e1 + 1) % elementsCountAround eft2 = tricubichermite.createEftWedgeRadial( va * 100, vb * 100) elementtemplate2.defineField(coordinates, -1, eft2) element = mesh.createElement(elementIdentifier, elementtemplate2) bni2 = elementsCountUp + 1 + (e2 - 1) * no2 + 1 nodeIdentifiers = [ e3 + e2 + 1, e3 + e2 + 2, bni2 + va, bni2 + vb, bni2 + va + elementsCountAround, bni2 + vb + elementsCountAround ] result1 = element.setNodesByIdentifier( eft2, nodeIdentifiers) # set general linear map coefficients radiansAround = va * radiansPerElementAround radiansAroundNext = vb * radiansPerElementAround scalefactors = [ -1.0, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround ] result2 = element.setScaleFactors(eft2, scalefactors) # print('axis element', elementIdentifier, result1, result2, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 else: # Regular elements bni = rni + e3 * no3 + e2 * no2 for e1 in range(elementsCountAround): element = mesh.createElement(elementIdentifier, elementtemplate) na = e1 nb = (e1 + 1) % elementsCountAround nodeIdentifiers = [ bni + na, bni + nb, bni + no2 + na, bni + no2 + nb, bni + no3 + na, bni + no3 + nb, bni + no3 + no2 + na, bni + no3 + no2 + nb ] result = element.setNodesByIdentifier( eft, nodeIdentifiers) # print('regular element', elementIdentifier, result, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 # Create elements on top pole radiansIncline = math.pi * 0.5 * e3 / elementsCountRadial radiansInclineNext = math.pi * 0.5 * (e3 + 1) / elementsCountRadial if e3 == 0: # # Create tetrahedron elements on the top pole bni3 = elementsCountUp + 1 + (elementsCountUp - 2) * no2 + 1 for e1 in range(elementsCountAround): va = e1 vb = (e1 + 1) % elementsCountAround eft3 = tricubichermite.createEftTetrahedronTop( va * 100, vb * 100, 100000) elementtemplate3.defineField(coordinates, -1, eft3) element = mesh.createElement(elementIdentifier, elementtemplate3) nodeIdentifiers = [ elementsCountUp, elementsCountUp + 1, bni3 + va, bni3 + vb ] result1 = element.setNodesByIdentifier( eft3, nodeIdentifiers) # set general linear map coefficients radiansAround = va * radiansPerElementAround radiansAroundNext = vb * radiansPerElementAround scalefactors = [ -1.0, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround, math.cos(radiansIncline), math.sin(radiansIncline), math.cos(radiansInclineNext), math.sin(radiansInclineNext) ] result2 = element.setScaleFactors(eft3, scalefactors) # print('Tetrahedron top element', elementIdentifier, result1, result2, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 else: # Create pyramid elements on the top pole bni5 = elementsCountUp + 1 + (e3 - 1) * no3 + ( elementsCountUp - 2) * no2 + 1 for e1 in range(elementsCountAround): va = e1 vb = (e1 + 1) % elementsCountAround eft5 = tricubichermite.createEftPyramidTop( va * 100, vb * 100, 100000 + e3 * 2) elementtemplate5.defineField(coordinates, -1, eft5) element = mesh.createElement(elementIdentifier, elementtemplate5) nodeIdentifiers = [ bni5 + va, bni5 + vb, elementsCountUp + 1, bni5 + no3 + va, bni5 + no3 + vb ] result1 = element.setNodesByIdentifier( eft5, nodeIdentifiers) # set general linear map coefficients radiansAround = va * radiansPerElementAround radiansAroundNext = vb * radiansPerElementAround scalefactors = [ -1.0, math.cos(radiansAround), math.sin(radiansAround), radiansPerElementAround, math.cos(radiansAroundNext), math.sin(radiansAroundNext), radiansPerElementAround, math.cos(radiansIncline), math.sin(radiansIncline), math.cos(radiansInclineNext), math.sin(radiansInclineNext) ] result2 = element.setScaleFactors(eft5, scalefactors) # print('pyramid top element', elementIdentifier, result1, result2, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 fm.endChange() return []