From c55b30f787d48d71d1a7310dee470ede2d9f6df9 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 5 Jul 2023 16:53:09 +1200 Subject: [PATCH 01/30] Update derivatives at apex and Richard's suggestions --- .../meshtypes/meshtype_3d_stomach1.py | 647 +++++++++--------- src/scaffoldmaker/utils/interpolation.py | 10 +- src/scaffoldmaker/utils/tracksurface.py | 53 ++ 3 files changed, 401 insertions(+), 309 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 900c2394..7235bb7a 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -9,6 +9,7 @@ import copy import math +from cmlibs.maths.vectorops import cross, sub from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates from cmlibs.utils.zinc.finiteelement import get_element_node_identifiers, getMaximumNodeIdentifier from cmlibs.utils.zinc.general import ChangeManager @@ -338,53 +339,58 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 7 + 'Number of elements': 12 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 2.000, 0.000, 0.000 ], [ -0.600, 0.000, 0.000 ], [ 0.000, -0.500, 0.000 ], [ 0.000, 0.000, 0.000 ], [ 0.000, 0.000, 0.500 ], [ 0.000, 0.000, 0.000]]), - (2, [[ 1.500, 0.000, 0.000 ], [ -0.400, 0.000, 0.000 ], [ 0.000, -0.500, 0.000 ], [ 0.000, 0.000, 0.000 ], [ 0.000, 0.000, 0.500 ], [ 0.000, 0.000, 0.000]]), - (3, [[ 1.200, 0.000, 0.000 ], [ -0.250, 0.000, 0.000 ], [ 0.000, -0.500, 0.000 ], [ 0.000, 0.000, 0.000 ], [ 0.000, 0.000, 0.500 ], [ 0.000, 0.000, 0.000]]), - (4, [[ 1.000, 0.000, 0.000 ], [ -0.300, 0.000, 0.000 ], [ 0.000, -0.500, 0.000 ], [ 0.000, 0.000, 0.000 ], [ 0.000, 0.000, 0.500 ], [ 0.000, 0.000, 0.000]]), - (5, [[ 0.600, 0.000, 0.000 ], [ -0.300, 0.000, 0.000 ], [ 0.000, -0.500, 0.000 ], [ 0.000, 0.067, 0.000 ], [ 0.000, 0.000, 0.500 ], [ 0.000, 0.000, -0.067]]), - (6, [[ 0.400, 0.000, 0.000 ], [ -0.200, 0.000, 0.000 ], [ 0.000, -0.400, 0.000 ], [ 0.000, 0.150, 0.000 ], [ 0.000, 0.000, 0.400 ], [ 0.000, 0.000, -0.150]]), - (7, [[ 0.200, 0.000, 0.000 ], [ -0.200, 0.000, 0.000 ], [ 0.000, -0.200, 0.000 ], [ 0.000, 0.100, 0.000 ], [ 0.000, 0.000, 0.200 ], [ 0.000, 0.000, -0.100]]), - (8, [[ 0.000, 0.000, 0.000 ], [ -0.200, 0.000, 0.000 ], [ 0.000, -0.200, 0.000 ], [ 0.000, -0.100, 0.000 ], [ 0.000, 0.000, 0.200 ], [ 0.000, 0.000, 0.100]]) - ]), + (1, [[2.00,0.00,0.00], [-0.02,-0.00,-0.00], [0.00,-0.05,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.05], [0.00,0.00,0.10]]), + (2, [[1.98,0.00,0.00], [-0.06,0.00,0.00], [0.00,-0.16,0.00], [0.00,-0.11,0.00], [0.00,0.00,0.16], [0.00,0.00,0.11]]), + (3, [[1.88,0.00,0.00], [-0.12,0.00,0.00], [0.00,-0.29,0.00], [0.00,-0.12,0.00], [0.00,0.00,0.29], [0.00,0.00,0.12]]), + (4, [[1.75,0.00,0.00], [-0.15,0.00,0.00], [0.00,-0.40,0.00], [0.00,-0.09,0.00], [0.00,0.00,0.40], [0.00,0.00,0.09]]), + (5, [[1.58,0.00,0.00], [-0.18,0.00,0.00], [0.00,-0.47,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.47], [0.00,0.00,0.05]]), + (6, [[1.40,0.00,0.00], [-0.19,0.00,0.00], [0.00,-0.50,0.00], [0.00,-0.02,0.00], [0.00,0.00,0.50], [0.00,0.00,0.02]]), + (7, [[1.20,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,-0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), + (8, [[1.00,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.00]]), + (9, [[0.80,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.00]]), + (10, [[0.60,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.07,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.07]]), + (11, [[0.40,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.40,0.00], [0.00,0.15,0.00], [0.00,0.00,0.40], [0.00,0.00,-0.15]]), + (12, [[0.20,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.10,0.00], [0.00,0.00,0.20], [0.00,0.00,-0.10]]), + (13, [[0.00,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.20,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.20], [0.00,0.00,0.10]]) + ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-2', + 'identifierRanges': '1-6', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '3-4', + 'identifierRanges': '7-9', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '5', + 'identifierRanges': '10', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6', + 'identifierRanges': '11', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7', + 'identifierRanges': '12', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] @@ -812,6 +818,7 @@ def generateBaseMesh(cls, region, options): coordinates = findOrCreateFieldCoordinates(fm) geometricCentralPath = StomachCentralPath(region, geometricCentralPath, stomachTermsAlong) + geometricCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path.exf") elementCountGroupList = [] allAnnotationGroups, elementCountGroupList, nextNodeIdentifier, nextElementIdentifier = \ @@ -830,6 +837,7 @@ def generateBaseMesh(cls, region, options): tmp_stomach_coordinates = findOrCreateFieldCoordinates(tmp_fm, name="stomach coordinates") materialCentralPath = StomachCentralPath(tmp_region, materialCentralPath, stomachTermsAlong) + materialCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path_material.exf") allAnnotationGroupsMaterial, elementCountGroupList, nextNodeIdentifier, nextElementIdentifier = \ createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, @@ -1169,7 +1177,7 @@ class StomachCentralPath: """ def __init__(self, region, centralPath, stomachTermsAlong=[None]): """ - :param region: Zinc region to define model in. + :param region: Zinc region needed to create path region to define path in. :param centralPath: Central path subscaffold from meshtype_1d_path1 :param stomachTermsAlong: Annotation terms along length of stomach """ @@ -1182,9 +1190,9 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): cd12Groups = [] cd13Groups = [] - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - tmpFieldmodule = tmpRegion.getFieldmodule() + self._path_region = region.createRegion() + centralPath.generate(self._path_region) + tmpFieldmodule = self._path_region.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') @@ -1216,7 +1224,6 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): del tmpCoordinates del tmpNodes del tmpFieldmodule - del tmpRegion self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong self.cxGroups = cxGroups @@ -1409,9 +1416,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio arcLengthRatioForGroupsFromFundusApex = [] arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong stomachCentralPathLength = arcLengthOfGroupsAlong[0] - xApex = centralPath.cxGroups[0][0] - d1Apex = centralPath.cd2Groups[0][0] - d2Apex = centralPath.cd3Groups[0][0] + # xApex = centralPath.cxGroups[0][0] + # d1Apex = centralPath.cd2Groups[0][0] + # d2Apex = centralPath.cd3Groups[0][0] for i in range(1, len(stomachTermsAlong)): arcLengthRatio = arcLengthOfGroupsAlong[i] / stomachCentralPathLength @@ -1476,8 +1483,16 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio cd1Sections = [] cd2Sections = [] cd3Sections = [] - - for i in range(1, len(elementCountGroupList)): # start from body + # +/- deltas to get d2 along by finite difference + deltaXi = 1.0E-5 + cxPlusSections = [] + cxMinusSections = [] + cd2PlusSections = [] + cd2MinusSections = [] + cd3PlusSections = [] + cd3MinusSections = [] + + for i in (list(range(1, len(elementCountGroupList))) + [0]): # start from body, go back to fundus cxGroup = centralPath.cxGroups[i + 1] cd1Group = centralPath.cd1Groups[i + 1] cd2Group = centralPath.cd2Groups[i + 1] @@ -1490,260 +1505,263 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio cd12Group[n] = zero cd13Group[n] = zero - # Break body into equal sized elements - if i == 1: # body - cxSection, cd1Section, pe, pxi, psf = \ - interp.sampleCubicHermiteCurves(cxGroup, cd1Group, elementCountGroupList[1], - arcLengthDerivatives=True) - cd2Section = interp.interpolateSampleCubicHermite(cd2Group, cd12Group, pe, pxi, psf)[0] - cd3Section = interp.interpolateSampleCubicHermite(cd3Group, cd13Group, pe, pxi, psf)[0] - - for n in range(len(cxSection)): - px, pd1 = sampleEllipsePoints(cxSection[n], cd2Section[n], cd3Section[n], 0.0, math.pi * 2.0, - elementsCountAroundDuod) - del px[-1], pd1[-1] - - if n == 0: - pxFundusEndQuarter = px[elementsAroundQuarterDuod] - d2FundusEndQuarter = cd1Section[0] - pxFundusEndGC = px[0] - if n == 1: - d2FundusEndGC = findDerivativeBetweenPoints(pxFundusEndGC, px[0]) - - cxSections.append(cxSection) - cd1Sections.append(cd1Section) - cd2Sections.append(cd2Section) - cd3Sections.append(cd3Section) - - else: - elementsOutSection = elementCountGroupList[i] - if elementsOutSection > 1: - cxSection, cd1Section, pe, pxi, psf = \ - interp.sampleCubicHermiteCurvesSmooth(cxGroup, cd1Group, elementsOutSection) - cd2Section = interp.interpolateSampleCubicHermite(cd2Group, cd12Group, pe, pxi, psf)[0] - cd3Section = interp.interpolateSampleCubicHermite(cd3Group, cd13Group, pe, pxi, psf)[0] - - else: - cxSection = cxGroup - arcLength = interp.getCubicHermiteArcLength(cxGroup[0], cd1Group[0], - cxGroup[1], cd1Group[1]) - d1BoundaryStart = cd1Sections[-1][-1] - d1BoundaryEnd = vector.setMagnitude(cd1Group[-1], - 2*arcLength - vector.magnitude(cd1Sections[-1][-1])) - cd1Section = [d1BoundaryStart, d1BoundaryEnd] - cd2Section = cd2Group - cd3Section = cd3Group - - cxSections.append(cxSection) - cd1Sections.append(cd1Section) - cd2Sections.append(cd2Section) - cd3Sections.append(cd3Section) - - # Create straight tube joined to ellipsoid for fundus - lengthOfFundusAlongCP = centralPath.arcLengthOfGroupsAlong[1] - ellipsoidHeight = (1 - fundusStraightFactor) * lengthOfFundusAlongCP - - elementsAlong = 10 - xQuarterFundus = [] - xGCFundus = [] - xLine = [] - dLine = [] - d2Line = [] - - # Sample ellipsoid part of central path into elementsAlong - cxFundus = centralPath.cxGroups[1] - cd1Fundus = centralPath.cd1Groups[1] - cd2Fundus = centralPath.cd2Groups[1] - cd3Fundus = centralPath.cd3Groups[1] - cd12Fundus = centralPath.cd12Groups[1] - cd13Fundus = centralPath.cd13Groups[1] - - sxFundus, sd1Fundus, pe, pxi, psf = interp.sampleCubicHermiteCurves(cxFundus, cd1Fundus, elementsAlong) - sd2Fundus, sd12Fundus = interp.interpolateSampleCubicHermite(cd2Fundus, cd12Fundus, pe, pxi, psf) - sd3Fundus, sd13Fundus = interp.interpolateSampleCubicHermite(cd3Fundus, cd13Fundus, pe, pxi, psf) - - xEllipsoidEnd, d1EllipsoidEnd, elementEllipsoidEnd, xi = \ - interp.getCubicHermiteCurvesPointAtArcDistance(sxFundus, sd1Fundus, ellipsoidHeight) - d2EllipsoidEnd, d12EllipsoidEnd = interp.getCubicHermiteCurvesPointAtArcDistance(sd2Fundus, sd12Fundus, - ellipsoidHeight)[0:2] - d3EllipsoidEnd, d13EllipsoidEnd = interp.getCubicHermiteCurvesPointAtArcDistance(sd3Fundus, sd13Fundus, - ellipsoidHeight)[0:2] - - ellipsoidMajorDiameter = vector.magnitude(d2EllipsoidEnd) - ellipsoidMinorDiameter = vector.magnitude(d3EllipsoidEnd) - - # resample just ellipsoidal part - sxFundusEllipsoid, sd1FundusEllipsoid, pe, pxi, psf = \ - interp.sampleCubicHermiteCurves(sxFundus[:elementEllipsoidEnd + 1] + [xEllipsoidEnd], - sd1Fundus[:elementEllipsoidEnd + 1] + [d1EllipsoidEnd], - elementsAlong, arcLengthDerivatives=True) - - sd2FundusEllipsoid, sd12FundusEllipsoid = \ - interp.interpolateSampleCubicHermite(sd2Fundus[:elementEllipsoidEnd + 1] + [d2EllipsoidEnd], - sd12Fundus[:elementEllipsoidEnd + 1] + [d12EllipsoidEnd], pe, pxi, psf) - - # Create template fundus with path of fundus length for transformation - xAroundAll = [] - for n2 in range(elementsAlong + 1): - xLine.append([-ellipsoidHeight/elementsAlong * n2, 0.0, 0.0]) - dLine.append([-ellipsoidHeight/elementsAlong, 0.0, 0.0]) - d2Line.append([0.0, -10.0, 0.0]) - theta = math.acos((-ellipsoidHeight/elementsAlong * n2 + ellipsoidHeight)/ellipsoidHeight) - xAround = [] - - for n1 in range(elementsCountAroundDuod): - psi = math.pi * 2.0 / elementsCountAroundDuod * n1 - x = [ellipsoidHeight * math.cos(theta) - ellipsoidHeight, - -ellipsoidMajorDiameter * math.sin(theta) * math.cos(psi), - ellipsoidMinorDiameter * math.sin(theta) * math.sin(psi)] - xAround.append(x) - xAroundAll.append(xAround) - - # Transform ellipse ring to align with central path - xAroundAllTransformed = [] - for n2 in range(elementsAlong + 1): - xAroundTransformed = [] - unitTangent = vector.normalise(sd1FundusEllipsoid[n2]) - unitVectorLine = vector.normalise(dLine[n2]) - cp = vector.crossproduct3(unitVectorLine, unitTangent) - dp = vector.dotproduct(dLine[n2], sd1FundusEllipsoid[n2]) - centroid = xLine[n2] - d2 = d2Line[n2] - - if vector.magnitude(cp) > 0.0: # path tangent not parallel to segment axis - axisRot = vector.normalise(cp) - thetaRot = math.acos(dp / (vector.magnitude(dLine[n2]) * vector.magnitude(sd1FundusEllipsoid[n2]))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(axisRot, thetaRot) - centroidRot = [rotFrame[j][0]*centroid[0] + rotFrame[j][1]*centroid[1] + - rotFrame[j][2]*centroid[2] for j in range(3)] - - else: # path tangent parallel to unitVectorLine (x-axis) - if dp == -1.0: # path tangent opposite direction to unitVectorLine - thetaRot = math.pi - axisRot = [1.0, 0, 0] - rotFrame = matrix.getRotationMatrixFromAxisAngle(axisRot, thetaRot) - centroidRot = [rotFrame[j][0] * centroid[0] + rotFrame[j][1] * centroid[1] + - rotFrame[j][2] * centroid[2] for j in range(3)] - - else: # unitVectorLine in same direction as unit tangent - rotFrame = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - centroidRot = centroid - - translateMatrix = [sxFundusEllipsoid[n2][j] - centroidRot[j] for j in range(3)] - - for n1 in range(len(xAroundAll[n2])): - x = xAroundAll[n2][n1] - if vector.magnitude(cp) > 0.0: # path tangent not parallel to segment axis - xRot1 = [rotFrame[j][0] * x[0] + rotFrame[j][1] * x[1] + rotFrame[j][2] * x[2] for j in range(3)] - else: # path tangent parallel to segment axis - xRot1 = [rotFrame[j][0] * x[0] + rotFrame[j][1] * x[1] + rotFrame[j][2] * x[2] for j in - range(3)] if dp == -1.0 else x - - # Check that the first node in each ellipse is aligned to sd2 - if n1 == 0: - vectorToFirstNode = [xRot1[c] - centroidRot[c] for c in range(3)] - if vector.magnitude(vectorToFirstNode) > 0.0: - cp = vector.crossproduct3(vector.normalise(vectorToFirstNode), - vector.normalise(sd2FundusEllipsoid[n2])) - if vector.magnitude(cp) > 1e-7: - cp = vector.normalise(cp) - signThetaRot2 = vector.dotproduct(unitTangent, cp) - thetaRot2 = math.acos( - vector.dotproduct(vector.normalise(vectorToFirstNode), vector.normalise(sd2FundusEllipsoid[n2]))) - axisRot2 = unitTangent - rotFrame2 = matrix.getRotationMatrixFromAxisAngle(axisRot2, signThetaRot2 * thetaRot2) - else: - rotFrame2 = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - else: - rotFrame2 = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - - xRot2 = [rotFrame2[j][0] * xRot1[0] + rotFrame2[j][1] * xRot1[1] + rotFrame2[j][2] * xRot1[2] for j in - range(3)] - xAroundTransformed.append([xRot2[j] + translateMatrix[j] for j in range(3)]) - xAroundAllTransformed.append(xAroundTransformed) - - for n in range(elementEllipsoidEnd + 1, len(sxFundus) - 1): - x = sampleEllipsePoints(sxFundus[n], sd2Fundus[n], sd3Fundus[n], 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] - del x[-1] - - xAroundAllTransformed.append(x) - - for n2 in range(elementsAlong): - xGCFundus.append(xAroundAllTransformed[n2][0]) - xQuarterFundus.append(xAroundAllTransformed[n2][elementsAroundQuarterDuod]) - xQuarterFundus.append(pxFundusEndQuarter) - xGCFundus.append(pxFundusEndGC) - - # Find derivative and sample fundus - # Quarter - d2FundusQuarter = [d2Apex] - for n in range(1, len(xQuarterFundus) - 1): - d2FundusQuarter.append(findDerivativeBetweenPoints(xQuarterFundus[n], xQuarterFundus[n + 1])) - d2FundusQuarter.append(d2FundusEndQuarter) - - xFundusQuarterSampled, d2FundusQuarterSampled = \ - interp.sampleCubicHermiteCurvesSmooth(xQuarterFundus, d2FundusQuarter, elementCountGroupList[0], - derivativeMagnitudeEnd=vector.magnitude(d2FundusEndQuarter))[0:2] - - # GC - d2FundusGC = [d1Apex] - for n in range(1, len(xGCFundus) - 1): - d2FundusGC.append(findDerivativeBetweenPoints(xGCFundus[n], xGCFundus[n + 1])) - d2FundusGC.append(d2FundusEndGC) - - xFundusGCSampled, d2FundusGCSampled = \ - interp.sampleCubicHermiteCurvesSmooth(xGCFundus, d2FundusGC, elementCountGroupList[0], - derivativeMagnitudeStart=vector.magnitude(d2FundusQuarterSampled[0]), - derivativeMagnitudeEnd=vector.magnitude(d2FundusEndGC))[0:2] - - for n2 in range(elementsAlong): - xGCFundus.append(xAroundAllTransformed[n2][0]) - xQuarterFundus.append(xAroundAllTransformed[n2][elementsAroundQuarterDuod]) - xQuarterFundus.append(pxFundusEndQuarter) - xGCFundus.append(pxFundusEndGC) - - cxFundus = [xApex] - cd1Fundus = [] - cd2Fundus = [d1Apex] - cd3Fundus = [d2Apex] - - for n2 in range(1, len(xFundusQuarterSampled)): # skip apex - xProjectionQuarter = findCentreOnCentralPathFromCrossAxisEndPt(xFundusQuarterSampled[n2], sxFundus, sd1Fundus) - xProjectionGC = findCentreOnCentralPathFromCrossAxisEndPt(xFundusGCSampled[n2], sxFundus, sd1Fundus) - xProjectionAve = [0.5 * xProjectionQuarter[c] + 0.5 * xProjectionGC[c] for c in range(3)] - - cxFundus.append(xProjectionAve) - d1 = findDerivativeBetweenPoints(cxFundus[n2 - 1], cxFundus[n2]) - d2 = findDerivativeBetweenPoints(xProjectionGC, xFundusGCSampled[n2]) - d3 = findDerivativeBetweenPoints(xProjectionQuarter, xFundusQuarterSampled[n2]) - cd3DV = vector.normalise(vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) - d3 = vector.setMagnitude(cd3DV, vector.magnitude(d3)) - - cd1Fundus.append(d1) - cd2Fundus.append(d2) - cd3Fundus.append(d3) - cd1Fundus.append(cd1Fundus[-1]) - - # Merge fundus with other groups on central path - cxSections = [cxFundus] + cxSections - cd1Sections = [cd1Fundus] + cd1Sections - cd2Sections = [cd2Fundus] + cd2Sections - cd3Sections = [cd3Fundus] + cd3Sections + # Break body into equal sized elements, all others vary smoothly from end derivative of last section + # Except for fundus which start at zero derivative and ends at start derivative for body + elementsOutSection = elementCountGroupList[i] + cxSection, cd1Section, pe, pxi, psf = interp.sampleCubicHermiteCurvesSmooth( + cxGroup, cd1Group, elementsOutSection, + derivativeMagnitudeStart=None if (i == 1) else 0.0 if (i == 0) else vector.magnitude(cd1Sections[-1][-1]), + derivativeMagnitudeEnd=None if (i != 0) else vector.magnitude(cd1Sections[0][0])) + cd2Section = interp.interpolateSampleCubicHermite(cd2Group, cd12Group, pe, pxi, psf)[0] + cd3Section = interp.interpolateSampleCubicHermite(cd3Group, cd13Group, pe, pxi, psf)[0] + pxiPlus = [xi + deltaXi for xi in pxi] + cxPlusSection = interp.interpolateSampleCubicHermite(cxGroup, cd1Group, pe, pxiPlus, psf)[0] + cd2PlusSection = interp.interpolateSampleCubicHermite(cd2Group, cd12Group, pe, pxiPlus, psf)[0] + cd3PlusSection = interp.interpolateSampleCubicHermite(cd3Group, cd13Group, pe, pxiPlus, psf)[0] + pxiMinus = [xi - deltaXi for xi in pxi] + cxMinusSection = interp.interpolateSampleCubicHermite(cxGroup, cd1Group, pe, pxiMinus, psf)[0] + cd2MinusSection = interp.interpolateSampleCubicHermite(cd2Group, cd12Group, pe, pxiMinus, psf)[0] + cd3MinusSection = interp.interpolateSampleCubicHermite(cd3Group, cd13Group, pe, pxiMinus, psf)[0] + + cxSections.append(cxSection) + cd1Sections.append(cd1Section) + cd2Sections.append(cd2Section) + cd3Sections.append(cd3Section) + cxPlusSections.append(cxPlusSection) + cd2PlusSections.append(cd2PlusSection) + cd3PlusSections.append(cd3PlusSection) + cxMinusSections.append(cxMinusSection) + cd2MinusSections.append(cd2MinusSection) + cd3MinusSections.append(cd3MinusSection) + + # if i == 1: # body: calculate end of fundus stuff + # for n in range(len(cxSection)): + # px, pd1 = sampleEllipsePoints(cxSection[n], cd2Section[n], cd3Section[n], 0.0, math.pi * 2.0, + # elementsCountAroundDuod) + # del px[-1], pd1[-1] + # + # if n == 0: + # pxFundusEndQuarter = px[elementsAroundQuarterDuod] + # d2FundusEndQuarter = cd1Section[0] + # pxFundusEndGC = px[0] + # if n == 1: + # d2FundusEndGC = findDerivativeBetweenPoints(pxFundusEndGC, px[0]) + + # put fundus section first + for values in [cxSections, cd1Sections, cd2Sections, cd3Sections, + cxPlusSections, cd2PlusSections, cd3PlusSections, + cxMinusSections, cd2MinusSections, cd3MinusSections]: + values.insert(0, values.pop()) + + # # Create straight tube joined to ellipsoid for fundus + # lengthOfFundusAlongCP = centralPath.arcLengthOfGroupsAlong[1] + # ellipsoidHeight = (1 - fundusStraightFactor) * lengthOfFundusAlongCP + # + # elementsAlong = 10 + # xQuarterFundus = [] + # xGCFundus = [] + # xLine = [] + # dLine = [] + # d2Line = [] + # + # # Sample ellipsoid part of central path into elementsAlong + # cxFundus = centralPath.cxGroups[1] + # cd1Fundus = centralPath.cd1Groups[1] + # cd2Fundus = centralPath.cd2Groups[1] + # cd3Fundus = centralPath.cd3Groups[1] + # cd12Fundus = centralPath.cd12Groups[1] + # cd13Fundus = centralPath.cd13Groups[1] + # + # sxFundus, sd1Fundus, pe, pxi, psf = interp.sampleCubicHermiteCurves(cxFundus, cd1Fundus, elementsAlong) + # sd2Fundus, sd12Fundus = interp.interpolateSampleCubicHermite(cd2Fundus, cd12Fundus, pe, pxi, psf) + # sd3Fundus, sd13Fundus = interp.interpolateSampleCubicHermite(cd3Fundus, cd13Fundus, pe, pxi, psf) + # + # xEllipsoidEnd, d1EllipsoidEnd, elementEllipsoidEnd, xi = \ + # interp.getCubicHermiteCurvesPointAtArcDistance(sxFundus, sd1Fundus, ellipsoidHeight) + # d2EllipsoidEnd, d12EllipsoidEnd = interp.getCubicHermiteCurvesPointAtArcDistance(sd2Fundus, sd12Fundus, + # ellipsoidHeight)[0:2] + # d3EllipsoidEnd, d13EllipsoidEnd = interp.getCubicHermiteCurvesPointAtArcDistance(sd3Fundus, sd13Fundus, + # ellipsoidHeight)[0:2] + # + # ellipsoidMajorDiameter = vector.magnitude(d2EllipsoidEnd) + # ellipsoidMinorDiameter = vector.magnitude(d3EllipsoidEnd) + # + # # resample just ellipsoidal part + # sxFundusEllipsoid, sd1FundusEllipsoid, pe, pxi, psf = \ + # interp.sampleCubicHermiteCurves(sxFundus[:elementEllipsoidEnd + 1] + [xEllipsoidEnd], + # sd1Fundus[:elementEllipsoidEnd + 1] + [d1EllipsoidEnd], + # elementsAlong, arcLengthDerivatives=True) + # + # sd2FundusEllipsoid, sd12FundusEllipsoid = \ + # interp.interpolateSampleCubicHermite(sd2Fundus[:elementEllipsoidEnd + 1] + [d2EllipsoidEnd], + # sd12Fundus[:elementEllipsoidEnd + 1] + [d12EllipsoidEnd], pe, pxi, psf) + # + # # Create template fundus with path of fundus length for transformation + # xAroundAll = [] + # for n2 in range(elementsAlong + 1): + # xLine.append([-ellipsoidHeight/elementsAlong * n2, 0.0, 0.0]) + # dLine.append([-ellipsoidHeight/elementsAlong, 0.0, 0.0]) + # d2Line.append([0.0, -10.0, 0.0]) + # theta = math.acos((-ellipsoidHeight/elementsAlong * n2 + ellipsoidHeight)/ellipsoidHeight) + # xAround = [] + # + # for n1 in range(elementsCountAroundDuod): + # psi = math.pi * 2.0 / elementsCountAroundDuod * n1 + # x = [ellipsoidHeight * math.cos(theta) - ellipsoidHeight, + # -ellipsoidMajorDiameter * math.sin(theta) * math.cos(psi), + # ellipsoidMinorDiameter * math.sin(theta) * math.sin(psi)] + # xAround.append(x) + # xAroundAll.append(xAround) + # + # # Transform ellipse ring to align with central path + # xAroundAllTransformed = [] + # for n2 in range(elementsAlong + 1): + # xAroundTransformed = [] + # unitTangent = vector.normalise(sd1FundusEllipsoid[n2]) + # unitVectorLine = vector.normalise(dLine[n2]) + # cp = vector.crossproduct3(unitVectorLine, unitTangent) + # dp = vector.dotproduct(dLine[n2], sd1FundusEllipsoid[n2]) + # centroid = xLine[n2] + # d2 = d2Line[n2] + # + # if vector.magnitude(cp) > 0.0: # path tangent not parallel to segment axis + # axisRot = vector.normalise(cp) + # thetaRot = math.acos(dp / (vector.magnitude(dLine[n2]) * vector.magnitude(sd1FundusEllipsoid[n2]))) + # rotFrame = matrix.getRotationMatrixFromAxisAngle(axisRot, thetaRot) + # centroidRot = [rotFrame[j][0]*centroid[0] + rotFrame[j][1]*centroid[1] + + # rotFrame[j][2]*centroid[2] for j in range(3)] + # + # else: # path tangent parallel to unitVectorLine (x-axis) + # if dp == -1.0: # path tangent opposite direction to unitVectorLine + # thetaRot = math.pi + # axisRot = [1.0, 0, 0] + # rotFrame = matrix.getRotationMatrixFromAxisAngle(axisRot, thetaRot) + # centroidRot = [rotFrame[j][0] * centroid[0] + rotFrame[j][1] * centroid[1] + + # rotFrame[j][2] * centroid[2] for j in range(3)] + # + # else: # unitVectorLine in same direction as unit tangent + # rotFrame = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + # centroidRot = centroid + # + # translateMatrix = [sxFundusEllipsoid[n2][j] - centroidRot[j] for j in range(3)] + # + # for n1 in range(len(xAroundAll[n2])): + # x = xAroundAll[n2][n1] + # if vector.magnitude(cp) > 0.0: # path tangent not parallel to segment axis + # xRot1 = [rotFrame[j][0] * x[0] + rotFrame[j][1] * x[1] + rotFrame[j][2] * x[2] for j in range(3)] + # else: # path tangent parallel to segment axis + # xRot1 = [rotFrame[j][0] * x[0] + rotFrame[j][1] * x[1] + rotFrame[j][2] * x[2] for j in + # range(3)] if dp == -1.0 else x + # + # # Check that the first node in each ellipse is aligned to sd2 + # if n1 == 0: + # vectorToFirstNode = [xRot1[c] - centroidRot[c] for c in range(3)] + # if vector.magnitude(vectorToFirstNode) > 0.0: + # cp = vector.crossproduct3(vector.normalise(vectorToFirstNode), + # vector.normalise(sd2FundusEllipsoid[n2])) + # if vector.magnitude(cp) > 1e-7: + # cp = vector.normalise(cp) + # signThetaRot2 = vector.dotproduct(unitTangent, cp) + # thetaRot2 = math.acos( + # vector.dotproduct(vector.normalise(vectorToFirstNode), vector.normalise(sd2FundusEllipsoid[n2]))) + # axisRot2 = unitTangent + # rotFrame2 = matrix.getRotationMatrixFromAxisAngle(axisRot2, signThetaRot2 * thetaRot2) + # else: + # rotFrame2 = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + # else: + # rotFrame2 = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + # + # xRot2 = [rotFrame2[j][0] * xRot1[0] + rotFrame2[j][1] * xRot1[1] + rotFrame2[j][2] * xRot1[2] for j in + # range(3)] + # xAroundTransformed.append([xRot2[j] + translateMatrix[j] for j in range(3)]) + # xAroundAllTransformed.append(xAroundTransformed) + # + # for n in range(elementEllipsoidEnd + 1, len(sxFundus) - 1): + # x = sampleEllipsePoints(sxFundus[n], sd2Fundus[n], sd3Fundus[n], 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] + # del x[-1] + # + # xAroundAllTransformed.append(x) + # + # for n2 in range(elementsAlong): + # xGCFundus.append(xAroundAllTransformed[n2][0]) + # xQuarterFundus.append(xAroundAllTransformed[n2][elementsAroundQuarterDuod]) + # xQuarterFundus.append(pxFundusEndQuarter) + # xGCFundus.append(pxFundusEndGC) + # + # # Find derivative and sample fundus + # # Quarter + # d2FundusQuarter = [d2Apex] + # for n in range(1, len(xQuarterFundus) - 1): + # d2FundusQuarter.append(findDerivativeBetweenPoints(xQuarterFundus[n], xQuarterFundus[n + 1])) + # d2FundusQuarter.append(d2FundusEndQuarter) + # + # xFundusQuarterSampled, d2FundusQuarterSampled = \ + # interp.sampleCubicHermiteCurvesSmooth(xQuarterFundus, d2FundusQuarter, elementCountGroupList[0], + # derivativeMagnitudeEnd=vector.magnitude(d2FundusEndQuarter))[0:2] + # + # # GC + # d2FundusGC = [d1Apex] + # for n in range(1, len(xGCFundus) - 1): + # d2FundusGC.append(findDerivativeBetweenPoints(xGCFundus[n], xGCFundus[n + 1])) + # d2FundusGC.append(d2FundusEndGC) + # + # xFundusGCSampled, d2FundusGCSampled = \ + # interp.sampleCubicHermiteCurvesSmooth(xGCFundus, d2FundusGC, elementCountGroupList[0], + # derivativeMagnitudeStart=vector.magnitude(d2FundusQuarterSampled[0]), + # derivativeMagnitudeEnd=vector.magnitude(d2FundusEndGC))[0:2] + # + # for n2 in range(elementsAlong): + # xGCFundus.append(xAroundAllTransformed[n2][0]) + # xQuarterFundus.append(xAroundAllTransformed[n2][elementsAroundQuarterDuod]) + # xQuarterFundus.append(pxFundusEndQuarter) + # xGCFundus.append(pxFundusEndGC) + # + # cxFundus = [xApex] + # cd1Fundus = [] + # cd2Fundus = [d1Apex] + # cd3Fundus = [d2Apex] + # + # for n2 in range(1, len(xFundusQuarterSampled)): # skip apex + # xProjectionQuarter = findCentreOnCentralPathFromCrossAxisEndPt(xFundusQuarterSampled[n2], sxFundus, sd1Fundus) + # xProjectionGC = findCentreOnCentralPathFromCrossAxisEndPt(xFundusGCSampled[n2], sxFundus, sd1Fundus) + # xProjectionAve = [0.5 * xProjectionQuarter[c] + 0.5 * xProjectionGC[c] for c in range(3)] + # + # cxFundus.append(xProjectionAve) + # d1 = findDerivativeBetweenPoints(cxFundus[n2 - 1], cxFundus[n2]) + # d2 = findDerivativeBetweenPoints(xProjectionGC, xFundusGCSampled[n2]) + # d3 = findDerivativeBetweenPoints(xProjectionQuarter, xFundusQuarterSampled[n2]) + # cd3DV = vector.normalise(vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) + # d3 = vector.setMagnitude(cd3DV, vector.magnitude(d3)) + # + # cd1Fundus.append(d1) + # cd2Fundus.append(d2) + # cd3Fundus.append(d3) + # cd1Fundus.append(cd1Fundus[-1]) + + # # Merge fundus with other groups on central path + # cxSections = [cxFundus] + cxSections + # cd1Sections = [cd1Fundus] + cd1Sections + # cd2Sections = [cd2Fundus] + cd2Sections + # cd3Sections = [cd3Fundus] + cd3Sections # Create ellipses - xApex = [cxSections[0][0] for n1 in range(elementsCountAroundDuod)] - d2ApexAround = [zero for n1 in range(elementsCountAroundDuod)] + cxApex = cxSections[0][0] + xApex = [cxApex for n1 in range(elementsCountAroundDuod)] + d1ApexAround = [] - d2Apex = cd2Sections[0][1] - d1Apex = cd3Sections[0][1] - rotAxisApex = vector.crossproduct3(vector.normalise(d1Apex), vector.normalise(d2Apex)) + d2Apex = cd2PlusSections[0][0] + d3Apex = cd3PlusSections[0][0] + rotAxisApex = vector.normalise(vector.crossproduct3(d3Apex, d2Apex)) - d1ApexAround = [] - for n1 in range(elementsCountAroundDuod): - rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * n1 - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) - d1ApexAround.append([rotFrame[j][0] * d1Apex[0] + rotFrame[j][1] * d1Apex[1] + - rotFrame[j][2] * d1Apex[2] for j in range(3)]) + px = sampleEllipsePoints(cxPlusSections[0][0], cd2PlusSections[0][0], cd3PlusSections[0][0], + 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] + d2ApexAround = [cross(cross(rotAxisApex, sub(tpx, cxApex)), rotAxisApex) for tpx in px] + + rotAngle = -math.pi * 0.5 + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) + for n in range(len(px)): + d1ApexAround.append([rotFrame[j][0] * d2ApexAround[n][0] + rotFrame[j][1] * d2ApexAround[n][1] + + rotFrame[j][2] * d2ApexAround[n][2] for j in range(3)]) xEllipseAroundAll = [xApex] d1EllipseAroundAll = [d1ApexAround] @@ -1754,12 +1772,20 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for s in range(len(cxSections)): for n2 in range(1, len(cxSections[s])): - px, pd1 = sampleEllipsePoints(cxSections[s][n2], cd2Sections[s][n2], cd3Sections[s][n2], 0.0, math.pi * 2.0, - elementsCountAroundDuod) + px, pd1 = sampleEllipsePoints(cxSections[s][n2], cd2Sections[s][n2], cd3Sections[s][n2], + 0.0, math.pi * 2.0, elementsCountAroundDuod) + px.pop() + pd1.pop() + + # get d2 from finite difference between plus and minus ellipses. note scale is not right + pxPlus = sampleEllipsePoints(cxPlusSections[s][n2], cd2PlusSections[s][n2], cd3PlusSections[s][n2], + 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] + pxPlus.pop() + pxMinus = sampleEllipsePoints(cxMinusSections[s][n2], cd2MinusSections[s][n2], cd3MinusSections[s][n2], + 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] + pxMinus.pop() + d2Around = [sub(pxPlus[n], pxMinus[n]) for n in range(len(pxPlus))] - del px[-1], pd1[-1] - - d2Around = [zero for n in range(len(pd1))] d2CurvatureAround = [0.0 for n in range(len(pd1))] xEllipseAroundAll.append(px) d1EllipseAroundAll.append(pd1) @@ -1769,37 +1795,47 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio if s == 0 and n2 == len(cxSections[s]) - 1: xGEJ = px[elementsAroundHalfDuod] + # Scale d1 and d2 at apex + d1EllipseAroundAll[0][0] = vector.setMagnitude(d1EllipseAroundAll[0][0], interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d1EllipseAroundAll[0][0], + xEllipseAroundAll[1][elementsAroundQuarterDuod], + d2EllipseAroundAll[1][elementsAroundQuarterDuod], True)) + d2EllipseAroundAll[0][0] = vector.setMagnitude(d2EllipseAroundAll[0][0], interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d2EllipseAroundAll[0][0], + xEllipseAroundAll[1][0], d2EllipseAroundAll[1][0], True)) + + # Create track surface # Find d2 + elementsCountAlongTS = 20 d2Raw = [] xRawSampled = [] d2RawSampled = [] arcLengthsAlongTS = [] + # d2 = zero for n1 in range(elementsCountAroundDuod): xAlong = [] d2Along = [] - for n2 in range(len(xEllipseAroundAll) - 1): - d2 = findDerivativeBetweenPoints(xEllipseAroundAll[n2][n1], xEllipseAroundAll[n2 + 1][n1]) + for n2 in range(len(xEllipseAroundAll)): + # d2 = findDerivativeBetweenPoints(xEllipseAroundAll[n2][n1], xEllipseAroundAll[n2 + 1][n1]) xAlong.append(xEllipseAroundAll[n2][n1]) - d2Along.append(d2) - xAlong.append(xEllipseAroundAll[-1][n1]) - d2Along.append(d2) - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Along.append(d2EllipseAroundAll[n2][n1]) + # xAlong.append(xEllipseAroundAll[-1][n1]) + # d2Along.append(d2) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along, fixAllDirections=True) d2Raw.append(d2Smoothed) # sample - xAlongSampled, d2AlongSampled = interp.sampleCubicHermiteCurves(xAlong, d2Along, 20)[0:2] - d2AlongSampledSmoothed = interp.smoothCubicHermiteDerivativesLine(xAlongSampled, d2AlongSampled) - d2RawSampled.append(d2AlongSampledSmoothed) + xAlongSampled, d2AlongSampled = interp.sampleCubicHermiteCurves(xAlong, d2Along, elementsCountAlongTS)[0:2] xRawSampled.append(xAlongSampled) + # d2AlongSampledSmoothed = interp.smoothCubicHermiteDerivativesLine(xAlongSampled, d2AlongSampled) + d2RawSampled.append(d2AlongSampled) if n1 in [elementsAroundQuarterDuod, elementsAroundHalfDuod, elementsAroundHalfDuod + elementsAroundQuarterDuod]: arcLength = 0.0 for n2 in range(len(xAlongSampled) - 1): - arcLength += interp.getCubicHermiteArcLength(xAlongSampled[n2], d2AlongSampledSmoothed[n2], - xAlongSampled[n2 + 1], d2AlongSampledSmoothed[n2 + 1]) + arcLength += interp.getCubicHermiteArcLength(xAlongSampled[n2], d2AlongSampled[n2], + xAlongSampled[n2 + 1], d2AlongSampled[n2 + 1]) arcLengthsAlongTS.append(arcLength) # Rearrange d2 @@ -1809,10 +1845,10 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # Rearrange sampled x and d2 xAroundTS = [] - d1AroundTS = [d1ApexAround] + d1AroundTS = [[zero for n1 in range(elementsCountAroundDuod)]] d2AroundTS = [] - for n2 in range(21): + for n2 in range(elementsCountAlongTS + 1): xAround= [] d1Around = [] d2Around = [] @@ -1846,15 +1882,12 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio trackSurfaceStomach = TrackSurface(elementsCountAroundDuod, len(xAroundTS) - 1, xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) - # # Visualise track surface - # for n1 in range(len(xTrackSurface)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + # Visualise track surface + tmpRegion = region.createRegion() + trackSurfaceStomach.generateMesh(tmpRegion) + tmpRegion.getFieldmodule().defineAllFaces() + tmpRegion.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_tracksurface.exf") + del tmpRegion # Set up gastro-esophagal junction with midpoint aligned to fundus-body junction GEJSettings['Number of elements around ostium'] = elementsCountAroundEso @@ -1985,7 +2018,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) p2 = trackSurfaceStomach.getProportion(xPosition) if p2[1] < endGCEsoP2: - xAlongGCHalfDuod.append(xAroundAllTransformed[n2][elementsAroundHalfDuod if n2 else 0]) + # xAlongGCHalfDuod.append(xAroundAllTransformed[n2][elementsAroundHalfDuod if n2 else 0]) + xAlongGCHalfDuod.append(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) else: break @@ -2414,8 +2448,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n2 in range(len(xOuter)): d3Around = [] for n1 in range(len(xOuter[n2])): - d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) + if n2 == 0: + d3Around.append(rotAxisApex) + else: + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) d3UnitOuter.append(d3Around) # Calculate curvature around diff --git a/src/scaffoldmaker/utils/interpolation.py b/src/scaffoldmaker/utils/interpolation.py index 3ae637e7..0b19d08d 100644 --- a/src/scaffoldmaker/utils/interpolation.py +++ b/src/scaffoldmaker/utils/interpolation.py @@ -417,7 +417,7 @@ def sampleCubicHermiteCurvesSmooth(nx, nd1, elementsCountOut, :param nd1: Derivatives of nodes along curves. :param derivativeMagnitudeStart, derivativeMagnitudeEnd: Optional magnitudes of start and end derivatives appropriate for elementsCountOut. If unspecified these are calculated from the other - end or set to be equal for even spaced elements. + end or set to be equal for even spaced elements. 0.0 is a valid derivative magnitude. :return: px[], pd1[], pe[], pxi[], psf[], where pe[] and pxi[] are lists of element indices and and xi locations in the 'in' elements to pass to partner interpolateSample functions. psf[] is a list of scale factors for converting derivatives from old to new xi coordinates: dxi(old)/dxi(new). @@ -430,11 +430,13 @@ def sampleCubicHermiteCurvesSmooth(nx, nd1, elementsCountOut, for e in range(elementsCountIn): length += getCubicHermiteArcLength(nx[e], nd1[e], nx[e + 1], nd1[e + 1]) lengths.append(length) - if derivativeMagnitudeStart and derivativeMagnitudeEnd: + hasStartDerivative = derivativeMagnitudeStart is not None + hasEndDerivative = derivativeMagnitudeEnd is not None + if hasStartDerivative and hasEndDerivative: pass - elif derivativeMagnitudeEnd: + elif hasEndDerivative: derivativeMagnitudeStart = (2.0*length - elementsCountOut*derivativeMagnitudeEnd)/elementsCountOut - elif derivativeMagnitudeStart: + elif hasStartDerivative: derivativeMagnitudeEnd = (2.0*length - elementsCountOut*derivativeMagnitudeStart)/elementsCountOut else: derivativeMagnitudeStart = derivativeMagnitudeEnd = length/elementsCountOut diff --git a/src/scaffoldmaker/utils/tracksurface.py b/src/scaffoldmaker/utils/tracksurface.py index 7308f745..cce85c1b 100644 --- a/src/scaffoldmaker/utils/tracksurface.py +++ b/src/scaffoldmaker/utils/tracksurface.py @@ -6,6 +6,13 @@ import copy import math +from cmlibs.utils.zinc.general import ChangeManager +from cmlibs.utils.zinc.field import find_or_create_field_coordinates +from cmlibs.utils.zinc.finiteelement import get_maximum_element_identifier, get_maximum_node_identifier +from cmlibs.zinc.element import Element, Elementbasis +from cmlibs.zinc.field import Field +from cmlibs.zinc.node import Node + from enum import Enum from scaffoldmaker.utils import interpolation as interp @@ -487,6 +494,52 @@ def updatePositionTofaceNumber(self, position, faceNumber): # print('!!! Reached boundary of face', faceNumber, 'position', position) return onBoundary + def generateMesh(self, region): + """ + Generate nodes and surface elements in region. + :param region: + :return: + """ + fieldmodule = region.getFieldmodule() + coordinates = find_or_create_field_coordinates(fieldmodule) + + nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + startNodeIdentifier = nodeIdentifier = max(get_maximum_node_identifier(nodes), 0) + 1 + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + + mesh = fieldmodule.findMeshByDimension(2) + elementIdentifier = max(get_maximum_element_identifier(mesh), 0) + 1 + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE) + bicubicHermiteBasis = fieldmodule.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) + # remote cross derivative terms + for n in range(4): + eft.setFunctionNumberOfTerms(n * 4 + 4, 0) + elementtemplate.defineField(coordinates, -1, eft) + + fieldcache = fieldmodule.createFieldcache() + with ChangeManager(fieldmodule): + for n1 in range(len(self.nx)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + fieldcache.setNode(node) + coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, self.nx[n1]) + coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, self.nd1[n1]) + coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, self.nd2[n1]) + nodeIdentifier += 1 + del n1 + nodesCount1 = self.elementsCount1 + 1 + for e2 in range(self.elementsCount2): + for e1 in range(self.elementsCount1): + nid1 = startNodeIdentifier + e2 * nodesCount1 + e1 + nids = [nid1, nid1 + 1, nid1 + nodesCount1, nid1 + nodesCount1 + 1] + element = mesh.createElement(elementIdentifier, elementtemplate) + element.setNodesByIdentifier(eft, nids) + # print(elementIdentifier, element.isValid(), nids) + elementIdentifier += 1 def calculate_surface_delta_xi(d1, d2, direction): ''' From b7a20c3d4dcfc149520392bfe34be73e197385f0 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 6 Jul 2023 19:26:59 +1200 Subject: [PATCH 02/30] Add points along fundus on central path --- .../meshtypes/meshtype_3d_stomach1.py | 205 ++++++++++-------- 1 file changed, 113 insertions(+), 92 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 7235bb7a..56d52bdc 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -52,53 +52,58 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 7 + 'Number of elements': 12 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 1.406, 0.437, 0.000 ], [ -0.179, -0.503, 0.000 ], [ 0.413, -0.146, 0.000 ], [ -0.039, -0.062, 0.000 ], [ 0.000, 0.000, 0.406 ], [ 0.000, 0.000, 0.047 ]]), - (2, [[ 1.200, 0.000, 0.000 ], [ -0.234, -0.366, 0.000 ], [ 0.338, -0.215, 0.000 ], [ -0.111, -0.076, 0.000 ], [ 0.000, 0.000, 0.435 ], [ 0.000, 0.000, 0.009 ]]), - (3, [[ 0.955, -0.294, 0.000 ], [ -0.291, -0.193, 0.000 ], [ 0.196, -0.296, 0.000 ], [ -0.159, -0.021, 0.000 ], [ 0.000, 0.000, 0.429 ], [ 0.000, 0.000, -0.053 ]]), - (4, [[ 0.660, -0.383, 0.000 ], [ -0.294, -0.027, 0.000 ], [ 0.024, -0.269, 0.000 ], [ -0.135, 0.048, 0.000 ], [ 0.000, 0.000, 0.339 ], [ 0.000, 0.000, -0.099 ]]), - (5, [[ 0.385, -0.352, 0.000 ], [ -0.216, 0.084, 0.000 ], [ -0.079, -0.202, 0.000 ], [ -0.067, 0.084, 0.000 ], [ 0.000, 0.000, 0.232 ], [ 0.000, 0.000, -0.071 ]]), - (6, [[ 0.237, -0.244, 0.000 ], [ -0.116, 0.131, 0.000 ], [ -0.122, -0.107, 0.000 ], [ -0.004, 0.082, 0.000 ], [ 0.000, 0.000, 0.185 ], [ 0.000, 0.000, -0.062 ]]), - (7, [[ 0.158, -0.101, 0.000 ], [ -0.067, 0.165, 0.000 ], [ -0.090, -0.037, 0.000 ], [ 0.004, 0.046, 0.000 ], [ 0.000, 0.000, 0.110 ], [ 0.000, 0.000, -0.033 ]]), - (8, [[ 0.108, 0.083, 0.000 ], [ -0.034, 0.203, 0.000 ], [ -0.117, -0.020, 0.000 ], [ -0.058, -0.012, 0.000 ], [ 0.000, 0.000, 0.126 ], [ 0.000, 0.000, 0.064 ]]) + (1, [ [ 1.41, 0.44, 0.00 ], [ -0.02, -0.03, 0.00 ], [ 0.04, -0.02, 0.00 ], [ 0.13, -0.05, 0.00 ], [ 0.00, 0.00, 0.04 ], [ 0.00, 0.00, 0.13 ] ] ), + (2, [ [ 1.39, 0.40, 0.00 ], [ -0.02, -0.05, 0.00 ], [ 0.16, -0.07, 0.00 ], [ 0.11, -0.04, 0.00 ], [ 0.00, 0.00, 0.17 ], [ 0.00, 0.00, 0.13 ] ] ), + (3, [ [ 1.37, 0.34, 0.00 ], [ -0.03, -0.08, 0.00 ], [ 0.26, -0.10, 0.00 ], [ 0.09, -0.04, 0.00 ], [ 0.00, 0.00, 0.29 ], [ 0.00, 0.00, 0.11 ] ] ), + (4, [ [ 1.33, 0.25, 0.00 ], [ -0.04, -0.10, 0.00 ], [ 0.33, -0.15, 0.00 ], [ 0.05, -0.04, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, 0.07 ] ] ), + (5, [ [ 1.28, 0.14, 0.00 ], [ -0.06, -0.13, 0.00 ], [ 0.36, -0.18, 0.00 ], [ 0.01, -0.04, 0.00 ], [ 0.00, 0.00, 0.42 ], [ 0.00, 0.00, 0.03 ] ] ), + (6, [ [ 1.20, 0.00, 0.00 ], [ -0.11, -0.17, 0.00 ], [ 0.34, -0.22, 0.00 ], [ -0.04, -0.04, 0.00 ], [ 0.00, 0.00, 0.43 ], [ 0.00, 0.00, 0.01 ] ] ), + (7, [ [ 1.06, -0.19, 0.00 ], [ -0.16, -0.17, 0.00 ], [ 0.27, -0.27, 0.00 ], [ -0.10, -0.05, 0.00 ], [ 0.00, 0.00, 0.44 ], [ 0.00, 0.00, -0.01 ] ] ), + (8, [ [ 0.88, -0.33, 0.00 ], [ -0.21, -0.10, 0.00 ], [ 0.15, -0.31, 0.00 ], [ -0.13, -0.00, 0.00 ], [ 0.00, 0.00, 0.41 ], [ 0.00, 0.00, -0.05 ] ] ), + (9, [ [ 0.66, -0.38, 0.00 ], [ -0.25, -0.01, 0.00 ], [ 0.02, -0.27, 0.00 ], [ -0.11, 0.05, 0.00 ], [ 0.00, 0.00, 0.34 ], [ 0.00, 0.00, -0.09 ] ] ), + (10, [ [ 0.39, -0.35, 0.00 ], [ -0.22, 0.08, 0.00 ], [ -0.08, -0.20, 0.00 ], [ -0.06, 0.08, 0.00 ], [ 0.00, 0.00, 0.23 ], [ 0.00, 0.00, -0.07 ] ] ), + (11, [ [ 0.24, -0.24, 0.00 ], [ -0.12, 0.13, 0.00 ], [ -0.12, -0.11, 0.00 ], [ -0.00, 0.08, 0.00 ], [ 0.00, 0.00, 0.18 ], [ 0.00, 0.00, -0.06 ] ] ), + (12, [ [ 0.16, -0.10, 0.00 ], [ -0.07, 0.16, 0.00 ], [ -0.09, -0.04, 0.00 ], [ 0.00, 0.05, 0.00 ], [ 0.00, 0.00, 0.11 ], [ 0.00, 0.00, -0.03 ] ] ), + (13, [ [ 0.11, 0.08, 0.00 ], [ -0.03, 0.20, 0.00 ], [ -0.12, -0.02, 0.00 ], [ -0.06, -0.01, 0.00 ], [ 0.00, 0.00, 0.13 ], [ 0.00, 0.00, 0.07 ] ] ) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1', + 'identifierRanges': '1-5', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '2-3', + 'identifierRanges': '6-8', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '4-5', + 'identifierRanges': '9-10', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6', + 'identifierRanges': '11', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7', + 'identifierRanges': '12', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] @@ -109,52 +114,58 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 7 + 'Number of elements': 12 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 61.47, -101.30, 1152.18 ], [ 1.92, -17.01, -22.36 ], [ 15.88, -0.53, 2.00 ], [ -1.47, -0.53, -7.23 ], [ -4.20, -32.38, 24.81 ], [ 1.62, -4.46, 0.00 ] ] ), - (2, [ [ 61.43, -121.54, 1122.53 ], [ -2.01, -23.41, -36.85 ], [ 39.29, -6.83, 2.36 ], [ -7.43, -2.71, -11.05 ], [ -7.56, -35.47, 23.07 ], [ 0.31, -0.85, 0.00 ] ] ), - (3, [ [ 56.78, -147.38, 1078.66 ], [ -18.57, -19.78, -33.63 ], [ 37.34, -13.52, -12.67 ], [ -13.50, -4.91, -7.49 ], [ -4.91, -35.87, 23.81 ], [ -1.83, 5.03, 0.00 ] ] ), - (4, [ [ 32.14, -159.44, 1058.12 ], [ -25.49, -7.02, -11.18 ], [ 12.92, -15.68, -19.60 ], [ -13.60, -4.95, -0.11 ], [ -1.59, -27.21, 20.72 ], [ -3.42, 9.40, 0.00 ] ] ), - (5, [ [ 10.36, -162.05, 1054.83 ], [ -21.12, 0.81, -0.05 ], [ -0.49, -14.00, -17.23 ], [ -8.70, -3.17, 5.66 ], [ -0.74, -18.17, 14.78 ], [ -2.45, 6.74, 0.00 ] ] ), - (6, [ [ -8.74, -158.28, 1057.63 ], [ -14.76, 6.59, 2.22 ], [ -6.11, -10.23, -10.22 ], [ -2.39, 4.12, 5.11 ], [ -3.26, -12.00, 13.95 ], [ -1.56, 6.63, -3.36 ] ] ), - (7, [ [ -18.83, -150.69, 1059.20 ], [ -11.47, 11.36, 1.06 ], [ -6.41, -5.88, -6.34 ], [ -0.18, 2.75, 2.61 ], [ -4.20, -5.07, 8.95 ], [ -1.21, 4.57, -2.38 ] ] ), - (8, [ [ -30.74, -135.24, 1059.32 ], [ -10.69, 13.10, -0.80 ], [ -6.40, -5.57, -5.67 ], [ 1.20, -0.04, -0.56 ], [ -5.80, -4.09, 10.56 ], [ 0.50, 1.74, -3.24 ] ] ) ] ), - + (1, [[ 61.59, -101.05, 1152.90 ], [ 0.44, -2.86, -3.86 ], [ 11.30, -0.23, 1.46 ], [ 15.70, -3.03, 2.83 ], [ -0.85, -7.44, 5.42 ], [ -5.75, -22.46, 14.95 ] ] ), + (2, [[ 61.99, -104.31, 1148.31 ], [ 0.36, -3.66, -5.31 ], [ 24.17, -2.49, 3.34 ], [ 10.04, -1.49, 0.93 ], [ -4.92, -25.06, 16.91 ], [ -2.38, -12.78, 8.03 ] ] ), + (3, [[ 62.28, -108.34, 1142.26 ], [ 0.25, -4.60, -7.04 ], [ 30.56, -2.99, 3.04 ], [ 5.72, -0.45, -0.07 ], [ -5.13, -31.61, 20.49 ], [ -0.21, -5.09, 2.60 ] ] ), + (4, [[ 62.47, -113.50, 1134.22 ], [ 0.31, -6.15, -9.74 ], [ 35.40, -3.37, 3.27 ], [ 4.54, -0.49, 0.32 ], [ -5.33, -34.80, 21.80 ], [ -0.38, -3.01, 1.22 ] ] ), + (5, [[ 62.94, -120.61, 1122.78 ], [ 0.45, -8.60, -13.99 ], [ 39.52, -4.01, 3.73 ], [ 3.19, -0.59, -0.29 ], [ -5.97, -37.56, 22.89 ], [ -0.10, -1.22, 0.55 ] ] ), + (6, [[ 63.32, -130.67, 1106.22 ], [ -0.18, -10.49, -16.96 ], [ 41.37, -4.52, 2.35 ], [ 0.50, -2.47, -4.03 ], [ -5.29, -36.56, 22.66 ], [ 0.26, 0.76, 0.24 ] ] ), + (7, [[ 62.54, -141.56, 1088.91 ], [ -4.62, -11.40, -18.64 ], [ 40.43, -9.06, -4.49 ], [ -4.50, -6.38, -11.05 ], [ -5.48, -36.05, 23.41 ], [ 0.77, 0.60, 1.05 ] ] ), + (8, [[ 53.67, -152.88, 1069.82 ], [ -15.96, -9.81, -16.27 ], [ 31.73, -17.62, -20.50 ], [ -14.93, -3.76, -8.28 ], [ -3.58, -35.33, 24.82 ], [ 2.03, 4.35, -1.23 ] ] ), + (9, [[ 32.23, -159.89, 1058.56 ], [ -22.29, -4.56, -7.46 ], [ 10.24, -16.32, -20.63 ], [ -15.75, 1.84, 1.75 ], [ -1.41, -27.16, 20.79 ], [ 1.20, 8.62, -5.08 ] ] ), + (10, [[ 10.36, -162.05, 1054.83 ], [ -21.09, 1.02, -0.27 ], [ -0.46, -14.00, -17.23 ], [ -8.02, 3.09, 5.32 ], [ -1.07, -18.15, 14.78 ], [ -1.00, 7.50, -3.26 ] ] ), + (11, [[ -8.74, -158.28, 1057.63 ], [ -14.76, 6.59, 2.22 ], [ -6.11, -10.23, -10.22 ], [ -2.40, 4.12, 5.11 ], [ -3.26, -12.00, 13.95 ], [ -1.43, 6.62, -3.36 ] ] ), + (12, [[-18.83, -150.69, 1059.20 ], [ -11.48, 11.37, 1.06 ], [ -6.41, -5.88, -6.34 ], [ -0.42, 3.10, 2.58 ], [ -4.20, -5.07, 8.95 ], [ -1.38, 4.80, -2.40 ] ] ), + (13, [[-30.74, -135.24, 1059.32 ], [ -12.23, 19.36, -0.81 ], [ -7.02, -4.68, -5.74 ], [ -0.80, -0.69, -1.38 ], [ -6.25, -3.51, 10.51 ], [ -2.73, -1.67, 5.52 ] ] ) + ]), + 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1', + 'identifierRanges': '1-4', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '2-3', + 'identifierRanges': '5-8', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '4-5', + 'identifierRanges': '9-10', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6', + 'identifierRanges': '11', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7', + 'identifierRanges': '12', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] @@ -165,55 +176,57 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 8 + 'Number of elements': 11 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 1.700, 0.603, 0.000 ], [ 0.103, -0.338, 0.000 ], [ 0.470, -0.088, 0.000 ], [ -0.191, -0.149, 0.000 ], [ 0.000, 0.000, 0.382 ], [ 0.000, 0.000, 0.121]]), - (2, [[ 1.690, 0.280, 0.000 ], [ -0.147, -0.294, 0.000 ], [ 0.294, -0.221, 0.000 ], [ -0.161, -0.117, 0.000 ], [ 0.000, 0.000, 0.456 ], [ 0.000, 0.000, 0.027]]), - (3, [[ 1.498, 0.059, 0.000 ], [ -0.294, -0.132, 0.000 ], [ 0.147, -0.323, 0.000 ], [ -0.169, -0.102, 0.000 ], [ 0.000, 0.000, 0.441 ], [ 0.000, 0.000, -0.022]]), - (4, [[ 1.200, 0.000, 0.000 ], [ -0.338, 0.044, 0.000 ], [ -0.044, -0.426, 0.000 ], [ -0.198, -0.003, 0.000 ], [ 0.000, 0.000, 0.412 ], [ 0.000, 0.000, -0.032]]), - (5, [[ 0.862, 0.147, 0.000 ], [ -0.221, 0.206, 0.000 ], [ -0.250, -0.309, 0.000 ], [ -0.103, 0.149, 0.000 ], [ 0.000, 0.000, 0.377 ], [ 0.000, 0.000, -0.046]]), - (6, [[ 0.759, 0.368, 0.000 ], [ -0.029, 0.206, 0.000 ], [ -0.284, -0.139, 0.000 ], [ 0.048, 0.118, 0.000 ], [ 0.000, 0.000, 0.324 ], [ 0.000, 0.000, -0.091]]), - (7, [[ 0.765, 0.543, 0.000 ], [ 0.015, 0.147, 0.000 ], [ -0.178, -0.057, 0.000 ], [ 0.089, 0.068, 0.000 ], [ 0.000, 0.000, 0.206 ], [ 0.000, 0.000, -0.093]]), - (8, [[ 0.799, 0.677, 0.000 ], [ 0.000, 0.132, 0.000 ], [ -0.103, 0.000, 0.000 ], [ 0.035, 0.027, 0.000 ], [ 0.000, 0.000, 0.132 ], [ 0.000, 0.000, -0.043]]), - (9, [[ 0.788, 0.809, 0.000 ], [ -0.015, 0.132, 0.000 ], [ -0.107, -0.002, 0.000 ], [ -0.043, -0.031, 0.000 ], [ 0.000, 0.000, 0.118 ], [ 0.000, 0.000, 0.015]]) + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [ [ 1.70, 0.60, 0.00 ], [ 0.04, -0.05, 0.00 ], [ 0.05, 0.04, 0.00 ], [ 0.14, 0.01, 0.00 ], [ 0.00, 0.00, 0.04 ], [ 0.00, 0.00, 0.13 ] ] ), + (2, [ [ 1.73, 0.52, 0.00 ], [ 0.01, -0.10, 0.00 ], [ 0.18, 0.02, 0.00 ], [ 0.11, -0.04, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, 0.12 ] ] ), + (3, [ [ 1.72, 0.40, 0.00 ], [ -0.03, -0.14, 0.00 ], [ 0.27, -0.05, 0.00 ], [ 0.08, -0.10, 0.00 ], [ 0.00, 0.00, 0.27 ], [ 0.00, 0.00, 0.10 ] ] ), + (4, [ [ 1.67, 0.24, 0.00 ], [ -0.08, -0.15, 0.00 ], [ 0.33, -0.17, 0.00 ], [ -0.00, -0.14, 0.00 ], [ 0.00, 0.00, 0.35 ], [ 0.00, 0.00, 0.07 ] ] ), + (5, [ [ 1.56, 0.10, 0.00 ], [ -0.14, -0.11, 0.00 ], [ 0.26, -0.32, 0.00 ], [ -0.11, -0.11, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, 0.03 ] ] ), + (6, [ [ 1.39, 0.02, 0.00 ], [ -0.21, -0.05, 0.00 ], [ 0.10, -0.40, 0.00 ], [ -0.17, -0.05, 0.00 ], [ 0.00, 0.00, 0.41 ], [ 0.00, 0.00, 0.01 ] ] ), + (7, [ [ 1.12, 0.01, 0.00 ], [ -0.28, 0.06, 0.00 ], [ -0.08, -0.42, 0.00 ], [ -0.19, 0.04, 0.00 ], [ 0.00, 0.00, 0.41 ], [ 0.00, 0.00, -0.01 ] ] ), + (8, [ [ 0.86, 0.15, 0.00 ], [ -0.22, 0.21, 0.00 ], [ -0.25, -0.31, 0.00 ], [ -0.10, 0.15, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, -0.05 ] ] ), + (9, [ [ 0.76, 0.37, 0.00 ], [ -0.03, 0.21, 0.00 ], [ -0.24, -0.17, 0.01 ], [ 0.05, 0.12, 0.00 ], [ 0.00, 0.00, 0.32 ], [ 0.00, 0.00, -0.09 ] ] ), + (10, [ [ 0.77, 0.54, 0.00 ], [ 0.01, 0.15, 0.00 ], [ -0.18, -0.06, 0.00 ], [ 0.09, 0.07, 0.00 ], [ 0.00, 0.00, 0.21 ], [ 0.00, 0.00, -0.09 ] ] ), + (11, [ [ 0.80, 0.68, 0.00 ], [ 0.00, 0.13, 0.00 ], [ -0.10, 0.00, 0.00 ], [ 0.04, 0.03, 0.00 ], [ 0.00, 0.00, 0.13 ], [ 0.00, 0.00, -0.04 ] ] ), + (12, [ [ 0.79, 0.81, 0.00 ], [ -0.01, 0.13, 0.00 ], [ -0.11, 0.00, 0.00 ], [ -0.04, -0.03, 0.00 ], [ 0.00, 0.00, 0.12 ], [ 0.00, 0.00, 0.01 ] ] ) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-3', + 'identifierRanges': '1-6', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '4-5', + 'identifierRanges': '7-8', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6', + 'identifierRanges': '9', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7', + 'identifierRanges': '10', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '8', + 'identifierRanges': '11', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] @@ -224,53 +237,56 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 7 + 'Number of elements': 10 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 1.401, 0.390, 0.000 ], [ -0.244, -0.494, 0.000 ], [ 0.218, -0.129, 0.000 ], [ 0.219, -0.097, 0.000 ], [ 0.000, 0.000, 0.328 ], [ 0.000, 0.000, 0.101]]), - (2, [[ 1.200, 0.000, 0.000 ], [ -0.157, -0.287, 0.000 ], [ 0.366, -0.195, 0.000 ], [ 0.054, -0.047, 0.000 ], [ 0.000, 0.000, 0.393 ], [ 0.000, 0.000, 0.028]]), - (3, [[ 1.093, -0.185, 0.000 ], [ -0.140, -0.215, 0.000 ], [ 0.356, -0.232, 0.000 ], [ -0.051, -0.053, 0.000 ], [ 0.000, 0.000, 0.398 ], [ 0.000, 0.000, -0.008]]), - (4, [[ 0.916, -0.425, 0.000 ], [ -0.230, -0.170, 0.000 ], [ 0.244, -0.312, 0.000 ], [ -0.162, -0.058, 0.000 ], [ 0.000, 0.000, 0.373 ], [ 0.000, 0.000, -0.044]]), - (5, [[ 0.664, -0.512, 0.000 ], [ -0.287, 0.022, 0.000 ], [ 0.037, -0.350, 0.000 ], [ -0.197, 0.057, 0.000 ], [ 0.000, 0.000, 0.313 ], [ 0.000, 0.000, -0.104]]), - (6, [[ 0.405, -0.372, 0.000 ], [ -0.170, 0.231, 0.000 ], [ -0.150, -0.188, 0.000 ], [ -0.048, 0.159, 0.000 ], [ 0.000, 0.000, 0.159 ], [ 0.000, 0.000, -0.092]]), - (7, [[ 0.352, -0.110, 0.000 ], [ -0.098, 0.216, 0.000 ], [ -0.072, -0.057, 0.000 ], [ 0.033, 0.052, 0.000 ], [ 0.000, 0.000, 0.085 ], [ 0.000, 0.000, -0.020]]), - (8, [[ 0.229, 0.051, 0.000 ], [ -0.139, 0.099, 0.000 ], [ -0.052, -0.071, 0.000 ], [ -0.031, -0.104, 0.000 ], [ 0.000, 0.000, 0.094 ], [ 0.000, 0.000, 0.006]]) + (1, [[ 1.40, 0.39, 0.00 ], [ -0.01, -0.02, 0.00 ], [ 0.05, -0.03, 0.00 ], [ 0.06, -0.02, 0.00 ], [ 0.00, 0.00, 0.08 ], [ 0.00, 0.00, 0.05 ] ] ), + (2, [[ 1.39, 0.37, 0.00 ], [ -0.04, -0.07, 0.00 ], [ 0.13, -0.06, 0.00 ], [ 0.09, -0.04, 0.00 ], [ 0.00, 0.00, 0.15 ], [ 0.00, 0.00, 0.08 ] ] ), + (3, [[ 1.36, 0.30, 0.00 ], [ -0.06, -0.13, 0.00 ], [ 0.25, -0.13, 0.00 ], [ 0.11, -0.06, 0.00 ], [ 0.00, 0.00, 0.28 ], [ 0.00, 0.00, 0.12 ] ] ), + (4, [[ 1.29, 0.17, 0.00 ], [ -0.09, -0.17, 0.00 ], [ 0.35, -0.18, 0.00 ], [ 0.06, -0.04, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, 0.06 ] ] ), + (5, [[ 1.20, 0.00, 0.00 ], [ -0.16, -0.29, 0.00 ], [ 0.37, -0.20, 0.00 ], [ 0.00, -0.03, 0.00 ], [ 0.00, 0.00, 0.39 ], [ 0.00, 0.00, 0.01 ] ] ), + (6, [[ 1.09, -0.18, 0.00 ], [ -0.14, -0.21, 0.00 ], [ 0.36, -0.23, 0.00 ], [ -0.05, -0.05, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, -0.01 ] ] ), + (7, [[ 0.92, -0.42, 0.00 ], [ -0.23, -0.17, 0.00 ], [ 0.24, -0.31, 0.00 ], [ -0.16, -0.06, 0.00 ], [ 0.00, 0.00, 0.37 ], [ 0.00, 0.00, -0.04 ] ] ), + (8, [[ 0.66, -0.51, 0.00 ], [ -0.29, 0.02, 0.00 ], [ 0.04, -0.35, 0.00 ], [ -0.20, 0.06, 0.00 ], [ 0.00, 0.00, 0.31 ], [ 0.00, 0.00, -0.10 ] ] ), + (9, [[ 0.41, -0.37, 0.00 ], [ -0.17, 0.23, 0.00 ], [ -0.15, -0.19, 0.00 ], [ -0.05, 0.16, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, -0.09 ] ] ), + (10, [[ 0.35, -0.11, 0.00 ], [ -0.10, 0.22, 0.00 ], [ -0.07, -0.06, 0.00 ], [ 0.03, 0.05, 0.00 ], [ 0.00, 0.00, 0.09 ], [ 0.00, 0.00, -0.02 ] ] ), + (11, [[ 0.23, 0.05, 0.00 ], [ -0.14, 0.10, 0.00 ], [ -0.05, -0.07, 0.00 ], [ -0.03, -0.10, 0.00 ], [ 0.00, 0.00, 0.09 ], [ 0.00, 0.00, 0.01 ] ] ) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1', + 'identifierRanges': '1-4', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '2-4', + 'identifierRanges': '5-7', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '5', + 'identifierRanges': '8', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6', + 'identifierRanges': '9', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7', + 'identifierRanges': '10', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] @@ -281,54 +297,58 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 8 + 'Number of elements': 12 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 1.666, 0.636, 0.000 ], [ 0.039, -0.249, 0.000 ], [ 0.282, 0.044, 0.000 ], [ 0.215, -0.158, 0.000 ], [ 0.000, 0.000, 0.318 ], [ 0.000, 0.000, 0.060]]), - (2, [[ 1.643, 0.375, 0.000 ], [ -0.086, -0.263, 0.000 ], [ 0.392, -0.127, 0.000 ], [ 0.008, -0.184, 0.000 ], [ 0.000, 0.000, 0.365 ], [ 0.000, 0.000, 0.035]]), - (3, [[ 1.496, 0.130, 0.000 ], [ -0.231, -0.204, 0.000 ], [ 0.287, -0.326, 0.000 ], [ -0.167, -0.162, 0.000 ], [ 0.000, 0.000, 0.387 ], [ 0.000, 0.000, 0.007]]), - (4, [[ 1.200, 0.000, 0.000 ], [ -0.322, -0.034, 0.000 ], [ 0.048, -0.444, 0.000 ], [ -0.262, -0.032, 0.000 ], [ 0.000, 0.000, 0.378 ], [ 0.000, 0.000, -0.020]]), - (5, [[ 0.879, 0.088, 0.000 ], [ -0.291, 0.191, 0.000 ], [ -0.223, -0.365, 0.000 ], [ -0.175, 0.165, 0.000 ], [ 0.000, 0.000, 0.348 ], [ 0.000, 0.000, -0.058]]), - (6, [[ 0.694, 0.378, 0.000 ], [ -0.083, 0.278, 0.000 ], [ -0.219, -0.145, 0.000 ], [ 0.041, 0.183, 0.000 ], [ 0.000, 0.000, 0.267 ], [ 0.000, 0.000, -0.114]]), - (7, [[ 0.689, 0.568, 0.000 ], [ -0.014, 0.165, 0.000 ], [ -0.156, -0.025, 0.000 ], [ 0.090, 0.031, 0.000 ], [ 0.000, 0.000, 0.120 ], [ 0.000, 0.000, -0.035]]), - (8, [[ 0.664, 0.691, 0.000 ], [ -0.035, 0.115, 0.000 ], [ -0.107, -0.035, 0.000 ], [ 0.011, -0.024, 0.000 ], [ 0.000, 0.000, 0.116 ], [ 0.000, 0.000, 0.011]]), - (9, [[ 0.619, 0.796, 0.000 ], [ -0.054, 0.096, 0.000 ], [ -0.125, -0.071, 0.000 ], [ -0.048, -0.047, 0.000 ], [ 0.000, 0.000, 0.146 ], [ 0.000, 0.000, -0.011]]) + (1, [[ 1.67, 0.64, 0.00 ], [ 0.00, -0.03, 0.00 ], [ 0.07, 0.01, 0.00 ], [ -0.17, -0.03, 0.00 ], [ 0.00, 0.00, 0.08 ], [ 0.00, 0.00, -0.24 ] ] ), + (2, [[ 1.67, 0.57, 0.00 ], [ 0.00, -0.11, 0.00 ], [ 0.18, 0.01, 0.00 ], [ -0.03, -0.05, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, -0.08 ] ] ), + (3, [[ 1.66, 0.43, 0.00 ], [ -0.03, -0.15, 0.00 ], [ 0.31, -0.07, 0.00 ], [ 0.09, -0.09, 0.00 ], [ 0.00, 0.00, 0.27 ], [ 0.00, 0.00, 0.09 ] ] ), + (4, [[ 1.60, 0.27, 0.00 ], [ -0.08, -0.15, 0.00 ], [ 0.35, -0.18, 0.00 ], [ -0.01, -0.12, 0.00 ], [ 0.00, 0.00, 0.33 ], [ 0.00, 0.00, 0.05 ] ] ), + (5, [[ 1.51, 0.14, 0.00 ], [ -0.12, -0.11, 0.00 ], [ 0.30, -0.32, 0.00 ], [ -0.09, -0.11, 0.00 ], [ 0.00, 0.00, 0.37 ], [ 0.00, 0.00, 0.02 ] ] ), + (6, [[ 1.37, 0.05, 0.00 ], [ -0.16, -0.07, 0.00 ], [ 0.18, -0.39, 0.00 ], [ -0.12, -0.06, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, 0.01 ] ] ), + (7, [[ 1.20, 0.00, 0.00 ], [ -0.20, -0.01, 0.00 ], [ 0.05, -0.44, 0.00 ], [ -0.26, -0.03, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, -0.02 ] ] ), + (8, [[ 0.98, 0.04, 0.00 ], [ -0.21, 0.09, 0.00 ], [ -0.15, -0.41, 0.00 ], [ -0.18, 0.08, 0.00 ], [ 0.00, 0.00, 0.36 ], [ 0.00, 0.00, -0.02 ] ] ), + (9, [[ 0.79, 0.17, 0.00 ], [ -0.15, 0.18, 0.00 ], [ -0.25, -0.29, 0.00 ], [ -0.00, 0.15, 0.00 ], [ 0.00, 0.00, 0.33 ], [ 0.00, 0.00, -0.05 ] ] ), + (10, [[ 0.69, 0.38, 0.00 ], [ -0.05, 0.21, 0.00 ], [ -0.22, -0.17, 0.00 ], [ 0.04, 0.18, 0.00 ], [ 0.00, 0.00, 0.27 ], [ 0.00, 0.00, -0.11 ] ] ), + (11, [[ 0.69, 0.57, 0.00 ], [ -0.02, 0.16, 0.00 ], [ -0.16, -0.03, 0.00 ], [ 0.09, 0.03, 0.00 ], [ 0.00, 0.00, 0.12 ], [ 0.00, 0.00, -0.04 ] ] ), + (12, [[ 0.66, 0.69, 0.00 ], [ -0.04, 0.12, 0.00 ], [ -0.11, -0.04, 0.00 ], [ 0.01, -0.02, 0.00 ], [ 0.00, 0.00, 0.12 ], [ 0.00, 0.00, 0.01 ] ] ), + (13, [[ 0.62, 0.80, 0.00 ], [ -0.04, 0.10, 0.00 ], [ -0.12, -0.07, 0.00 ], [ -0.05, -0.05, 0.00 ], [ 0.00, 0.00, 0.15 ], [ 0.00, 0.00, -0.01 ] ] ) ]), - + 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-3', + 'identifierRanges': '1-6', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '4-5', + 'identifierRanges': '7-9', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6', + 'identifierRanges': '10', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7', + 'identifierRanges': '11', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '8', + 'identifierRanges': '12', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] @@ -343,21 +363,21 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[2.00,0.00,0.00], [-0.02,-0.00,-0.00], [0.00,-0.05,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.05], [0.00,0.00,0.10]]), - (2, [[1.98,0.00,0.00], [-0.06,0.00,0.00], [0.00,-0.16,0.00], [0.00,-0.11,0.00], [0.00,0.00,0.16], [0.00,0.00,0.11]]), - (3, [[1.88,0.00,0.00], [-0.12,0.00,0.00], [0.00,-0.29,0.00], [0.00,-0.12,0.00], [0.00,0.00,0.29], [0.00,0.00,0.12]]), - (4, [[1.75,0.00,0.00], [-0.15,0.00,0.00], [0.00,-0.40,0.00], [0.00,-0.09,0.00], [0.00,0.00,0.40], [0.00,0.00,0.09]]), - (5, [[1.58,0.00,0.00], [-0.18,0.00,0.00], [0.00,-0.47,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.47], [0.00,0.00,0.05]]), - (6, [[1.40,0.00,0.00], [-0.19,0.00,0.00], [0.00,-0.50,0.00], [0.00,-0.02,0.00], [0.00,0.00,0.50], [0.00,0.00,0.02]]), - (7, [[1.20,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,-0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), - (8, [[1.00,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.00]]), - (9, [[0.80,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.00]]), - (10, [[0.60,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.07,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.07]]), - (11, [[0.40,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.40,0.00], [0.00,0.15,0.00], [0.00,0.00,0.40], [0.00,0.00,-0.15]]), - (12, [[0.20,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.10,0.00], [0.00,0.00,0.20], [0.00,0.00,-0.10]]), - (13, [[0.00,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.20,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.20], [0.00,0.00,0.10]]) - ]), - + (1, [ [2.00, 0.00, 0.00 ], [ -0.02, 0.00, 0.00 ], [ 0.00, -0.05, 0.00 ], [ 0.00, -0.10, 0.00 ], [ 0.00, 0.00, 0.05 ], [ 0.00, 0.00, 0.10 ] ] ), + (2, [ [1.98, 0.00, 0.00 ], [ -0.06, 0.00, 0.00 ], [ 0.00, -0.16, 0.00 ], [ 0.00, -0.11, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, 0.11 ] ] ), + (3, [ [1.88, 0.00, 0.00 ], [ -0.12, 0.00, 0.00 ], [ 0.00, -0.29, 0.00 ], [ 0.00, -0.12, 0.00 ], [ 0.00, 0.00, 0.29 ], [ 0.00, 0.00, 0.12 ] ] ), + (4, [ [1.75, 0.00, 0.00 ], [ -0.15, 0.00, 0.00 ], [ 0.00, -0.40, 0.00 ], [ 0.00, -0.09, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, 0.09 ] ] ), + (5, [ [1.58, 0.00, 0.00 ], [ -0.18, 0.00, 0.00 ], [ 0.00, -0.47, 0.00 ], [ 0.00, -0.05, 0.00 ], [ 0.00, 0.00, 0.47 ], [ 0.00, 0.00, 0.05 ] ] ), + (6, [ [1.40, 0.00, 0.00 ], [ -0.19, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, -0.02, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.02 ] ] ), + (7, [ [1.20, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, -0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), + (8, [ [1.00, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), + (9, [ [0.80, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), + (10, [ [0.60, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.07, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, -0.07 ] ] ), + (11, [ [0.40, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.40, 0.00 ], [ 0.00, 0.15, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, -0.15 ] ] ), + (12, [ [0.20, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.20, 0.00 ], [ 0.00, 0.10, 0.00 ], [ 0.00, 0.00, 0.20 ], [ 0.00, 0.00, -0.10 ] ] ), + (13, [ [0.00, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.20, 0.00 ], [ 0.00, -0.10, 0.00 ], [ 0.00, 0.00, 0.20 ], [ 0.00, 0.00, 0.10 ] ] ) + ]), + 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -641,6 +661,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Human 2' in parameterSetName: + options['Number of elements between cardia and duodenum'] = 8 options['Number of elements through wall'] = 1 # 4 later options['Wall thickness'] = 0.0525 * 101 elif 'Mouse 1' in parameterSetName: @@ -656,7 +677,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): elif 'Pig 1' in parameterSetName: options['Number of elements around duodenum'] = 16 options['Number of elements between fundus apex and cardia'] = 3 - options['Number of elements between cardia and duodenum'] = 7 + options['Number of elements between cardia and duodenum'] = 6 options['Wall thickness'] = 0.059 options['Mucosa relative thickness'] = 0.47 options['Submucosa relative thickness'] = 0.1 From 6bcc1a9bba4c2fe53d8ea65e594d4fdfac1b80f6 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 6 Jul 2023 19:31:27 +1200 Subject: [PATCH 03/30] Correct typo to gastro-esophageal --- .../meshtypes/meshtype_3d_stomach1.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 56d52bdc..c4f1b108 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -654,7 +654,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Circular muscle layer relative thickness': 0.25, 'Longitudinal muscle layer relative thickness': 0.05, 'Limiting ridge': False, - 'Gastro-esophagal junction': copy.deepcopy(ostiumOption), + 'Gastro-esophageal junction': copy.deepcopy(ostiumOption), 'Use linear through wall': True, 'Refine': False, 'Refine number of elements surface': 4, @@ -722,7 +722,7 @@ def getOrderedOptionNames(): 'Circular muscle layer relative thickness', 'Longitudinal muscle layer relative thickness', 'Limiting ridge', - 'Gastro-esophagal junction', + 'Gastro-esophageal junction', 'Use linear through wall', 'Refine', 'Refine number of elements surface', @@ -732,7 +732,7 @@ def getOrderedOptionNames(): def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': return [MeshType_1d_path1] - if optionName == 'Gastro-esophagal junction': + if optionName == 'Gastro-esophageal junction': return [MeshType_3d_ostium1] return [] @@ -740,7 +740,7 @@ def getOptionValidScaffoldTypes(cls, optionName): def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.keys()) - if optionName == 'Gastro-esophagal junction': + if optionName == 'Gastro-esophageal junction': return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ @@ -761,7 +761,7 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non if not parameterSetName: parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) - if optionName == 'Gastro-esophagal junction': + if optionName == 'Gastro-esophageal junction': if not parameterSetName: parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) @@ -771,9 +771,9 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non def checkOptions(cls, options): if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) - if not options['Gastro-esophagal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( - 'Gastro-esophagal junction'): - options['Gastro-esophagal junction'] = cls.getOptionScaffoldPackage('Gastro-esophagal junction', + if not options['Gastro-esophageal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( + 'Gastro-esophageal junction'): + options['Gastro-esophageal junction'] = cls.getOptionScaffoldPackage('Gastro-esophageal junction', MeshType_3d_ostium1) if options['Number of elements around duodenum'] < 12: options['Number of elements around duodenum'] = 12 @@ -798,7 +798,7 @@ def updateSubScaffoldOptions(cls, options): """ Update ostium sub-scaffold options which depend on parent options. """ - ostiumOptions = options['Gastro-esophagal junction'] + ostiumOptions = options['Gastro-esophageal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() wallThickness = options['Wall thickness'] / ostiumSettings['Unit scale'] ostiumSettings['Ostium wall thickness'] = wallThickness @@ -1362,7 +1362,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio useCrossDerivatives = False useCubicHermiteThroughWall = not (options['Use linear through wall']) - GEJOptions = options['Gastro-esophagal junction'] + GEJOptions = options['Gastro-esophageal junction'] GEJSettings = GEJOptions.getScaffoldSettings() elementsAlongEsophagus = GEJSettings['Number of elements along'] elementsThroughEsophagusWall = GEJSettings['Number of elements through wall'] @@ -1910,7 +1910,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio tmpRegion.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_tracksurface.exf") del tmpRegion - # Set up gastro-esophagal junction with midpoint aligned to fundus-body junction + # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction GEJSettings['Number of elements around ostium'] = elementsCountAroundEso GEJPosition = trackSurfaceStomach.findNearestPosition(xGEJ) xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GEJPosition, derivatives=True) From 5fbdd1c7083f2f8e6eb5659da8000c54fdce6e22 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 6 Jul 2023 19:43:02 +1200 Subject: [PATCH 04/30] Pre-calculate how to spread out elements along --- .../meshtypes/meshtype_3d_stomach1.py | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index c4f1b108..0faeab25 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -829,6 +829,10 @@ def generateBaseMesh(cls, region, options): materialCentralPath = cls.centralPathDefaultScaffoldPackages['Material'] limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] + elementsAlongFundusApexToCardia = options['Number of elements between fundus apex and cardia'] + elementsAlongCardiaToDuod = options['Number of elements between cardia and duodenum'] + elementsCountAroundEso = 8 + elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) allAnnotationGroups = [] stomachTermsAlong = [None, 'fundus of stomach', 'body of stomach', @@ -840,17 +844,43 @@ def generateBaseMesh(cls, region, options): geometricCentralPath = StomachCentralPath(region, geometricCentralPath, stomachTermsAlong) geometricCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path.exf") + arcLengthOfGroupsAlong = geometricCentralPath.arcLengthOfGroupsAlong + + # Pre-calculate element numbers in each group + elementsAlongFromBody = elementsAlongCardiaToDuod + elementsAroundQuarterEso - 1 + arcLengthOfGroupsAlongFromBody = arcLengthOfGroupsAlong[0] - arcLengthOfGroupsAlong[1] + estElementLengthFromBody = arcLengthOfGroupsAlongFromBody / elementsAlongFromBody + + modGroups = [0.0] + elementsAlongCPFundus = elementsAlongFundusApexToCardia + elementsAroundQuarterEso - 1 + elementCountGroupList = [elementsAlongCPFundus] + elementsTally = 0 + for i in range(2, len(stomachTermsAlong)): + numberOfElementsGroup = int(arcLengthOfGroupsAlong[i] // estElementLengthFromBody) + if numberOfElementsGroup < 1: + numberOfElementsGroup = 1 + + mod = arcLengthOfGroupsAlong[i] - estElementLengthFromBody * numberOfElementsGroup + modGroups.append(mod) + + elementsTally += numberOfElementsGroup + elementCountGroupList.append(numberOfElementsGroup) + + excessElements = elementsAlongFromBody - elementsTally + for i in range(excessElements): + maxIdx = max(range(len(modGroups)), key=modGroups.__getitem__) + elementCountGroupList[maxIdx] += 1 + modGroups[maxIdx] = arcLengthOfGroupsAlong[maxIdx] - estElementLengthFromBody * \ + elementCountGroupList[maxIdx] - elementCountGroupList = [] allAnnotationGroups, elementCountGroupList, nextNodeIdentifier, nextElementIdentifier = \ createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, elementCountGroupList, centralPath=geometricCentralPath, options=options, nodeIdentifier=1, elementIdentifier=1, splitCoordinates=False, materialCoordinates=False) - stomach_coordinates = findOrCreateFieldCoordinates(fm, name="stomach coordinates") - # Material coordinates + stomach_coordinates = findOrCreateFieldCoordinates(fm, name="stomach coordinates") allAnnotationGroupsMaterial = [] tmp_region = region.createRegion() tmp_fm = tmp_region.getFieldmodule() @@ -1374,7 +1404,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementsCountAcrossCardia = 1 cardiaDiameterFactor = 1.4 # scale to ostium diameter sf = (cardiaDiameterFactor - 1) * ostiumDiameter * 0.5 * GEJSettings['Unit scale'] - fundusStraightFactor = 0.2 + # fundusStraightFactor = 0.2 elementsAroundHalfEso = int(elementsCountAroundEso * 0.5) elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) @@ -1471,34 +1501,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio [circularMuscleGroup], [longitudinalMuscleGroup]] - # Spread out elements along groups - elementsAlongFromBody = elementsAlongCardiaToDuod + elementsAroundQuarterEso - 1 - arcLengthOfGroupsAlongFromBody = arcLengthOfGroupsAlong[0] - arcLengthOfGroupsAlong[1] - estElementLengthFromBody = arcLengthOfGroupsAlongFromBody / elementsAlongFromBody - - if not materialCoordinates: - modGroups = [0.0] - elementsAlongCPFundus = elementsAlongFundusApexToCardia + elementsAroundQuarterEso - 1 - elementCountGroupList = [elementsAlongCPFundus] - elementsTally = 0 - for i in range(2, len(stomachTermsAlong)): - numberOfElementsGroup = int(arcLengthOfGroupsAlong[i] // estElementLengthFromBody) - if numberOfElementsGroup < 1: - numberOfElementsGroup = 1 - - mod = arcLengthOfGroupsAlong[i] - estElementLengthFromBody * numberOfElementsGroup - modGroups.append(mod) - - elementsTally += numberOfElementsGroup - elementCountGroupList.append(numberOfElementsGroup) - - excessElements = elementsAlongFromBody - elementsTally - for i in range(excessElements): - maxIdx = max(range(len(modGroups)), key=modGroups.__getitem__) - elementCountGroupList[maxIdx] += 1 - modGroups[maxIdx] = arcLengthOfGroupsAlong[maxIdx] - estElementLengthFromBody * \ - elementCountGroupList[maxIdx] - # Break central path into elements allocation to each group cxSections = [] cd1Sections = [] From 128c06af7c4b881d3ad426802b7b5354048a6dfe Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 7 Jul 2023 10:11:32 +1200 Subject: [PATCH 05/30] Remove return of elementCountGroupList --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 0faeab25..2772ed7d 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -873,7 +873,7 @@ def generateBaseMesh(cls, region, options): modGroups[maxIdx] = arcLengthOfGroupsAlong[maxIdx] - estElementLengthFromBody * \ elementCountGroupList[maxIdx] - allAnnotationGroups, elementCountGroupList, nextNodeIdentifier, nextElementIdentifier = \ + allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier = \ createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, elementCountGroupList, centralPath=geometricCentralPath, options=options, nodeIdentifier=1, elementIdentifier=1, splitCoordinates=False, @@ -890,7 +890,7 @@ def generateBaseMesh(cls, region, options): materialCentralPath = StomachCentralPath(tmp_region, materialCentralPath, stomachTermsAlong) materialCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path_material.exf") - allAnnotationGroupsMaterial, elementCountGroupList, nextNodeIdentifier, nextElementIdentifier = \ + allAnnotationGroupsMaterial, nextNodeIdentifier, nextElementIdentifier = \ createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, allAnnotationGroupsMaterial, elementCountGroupList, centralPath=materialCentralPath, options=options, nodeIdentifier=1, @@ -3267,7 +3267,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio allAnnotationGroups.append(nearLCGroup) - return allAnnotationGroups, elementCountGroupList, nextNodeIdentifier, nextElementIdentifier + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier def findCentreOnCentralPathFromCrossAxisEndPt(xPoint, xCentralPath, dCentralPath): From fa3c272452ea01543d4df8ce0984ecf7e723732a Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 7 Jul 2023 12:14:59 +1200 Subject: [PATCH 06/30] Remove unused code --- .../meshtypes/meshtype_3d_stomach1.py | 229 +----------------- 1 file changed, 10 insertions(+), 219 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 2772ed7d..31be1971 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1221,7 +1221,6 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): annotationGroups.remove(nearLCGroup) - class StomachCentralPath: """ Generates sampled central path for stomach scaffold. @@ -1404,7 +1403,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementsCountAcrossCardia = 1 cardiaDiameterFactor = 1.4 # scale to ostium diameter sf = (cardiaDiameterFactor - 1) * ostiumDiameter * 0.5 * GEJSettings['Unit scale'] - # fundusStraightFactor = 0.2 elementsAroundHalfEso = int(elementsCountAroundEso * 0.5) elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) @@ -1467,9 +1465,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio arcLengthRatioForGroupsFromFundusApex = [] arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong stomachCentralPathLength = arcLengthOfGroupsAlong[0] - # xApex = centralPath.cxGroups[0][0] - # d1Apex = centralPath.cd2Groups[0][0] - # d2Apex = centralPath.cd3Groups[0][0] for i in range(1, len(stomachTermsAlong)): arcLengthRatio = arcLengthOfGroupsAlong[i] / stomachCentralPathLength @@ -1557,216 +1552,12 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio cd2MinusSections.append(cd2MinusSection) cd3MinusSections.append(cd3MinusSection) - # if i == 1: # body: calculate end of fundus stuff - # for n in range(len(cxSection)): - # px, pd1 = sampleEllipsePoints(cxSection[n], cd2Section[n], cd3Section[n], 0.0, math.pi * 2.0, - # elementsCountAroundDuod) - # del px[-1], pd1[-1] - # - # if n == 0: - # pxFundusEndQuarter = px[elementsAroundQuarterDuod] - # d2FundusEndQuarter = cd1Section[0] - # pxFundusEndGC = px[0] - # if n == 1: - # d2FundusEndGC = findDerivativeBetweenPoints(pxFundusEndGC, px[0]) - # put fundus section first for values in [cxSections, cd1Sections, cd2Sections, cd3Sections, cxPlusSections, cd2PlusSections, cd3PlusSections, cxMinusSections, cd2MinusSections, cd3MinusSections]: values.insert(0, values.pop()) - # # Create straight tube joined to ellipsoid for fundus - # lengthOfFundusAlongCP = centralPath.arcLengthOfGroupsAlong[1] - # ellipsoidHeight = (1 - fundusStraightFactor) * lengthOfFundusAlongCP - # - # elementsAlong = 10 - # xQuarterFundus = [] - # xGCFundus = [] - # xLine = [] - # dLine = [] - # d2Line = [] - # - # # Sample ellipsoid part of central path into elementsAlong - # cxFundus = centralPath.cxGroups[1] - # cd1Fundus = centralPath.cd1Groups[1] - # cd2Fundus = centralPath.cd2Groups[1] - # cd3Fundus = centralPath.cd3Groups[1] - # cd12Fundus = centralPath.cd12Groups[1] - # cd13Fundus = centralPath.cd13Groups[1] - # - # sxFundus, sd1Fundus, pe, pxi, psf = interp.sampleCubicHermiteCurves(cxFundus, cd1Fundus, elementsAlong) - # sd2Fundus, sd12Fundus = interp.interpolateSampleCubicHermite(cd2Fundus, cd12Fundus, pe, pxi, psf) - # sd3Fundus, sd13Fundus = interp.interpolateSampleCubicHermite(cd3Fundus, cd13Fundus, pe, pxi, psf) - # - # xEllipsoidEnd, d1EllipsoidEnd, elementEllipsoidEnd, xi = \ - # interp.getCubicHermiteCurvesPointAtArcDistance(sxFundus, sd1Fundus, ellipsoidHeight) - # d2EllipsoidEnd, d12EllipsoidEnd = interp.getCubicHermiteCurvesPointAtArcDistance(sd2Fundus, sd12Fundus, - # ellipsoidHeight)[0:2] - # d3EllipsoidEnd, d13EllipsoidEnd = interp.getCubicHermiteCurvesPointAtArcDistance(sd3Fundus, sd13Fundus, - # ellipsoidHeight)[0:2] - # - # ellipsoidMajorDiameter = vector.magnitude(d2EllipsoidEnd) - # ellipsoidMinorDiameter = vector.magnitude(d3EllipsoidEnd) - # - # # resample just ellipsoidal part - # sxFundusEllipsoid, sd1FundusEllipsoid, pe, pxi, psf = \ - # interp.sampleCubicHermiteCurves(sxFundus[:elementEllipsoidEnd + 1] + [xEllipsoidEnd], - # sd1Fundus[:elementEllipsoidEnd + 1] + [d1EllipsoidEnd], - # elementsAlong, arcLengthDerivatives=True) - # - # sd2FundusEllipsoid, sd12FundusEllipsoid = \ - # interp.interpolateSampleCubicHermite(sd2Fundus[:elementEllipsoidEnd + 1] + [d2EllipsoidEnd], - # sd12Fundus[:elementEllipsoidEnd + 1] + [d12EllipsoidEnd], pe, pxi, psf) - # - # # Create template fundus with path of fundus length for transformation - # xAroundAll = [] - # for n2 in range(elementsAlong + 1): - # xLine.append([-ellipsoidHeight/elementsAlong * n2, 0.0, 0.0]) - # dLine.append([-ellipsoidHeight/elementsAlong, 0.0, 0.0]) - # d2Line.append([0.0, -10.0, 0.0]) - # theta = math.acos((-ellipsoidHeight/elementsAlong * n2 + ellipsoidHeight)/ellipsoidHeight) - # xAround = [] - # - # for n1 in range(elementsCountAroundDuod): - # psi = math.pi * 2.0 / elementsCountAroundDuod * n1 - # x = [ellipsoidHeight * math.cos(theta) - ellipsoidHeight, - # -ellipsoidMajorDiameter * math.sin(theta) * math.cos(psi), - # ellipsoidMinorDiameter * math.sin(theta) * math.sin(psi)] - # xAround.append(x) - # xAroundAll.append(xAround) - # - # # Transform ellipse ring to align with central path - # xAroundAllTransformed = [] - # for n2 in range(elementsAlong + 1): - # xAroundTransformed = [] - # unitTangent = vector.normalise(sd1FundusEllipsoid[n2]) - # unitVectorLine = vector.normalise(dLine[n2]) - # cp = vector.crossproduct3(unitVectorLine, unitTangent) - # dp = vector.dotproduct(dLine[n2], sd1FundusEllipsoid[n2]) - # centroid = xLine[n2] - # d2 = d2Line[n2] - # - # if vector.magnitude(cp) > 0.0: # path tangent not parallel to segment axis - # axisRot = vector.normalise(cp) - # thetaRot = math.acos(dp / (vector.magnitude(dLine[n2]) * vector.magnitude(sd1FundusEllipsoid[n2]))) - # rotFrame = matrix.getRotationMatrixFromAxisAngle(axisRot, thetaRot) - # centroidRot = [rotFrame[j][0]*centroid[0] + rotFrame[j][1]*centroid[1] + - # rotFrame[j][2]*centroid[2] for j in range(3)] - # - # else: # path tangent parallel to unitVectorLine (x-axis) - # if dp == -1.0: # path tangent opposite direction to unitVectorLine - # thetaRot = math.pi - # axisRot = [1.0, 0, 0] - # rotFrame = matrix.getRotationMatrixFromAxisAngle(axisRot, thetaRot) - # centroidRot = [rotFrame[j][0] * centroid[0] + rotFrame[j][1] * centroid[1] + - # rotFrame[j][2] * centroid[2] for j in range(3)] - # - # else: # unitVectorLine in same direction as unit tangent - # rotFrame = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - # centroidRot = centroid - # - # translateMatrix = [sxFundusEllipsoid[n2][j] - centroidRot[j] for j in range(3)] - # - # for n1 in range(len(xAroundAll[n2])): - # x = xAroundAll[n2][n1] - # if vector.magnitude(cp) > 0.0: # path tangent not parallel to segment axis - # xRot1 = [rotFrame[j][0] * x[0] + rotFrame[j][1] * x[1] + rotFrame[j][2] * x[2] for j in range(3)] - # else: # path tangent parallel to segment axis - # xRot1 = [rotFrame[j][0] * x[0] + rotFrame[j][1] * x[1] + rotFrame[j][2] * x[2] for j in - # range(3)] if dp == -1.0 else x - # - # # Check that the first node in each ellipse is aligned to sd2 - # if n1 == 0: - # vectorToFirstNode = [xRot1[c] - centroidRot[c] for c in range(3)] - # if vector.magnitude(vectorToFirstNode) > 0.0: - # cp = vector.crossproduct3(vector.normalise(vectorToFirstNode), - # vector.normalise(sd2FundusEllipsoid[n2])) - # if vector.magnitude(cp) > 1e-7: - # cp = vector.normalise(cp) - # signThetaRot2 = vector.dotproduct(unitTangent, cp) - # thetaRot2 = math.acos( - # vector.dotproduct(vector.normalise(vectorToFirstNode), vector.normalise(sd2FundusEllipsoid[n2]))) - # axisRot2 = unitTangent - # rotFrame2 = matrix.getRotationMatrixFromAxisAngle(axisRot2, signThetaRot2 * thetaRot2) - # else: - # rotFrame2 = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - # else: - # rotFrame2 = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - # - # xRot2 = [rotFrame2[j][0] * xRot1[0] + rotFrame2[j][1] * xRot1[1] + rotFrame2[j][2] * xRot1[2] for j in - # range(3)] - # xAroundTransformed.append([xRot2[j] + translateMatrix[j] for j in range(3)]) - # xAroundAllTransformed.append(xAroundTransformed) - # - # for n in range(elementEllipsoidEnd + 1, len(sxFundus) - 1): - # x = sampleEllipsePoints(sxFundus[n], sd2Fundus[n], sd3Fundus[n], 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] - # del x[-1] - # - # xAroundAllTransformed.append(x) - # - # for n2 in range(elementsAlong): - # xGCFundus.append(xAroundAllTransformed[n2][0]) - # xQuarterFundus.append(xAroundAllTransformed[n2][elementsAroundQuarterDuod]) - # xQuarterFundus.append(pxFundusEndQuarter) - # xGCFundus.append(pxFundusEndGC) - # - # # Find derivative and sample fundus - # # Quarter - # d2FundusQuarter = [d2Apex] - # for n in range(1, len(xQuarterFundus) - 1): - # d2FundusQuarter.append(findDerivativeBetweenPoints(xQuarterFundus[n], xQuarterFundus[n + 1])) - # d2FundusQuarter.append(d2FundusEndQuarter) - # - # xFundusQuarterSampled, d2FundusQuarterSampled = \ - # interp.sampleCubicHermiteCurvesSmooth(xQuarterFundus, d2FundusQuarter, elementCountGroupList[0], - # derivativeMagnitudeEnd=vector.magnitude(d2FundusEndQuarter))[0:2] - # - # # GC - # d2FundusGC = [d1Apex] - # for n in range(1, len(xGCFundus) - 1): - # d2FundusGC.append(findDerivativeBetweenPoints(xGCFundus[n], xGCFundus[n + 1])) - # d2FundusGC.append(d2FundusEndGC) - # - # xFundusGCSampled, d2FundusGCSampled = \ - # interp.sampleCubicHermiteCurvesSmooth(xGCFundus, d2FundusGC, elementCountGroupList[0], - # derivativeMagnitudeStart=vector.magnitude(d2FundusQuarterSampled[0]), - # derivativeMagnitudeEnd=vector.magnitude(d2FundusEndGC))[0:2] - # - # for n2 in range(elementsAlong): - # xGCFundus.append(xAroundAllTransformed[n2][0]) - # xQuarterFundus.append(xAroundAllTransformed[n2][elementsAroundQuarterDuod]) - # xQuarterFundus.append(pxFundusEndQuarter) - # xGCFundus.append(pxFundusEndGC) - # - # cxFundus = [xApex] - # cd1Fundus = [] - # cd2Fundus = [d1Apex] - # cd3Fundus = [d2Apex] - # - # for n2 in range(1, len(xFundusQuarterSampled)): # skip apex - # xProjectionQuarter = findCentreOnCentralPathFromCrossAxisEndPt(xFundusQuarterSampled[n2], sxFundus, sd1Fundus) - # xProjectionGC = findCentreOnCentralPathFromCrossAxisEndPt(xFundusGCSampled[n2], sxFundus, sd1Fundus) - # xProjectionAve = [0.5 * xProjectionQuarter[c] + 0.5 * xProjectionGC[c] for c in range(3)] - # - # cxFundus.append(xProjectionAve) - # d1 = findDerivativeBetweenPoints(cxFundus[n2 - 1], cxFundus[n2]) - # d2 = findDerivativeBetweenPoints(xProjectionGC, xFundusGCSampled[n2]) - # d3 = findDerivativeBetweenPoints(xProjectionQuarter, xFundusQuarterSampled[n2]) - # cd3DV = vector.normalise(vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) - # d3 = vector.setMagnitude(cd3DV, vector.magnitude(d3)) - # - # cd1Fundus.append(d1) - # cd2Fundus.append(d2) - # cd3Fundus.append(d3) - # cd1Fundus.append(cd1Fundus[-1]) - - # # Merge fundus with other groups on central path - # cxSections = [cxFundus] + cxSections - # cd1Sections = [cd1Fundus] + cd1Sections - # cd2Sections = [cd2Fundus] + cd2Sections - # cd3Sections = [cd3Fundus] + cd3Sections - # Create ellipses cxApex = cxSections[0][0] xApex = [cxApex for n1 in range(elementsCountAroundDuod)] @@ -1819,12 +1610,16 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xGEJ = px[elementsAroundHalfDuod] # Scale d1 and d2 at apex - d1EllipseAroundAll[0][0] = vector.setMagnitude(d1EllipseAroundAll[0][0], interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d1EllipseAroundAll[0][0], - xEllipseAroundAll[1][elementsAroundQuarterDuod], - d2EllipseAroundAll[1][elementsAroundQuarterDuod], True)) - d2EllipseAroundAll[0][0] = vector.setMagnitude(d2EllipseAroundAll[0][0], interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d2EllipseAroundAll[0][0], - xEllipseAroundAll[1][0], d2EllipseAroundAll[1][0], True)) - + d1EllipseAroundAll[0][0] = \ + vector.setMagnitude(d1EllipseAroundAll[0][0], + interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d1EllipseAroundAll[0][0], + xEllipseAroundAll[1][elementsAroundQuarterDuod], + d2EllipseAroundAll[1][elementsAroundQuarterDuod], True)) + d2EllipseAroundAll[0][0] = \ + vector.setMagnitude(d2EllipseAroundAll[0][0], + interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d2EllipseAroundAll[0][0], + xEllipseAroundAll[1][0], d2EllipseAroundAll[1][0], + True)) # Create track surface # Find d2 @@ -1839,18 +1634,14 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xAlong = [] d2Along = [] for n2 in range(len(xEllipseAroundAll)): - # d2 = findDerivativeBetweenPoints(xEllipseAroundAll[n2][n1], xEllipseAroundAll[n2 + 1][n1]) xAlong.append(xEllipseAroundAll[n2][n1]) d2Along.append(d2EllipseAroundAll[n2][n1]) - # xAlong.append(xEllipseAroundAll[-1][n1]) - # d2Along.append(d2) d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along, fixAllDirections=True) d2Raw.append(d2Smoothed) # sample xAlongSampled, d2AlongSampled = interp.sampleCubicHermiteCurves(xAlong, d2Along, elementsCountAlongTS)[0:2] xRawSampled.append(xAlongSampled) - # d2AlongSampledSmoothed = interp.smoothCubicHermiteDerivativesLine(xAlongSampled, d2AlongSampled) d2RawSampled.append(d2AlongSampled) if n1 in [elementsAroundQuarterDuod, elementsAroundHalfDuod, From ad756cb7312a1b00c3452aa9f46c953e7970f1df Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 19 Jul 2023 10:41:17 +1200 Subject: [PATCH 07/30] Update antrum to 0.3, fundus to 0.7 in material coordinates --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 31be1971..c0aebc6f 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -369,10 +369,10 @@ class MeshType_3d_stomach1(Scaffold_base): (4, [ [1.75, 0.00, 0.00 ], [ -0.15, 0.00, 0.00 ], [ 0.00, -0.40, 0.00 ], [ 0.00, -0.09, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, 0.09 ] ] ), (5, [ [1.58, 0.00, 0.00 ], [ -0.18, 0.00, 0.00 ], [ 0.00, -0.47, 0.00 ], [ 0.00, -0.05, 0.00 ], [ 0.00, 0.00, 0.47 ], [ 0.00, 0.00, 0.05 ] ] ), (6, [ [1.40, 0.00, 0.00 ], [ -0.19, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, -0.02, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.02 ] ] ), - (7, [ [1.20, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, -0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), + (7, [ [1.30, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, -0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), (8, [ [1.00, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), (9, [ [0.80, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), - (10, [ [0.60, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.07, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, -0.07 ] ] ), + (10, [ [0.70, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.07, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, -0.07 ] ] ), (11, [ [0.40, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.40, 0.00 ], [ 0.00, 0.15, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, -0.15 ] ] ), (12, [ [0.20, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.20, 0.00 ], [ 0.00, 0.10, 0.00 ], [ 0.00, 0.00, 0.20 ], [ 0.00, 0.00, -0.10 ] ] ), (13, [ [0.00, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.20, 0.00 ], [ 0.00, -0.10, 0.00 ], [ 0.00, 0.00, 0.20 ], [ 0.00, 0.00, 0.10 ] ] ) From c0082036f57b8145e2e14e8d7e49269087d0d9ba Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 19 Jul 2023 14:22:17 +1200 Subject: [PATCH 08/30] Implement hemisphere and cubic hermite functions for material coordinates --- docs/scaffolds/stomach.rst | 12 ++++-- .../meshtypes/meshtype_3d_stomach1.py | 37 ++++++++++--------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/docs/scaffolds/stomach.rst b/docs/scaffolds/stomach.rst index a40d96b1..cc1eeadd 100644 --- a/docs/scaffolds/stomach.rst +++ b/docs/scaffolds/stomach.rst @@ -60,9 +60,15 @@ which is intended to be fitted to actual data for a specimen. The material coordinates field ``stomach coordinates`` defines a highly idealized coordinate system to give permanent locations for embedding structures in the stomach. It is defined by a capsule-shaped structure with an inlet cylindrical -tube representing the esophagus and another outlet tube representing the duodenum. This can be viewed by -visualising this field in the *Display* tab of **Scaffold Creator** or by switching to the special ``Material`` -parameter set. +tube representing the esophagus and another outlet tube representing the duodenum. In this coordinate field, the stomach +has a unit length of 2.0. The length of the fundus region is 0.7 unit. It is represented by a hemisphere with +unit length diameter along the first 0.5 unit length and a cylindrical tube with a uniform unit diameter along the next +0.2 unit along its length. The body continues as a cylindrical tube with a uniform unit diameter along its 0.6 unit +length. The antrum is a cylindrical tube of 0.3 unit length and the rate of change of its diameter along its length is +described by a cubic hermite function, decreasing at a rate of 0.75 unit/unit length. The pylorus and duodenum are both +described by cylindrical tube with a uniform diameter of 0.4 unit and a length of 0.2 unit. The material coordinates +field can be viewed by visualising this field in the *Display* tab of **Scaffold Creator** or by switching to the +special ``Material`` parameter set. The stomach scaffold supports limited refinement/resampling by checking *Refine* (set parameter to ``true``) with chosen *Refine number of elements* parameters. Be aware that only the ``coordinates`` field is currently defined on the refined diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index c0aebc6f..fb2ac1fc 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -359,23 +359,26 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 12 + 'Number of elements': 15 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [2.00, 0.00, 0.00 ], [ -0.02, 0.00, 0.00 ], [ 0.00, -0.05, 0.00 ], [ 0.00, -0.10, 0.00 ], [ 0.00, 0.00, 0.05 ], [ 0.00, 0.00, 0.10 ] ] ), - (2, [ [1.98, 0.00, 0.00 ], [ -0.06, 0.00, 0.00 ], [ 0.00, -0.16, 0.00 ], [ 0.00, -0.11, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, 0.11 ] ] ), - (3, [ [1.88, 0.00, 0.00 ], [ -0.12, 0.00, 0.00 ], [ 0.00, -0.29, 0.00 ], [ 0.00, -0.12, 0.00 ], [ 0.00, 0.00, 0.29 ], [ 0.00, 0.00, 0.12 ] ] ), - (4, [ [1.75, 0.00, 0.00 ], [ -0.15, 0.00, 0.00 ], [ 0.00, -0.40, 0.00 ], [ 0.00, -0.09, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, 0.09 ] ] ), - (5, [ [1.58, 0.00, 0.00 ], [ -0.18, 0.00, 0.00 ], [ 0.00, -0.47, 0.00 ], [ 0.00, -0.05, 0.00 ], [ 0.00, 0.00, 0.47 ], [ 0.00, 0.00, 0.05 ] ] ), - (6, [ [1.40, 0.00, 0.00 ], [ -0.19, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, -0.02, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.02 ] ] ), - (7, [ [1.30, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, -0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), - (8, [ [1.00, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), - (9, [ [0.80, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.00, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, 0.00 ] ] ), - (10, [ [0.70, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.50, 0.00 ], [ 0.00, 0.07, 0.00 ], [ 0.00, 0.00, 0.50 ], [ 0.00, 0.00, -0.07 ] ] ), - (11, [ [0.40, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.40, 0.00 ], [ 0.00, 0.15, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, -0.15 ] ] ), - (12, [ [0.20, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.20, 0.00 ], [ 0.00, 0.10, 0.00 ], [ 0.00, 0.00, 0.20 ], [ 0.00, 0.00, -0.10 ] ] ), - (13, [ [0.00, 0.00, 0.00 ], [ -0.20, 0.00, 0.00 ], [ 0.00, -0.20, 0.00 ], [ 0.00, -0.10, 0.00 ], [ 0.00, 0.00, 0.20 ], [ 0.00, 0.00, 0.10 ] ] ) + (1, [[2.00,0.00,0.00], [-0.02,0.00,0.00], [0.00,-0.05,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.05], [0.00,0.00,0.10]]), + (2, [[1.98,0.00,0.00], [-0.05,0.00,0.00], [0.00,-0.15,0.00], [0.00,-0.11,0.00], [0.00,0.00,0.15], [0.00,0.00,0.11]]), + (3, [[1.90,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.29,0.00], [0.00,-0.13,0.00], [0.00,0.00,0.29], [0.00,0.00,0.13]]), + (4, [[1.79,0.00,0.00], [-0.13,0.00,0.00], [0.00,-0.40,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.40], [0.00,0.00,0.10]]), + (5, [[1.65,0.00,0.00], [-0.16,0.00,0.00], [0.00,-0.48,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.48], [0.00,0.00,0.05]]), + (6, [[1.48,0.00,0.00], [-0.17,0.00,0.00], [0.00,-0.50,0.00], [0.00,-0.01,0.00], [0.00,0.00,0.50], [0.00,0.00,0.01]]), + (7, [[1.30,0.00,0.00], [-0.19,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), + (8, [[1.10,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), + (9, [[0.90,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), + (10, [[0.70,0.00,0.00], [-0.18,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.04,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.04]]), + (11, [[0.55,0.00,0.00], [-0.15,0.00,0.00], [0.00,-0.44,0.00], [0.00,0.10,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.10]]), + (12, [[0.40,0.00,0.00], [-0.12,0.00,0.00], [0.00,-0.31,0.00], [0.00,0.12,0.00], [0.00,0.00,0.31], [0.00,0.00,-0.12]]), + (13, [[0.30,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,-0.05]]), + (14, [[0.20,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,-0.05]]), + (15, [[0.10,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,0.05]]), + (16, [[0.00,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,0.05]]) ]), 'userAnnotationGroups': [ @@ -396,21 +399,21 @@ class MeshType_3d_stomach1(Scaffold_base): { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '10', + 'identifierRanges': '10-11', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '11', + 'identifierRanges': '12-13', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '12', + 'identifierRanges': '14-15', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] From 67c62964b18eca84588e4761438ee1e05988ecbe Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 21 Jul 2023 12:00:51 +1200 Subject: [PATCH 09/30] Update central paths to make smooth track surfaces --- .../meshtypes/meshtype_3d_stomach1.py | 3593 +++++++++-------- 1 file changed, 1821 insertions(+), 1772 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index fb2ac1fc..a4a15aca 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -10,10 +10,10 @@ import math from cmlibs.maths.vectorops import cross, sub -from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates -from cmlibs.utils.zinc.finiteelement import get_element_node_identifiers, getMaximumNodeIdentifier +from cmlibs.utils.zinc.field import find_or_create_field_coordinates +from cmlibs.utils.zinc.finiteelement import get_maximum_element_identifier, get_maximum_node_identifier from cmlibs.utils.zinc.general import ChangeManager -from cmlibs.zinc.element import Element +from cmlibs.zinc.element import Element, Elementbasis from cmlibs.zinc.field import Field from cmlibs.zinc.node import Node from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups, \ @@ -56,19 +56,19 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 1.41, 0.44, 0.00 ], [ -0.02, -0.03, 0.00 ], [ 0.04, -0.02, 0.00 ], [ 0.13, -0.05, 0.00 ], [ 0.00, 0.00, 0.04 ], [ 0.00, 0.00, 0.13 ] ] ), - (2, [ [ 1.39, 0.40, 0.00 ], [ -0.02, -0.05, 0.00 ], [ 0.16, -0.07, 0.00 ], [ 0.11, -0.04, 0.00 ], [ 0.00, 0.00, 0.17 ], [ 0.00, 0.00, 0.13 ] ] ), - (3, [ [ 1.37, 0.34, 0.00 ], [ -0.03, -0.08, 0.00 ], [ 0.26, -0.10, 0.00 ], [ 0.09, -0.04, 0.00 ], [ 0.00, 0.00, 0.29 ], [ 0.00, 0.00, 0.11 ] ] ), - (4, [ [ 1.33, 0.25, 0.00 ], [ -0.04, -0.10, 0.00 ], [ 0.33, -0.15, 0.00 ], [ 0.05, -0.04, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, 0.07 ] ] ), - (5, [ [ 1.28, 0.14, 0.00 ], [ -0.06, -0.13, 0.00 ], [ 0.36, -0.18, 0.00 ], [ 0.01, -0.04, 0.00 ], [ 0.00, 0.00, 0.42 ], [ 0.00, 0.00, 0.03 ] ] ), - (6, [ [ 1.20, 0.00, 0.00 ], [ -0.11, -0.17, 0.00 ], [ 0.34, -0.22, 0.00 ], [ -0.04, -0.04, 0.00 ], [ 0.00, 0.00, 0.43 ], [ 0.00, 0.00, 0.01 ] ] ), - (7, [ [ 1.06, -0.19, 0.00 ], [ -0.16, -0.17, 0.00 ], [ 0.27, -0.27, 0.00 ], [ -0.10, -0.05, 0.00 ], [ 0.00, 0.00, 0.44 ], [ 0.00, 0.00, -0.01 ] ] ), - (8, [ [ 0.88, -0.33, 0.00 ], [ -0.21, -0.10, 0.00 ], [ 0.15, -0.31, 0.00 ], [ -0.13, -0.00, 0.00 ], [ 0.00, 0.00, 0.41 ], [ 0.00, 0.00, -0.05 ] ] ), - (9, [ [ 0.66, -0.38, 0.00 ], [ -0.25, -0.01, 0.00 ], [ 0.02, -0.27, 0.00 ], [ -0.11, 0.05, 0.00 ], [ 0.00, 0.00, 0.34 ], [ 0.00, 0.00, -0.09 ] ] ), - (10, [ [ 0.39, -0.35, 0.00 ], [ -0.22, 0.08, 0.00 ], [ -0.08, -0.20, 0.00 ], [ -0.06, 0.08, 0.00 ], [ 0.00, 0.00, 0.23 ], [ 0.00, 0.00, -0.07 ] ] ), - (11, [ [ 0.24, -0.24, 0.00 ], [ -0.12, 0.13, 0.00 ], [ -0.12, -0.11, 0.00 ], [ -0.00, 0.08, 0.00 ], [ 0.00, 0.00, 0.18 ], [ 0.00, 0.00, -0.06 ] ] ), - (12, [ [ 0.16, -0.10, 0.00 ], [ -0.07, 0.16, 0.00 ], [ -0.09, -0.04, 0.00 ], [ 0.00, 0.05, 0.00 ], [ 0.00, 0.00, 0.11 ], [ 0.00, 0.00, -0.03 ] ] ), - (13, [ [ 0.11, 0.08, 0.00 ], [ -0.03, 0.20, 0.00 ], [ -0.12, -0.02, 0.00 ], [ -0.06, -0.01, 0.00 ], [ 0.00, 0.00, 0.13 ], [ 0.00, 0.00, 0.07 ] ] ) + (1, [[1.41,0.44,0.00], [-0.01,-0.03,0.00], [0.04,-0.01,0.00], [0.13,-0.05,0.00], [0.00,0.00,0.04], [0.00,0.00,0.13]]), + (2, [[1.40,0.40,0.00], [-0.02,-0.05,0.00], [0.16,-0.06,0.00], [0.11,-0.05,0.00], [0.00,0.00,0.17], [0.00,0.00,0.13]]), + (3, [[1.37,0.34,0.00], [-0.03,-0.08,0.00], [0.25,-0.11,0.00], [0.09,-0.04,0.00], [0.00,0.00,0.29], [0.00,0.00,0.11]]), + (4, [[1.33,0.25,0.00], [-0.04,-0.10,0.00], [0.33,-0.15,0.00], [0.05,-0.04,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), + (5, [[1.28,0.14,0.00], [-0.06,-0.13,0.00], [0.36,-0.18,0.00], [0.01,-0.04,0.00], [0.00,0.00,0.42], [0.00,0.00,0.03]]), + (6, [[1.20,0.00,0.00], [-0.11,-0.17,0.00], [0.34,-0.22,0.00], [-0.04,-0.04,0.00], [0.00,0.00,0.43], [0.00,0.00,0.01]]), + (7, [[1.06,-0.19,0.00], [-0.16,-0.17,0.00], [0.27,-0.27,0.00], [-0.10,-0.05,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.01]]), + (8, [[0.88,-0.33,0.00], [-0.21,-0.10,0.00], [0.15,-0.31,0.00], [-0.13,-0.00,0.00], [0.00,0.00,0.41], [0.00,0.00,-0.05]]), + (9, [[0.66,-0.38,0.00], [-0.25,-0.01,0.00], [0.02,-0.27,0.00], [-0.11,0.05,0.00], [0.00,0.00,0.34], [0.00,0.00,-0.09]]), + (10, [[0.39,-0.35,0.00], [-0.22,0.08,0.00], [-0.08,-0.20,0.00], [-0.06,0.08,0.00], [0.00,0.00,0.23], [0.00,0.00,-0.07]]), + (11, [[0.24,-0.24,0.00], [-0.12,0.13,0.00], [-0.12,-0.11,0.00], [-0.00,0.08,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.06]]), + (12, [[0.16,-0.10,0.00], [-0.07,0.16,0.00], [-0.09,-0.04,0.00], [0.00,0.05,0.00], [0.00,0.00,0.11], [0.00,0.00,-0.03]]), + (13, [[0.11,0.08,0.00], [-0.03,0.20,0.00], [-0.12,-0.02,0.00], [-0.06,-0.01,0.00], [0.00,0.00,0.13], [0.00,0.00,0.07]]) ]), 'userAnnotationGroups': [ @@ -118,19 +118,19 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 61.59, -101.05, 1152.90 ], [ 0.44, -2.86, -3.86 ], [ 11.30, -0.23, 1.46 ], [ 15.70, -3.03, 2.83 ], [ -0.85, -7.44, 5.42 ], [ -5.75, -22.46, 14.95 ] ] ), - (2, [[ 61.99, -104.31, 1148.31 ], [ 0.36, -3.66, -5.31 ], [ 24.17, -2.49, 3.34 ], [ 10.04, -1.49, 0.93 ], [ -4.92, -25.06, 16.91 ], [ -2.38, -12.78, 8.03 ] ] ), - (3, [[ 62.28, -108.34, 1142.26 ], [ 0.25, -4.60, -7.04 ], [ 30.56, -2.99, 3.04 ], [ 5.72, -0.45, -0.07 ], [ -5.13, -31.61, 20.49 ], [ -0.21, -5.09, 2.60 ] ] ), - (4, [[ 62.47, -113.50, 1134.22 ], [ 0.31, -6.15, -9.74 ], [ 35.40, -3.37, 3.27 ], [ 4.54, -0.49, 0.32 ], [ -5.33, -34.80, 21.80 ], [ -0.38, -3.01, 1.22 ] ] ), - (5, [[ 62.94, -120.61, 1122.78 ], [ 0.45, -8.60, -13.99 ], [ 39.52, -4.01, 3.73 ], [ 3.19, -0.59, -0.29 ], [ -5.97, -37.56, 22.89 ], [ -0.10, -1.22, 0.55 ] ] ), - (6, [[ 63.32, -130.67, 1106.22 ], [ -0.18, -10.49, -16.96 ], [ 41.37, -4.52, 2.35 ], [ 0.50, -2.47, -4.03 ], [ -5.29, -36.56, 22.66 ], [ 0.26, 0.76, 0.24 ] ] ), - (7, [[ 62.54, -141.56, 1088.91 ], [ -4.62, -11.40, -18.64 ], [ 40.43, -9.06, -4.49 ], [ -4.50, -6.38, -11.05 ], [ -5.48, -36.05, 23.41 ], [ 0.77, 0.60, 1.05 ] ] ), - (8, [[ 53.67, -152.88, 1069.82 ], [ -15.96, -9.81, -16.27 ], [ 31.73, -17.62, -20.50 ], [ -14.93, -3.76, -8.28 ], [ -3.58, -35.33, 24.82 ], [ 2.03, 4.35, -1.23 ] ] ), - (9, [[ 32.23, -159.89, 1058.56 ], [ -22.29, -4.56, -7.46 ], [ 10.24, -16.32, -20.63 ], [ -15.75, 1.84, 1.75 ], [ -1.41, -27.16, 20.79 ], [ 1.20, 8.62, -5.08 ] ] ), - (10, [[ 10.36, -162.05, 1054.83 ], [ -21.09, 1.02, -0.27 ], [ -0.46, -14.00, -17.23 ], [ -8.02, 3.09, 5.32 ], [ -1.07, -18.15, 14.78 ], [ -1.00, 7.50, -3.26 ] ] ), - (11, [[ -8.74, -158.28, 1057.63 ], [ -14.76, 6.59, 2.22 ], [ -6.11, -10.23, -10.22 ], [ -2.40, 4.12, 5.11 ], [ -3.26, -12.00, 13.95 ], [ -1.43, 6.62, -3.36 ] ] ), - (12, [[-18.83, -150.69, 1059.20 ], [ -11.48, 11.37, 1.06 ], [ -6.41, -5.88, -6.34 ], [ -0.42, 3.10, 2.58 ], [ -4.20, -5.07, 8.95 ], [ -1.38, 4.80, -2.40 ] ] ), - (13, [[-30.74, -135.24, 1059.32 ], [ -12.23, 19.36, -0.81 ], [ -7.02, -4.68, -5.74 ], [ -0.80, -0.69, -1.38 ], [ -6.25, -3.51, 10.51 ], [ -2.73, -1.67, 5.52 ] ] ) + (1, [[61.590,-101.050,1152.900], [0.442,-2.863,-3.864], [11.300,-0.230,1.460], [15.701,-3.029,2.832], [-0.850,-7.440,5.420], [-5.756,-22.456,14.946]]), + (2, [[61.990,-104.310,1148.310], [0.358,-3.656,-5.314], [24.170,-2.490,3.340], [10.039,-1.491,0.928], [-4.920,-25.060,16.910], [-2.384,-12.784,8.034]]), + (3, [[62.280,-108.340,1142.260], [0.251,-4.603,-7.040], [30.560,-2.990,3.040], [5.720,-0.448,-0.071], [-5.130,-31.610,20.490], [-0.206,-5.098,2.599]]), + (4, [[62.470,-113.500,1134.220], [0.315,-6.148,-9.733], [35.400,-3.370,3.270], [4.541,-0.488,0.325], [-5.330,-34.800,21.800], [-0.383,-3.012,1.219]]), + (5, [[62.940,-120.610,1122.780], [0.448,-8.598,-13.993], [39.520,-4.010,3.730], [3.189,-0.587,-0.295], [-5.970,-37.560,22.890], [-0.099,-1.218,0.549]]), + (6, [[63.320,-130.670,1106.220], [-0.184,-10.489,-16.967], [41.370,-4.520,2.350], [0.495,-2.468,-4.032], [-5.290,-36.560,22.660], [0.257,0.762,0.246]]), + (7, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.801], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), + (8, [[53.670,-152.880,1069.820], [-15.955,-9.817,-16.265], [30.765,-14.468,-15.598], [-14.187,-3.408,-7.577], [-3.580,-35.330,24.820], [2.031,4.346,-1.238]]), + (9, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.623], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), + (10, [[10.360,-162.050,1054.830], [-21.091,1.023,-0.270], [-0.460,-14.000,-17.230], [-8.753,2.830,4.765], [-1.070,-18.150,14.780], [-1.004,7.491,-3.259]]), + (11, [[-8.740,-158.280,1057.630], [-14.760,6.591,2.223], [-6.110,-10.230,-10.220], [-2.404,4.122,5.111], [-3.260,-12.000,13.950], [-1.432,6.623,-3.360]]), + (12, [[-18.830,-150.690,1059.200], [-11.483,11.369,1.057], [-6.410,-5.880,-6.340], [-0.423,3.102,2.580], [-4.200,-5.070,8.950], [-1.380,4.802,-2.401]]), + (13, [[-30.740,-135.240,1059.320], [-12.232,19.364,-0.810], [-7.020,-4.680,-5.740], [-0.797,-0.702,-1.380], [-6.250,-3.510,10.510], [-2.720,-1.682,5.521]]) ]), 'userAnnotationGroups': [ @@ -180,18 +180,18 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 1.70, 0.60, 0.00 ], [ 0.04, -0.05, 0.00 ], [ 0.05, 0.04, 0.00 ], [ 0.14, 0.01, 0.00 ], [ 0.00, 0.00, 0.04 ], [ 0.00, 0.00, 0.13 ] ] ), - (2, [ [ 1.73, 0.52, 0.00 ], [ 0.01, -0.10, 0.00 ], [ 0.18, 0.02, 0.00 ], [ 0.11, -0.04, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, 0.12 ] ] ), - (3, [ [ 1.72, 0.40, 0.00 ], [ -0.03, -0.14, 0.00 ], [ 0.27, -0.05, 0.00 ], [ 0.08, -0.10, 0.00 ], [ 0.00, 0.00, 0.27 ], [ 0.00, 0.00, 0.10 ] ] ), - (4, [ [ 1.67, 0.24, 0.00 ], [ -0.08, -0.15, 0.00 ], [ 0.33, -0.17, 0.00 ], [ -0.00, -0.14, 0.00 ], [ 0.00, 0.00, 0.35 ], [ 0.00, 0.00, 0.07 ] ] ), - (5, [ [ 1.56, 0.10, 0.00 ], [ -0.14, -0.11, 0.00 ], [ 0.26, -0.32, 0.00 ], [ -0.11, -0.11, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, 0.03 ] ] ), - (6, [ [ 1.39, 0.02, 0.00 ], [ -0.21, -0.05, 0.00 ], [ 0.10, -0.40, 0.00 ], [ -0.17, -0.05, 0.00 ], [ 0.00, 0.00, 0.41 ], [ 0.00, 0.00, 0.01 ] ] ), - (7, [ [ 1.12, 0.01, 0.00 ], [ -0.28, 0.06, 0.00 ], [ -0.08, -0.42, 0.00 ], [ -0.19, 0.04, 0.00 ], [ 0.00, 0.00, 0.41 ], [ 0.00, 0.00, -0.01 ] ] ), - (8, [ [ 0.86, 0.15, 0.00 ], [ -0.22, 0.21, 0.00 ], [ -0.25, -0.31, 0.00 ], [ -0.10, 0.15, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, -0.05 ] ] ), - (9, [ [ 0.76, 0.37, 0.00 ], [ -0.03, 0.21, 0.00 ], [ -0.24, -0.17, 0.01 ], [ 0.05, 0.12, 0.00 ], [ 0.00, 0.00, 0.32 ], [ 0.00, 0.00, -0.09 ] ] ), - (10, [ [ 0.77, 0.54, 0.00 ], [ 0.01, 0.15, 0.00 ], [ -0.18, -0.06, 0.00 ], [ 0.09, 0.07, 0.00 ], [ 0.00, 0.00, 0.21 ], [ 0.00, 0.00, -0.09 ] ] ), - (11, [ [ 0.80, 0.68, 0.00 ], [ 0.00, 0.13, 0.00 ], [ -0.10, 0.00, 0.00 ], [ 0.04, 0.03, 0.00 ], [ 0.00, 0.00, 0.13 ], [ 0.00, 0.00, -0.04 ] ] ), - (12, [ [ 0.79, 0.81, 0.00 ], [ -0.01, 0.13, 0.00 ], [ -0.11, 0.00, 0.00 ], [ -0.04, -0.03, 0.00 ], [ 0.00, 0.00, 0.12 ], [ 0.00, 0.00, 0.01 ] ] ) + (1, [[1.71,0.60,-0.00], [0.03,-0.06,0.00], [0.07,0.01,-0.00], [0.13,0.01,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), + (2, [[1.73,0.52,0.00], [0.01,-0.10,0.00], [0.19,-0.01,0.00], [0.11,-0.03,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), + (3, [[1.72,0.40,0.00], [-0.03,-0.14,0.00], [0.25,-0.07,0.00], [0.05,-0.09,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), + (4, [[1.67,0.24,0.00], [-0.08,-0.15,0.00], [0.26,-0.19,0.01], [-0.03,-0.13,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), + (5, [[1.56,0.10,0.00], [-0.14,-0.12,0.00], [0.22,-0.31,0.00], [-0.08,-0.10,-0.01], [0.00,0.00,0.38], [0.00,0.00,0.02]]), + (6, [[1.39,0.02,0.00], [-0.23,-0.06,0.00], [0.09,-0.38,0.00], [-0.15,-0.04,-0.00], [0.00,0.00,0.39], [0.00,0.00,0.00]]), + (7, [[1.12,0.01,0.00], [-0.28,0.07,0.00], [-0.09,-0.39,0.00], [-0.18,0.06,0.00], [0.00,0.00,0.38], [0.00,0.00,-0.01]]), + (8, [[0.86,0.15,0.00], [-0.19,0.20,0.00], [-0.28,-0.26,0.00], [-0.09,0.17,0.01], [0.00,0.00,0.36], [0.01,0.00,-0.03]]), + (9, [[0.76,0.37,0.00], [-0.04,0.20,0.00], [-0.29,-0.08,0.01], [0.05,0.13,-0.00], [0.01,0.00,0.32], [-0.00,0.00,-0.08]]), + (10, [[0.77,0.54,0.00], [0.02,0.16,0.00], [-0.19,-0.00,0.00], [0.09,0.03,-0.00], [0.00,-0.00,0.21], [-0.00,0.00,-0.09]]), + (11, [[0.80,0.68,0.00], [0.01,0.14,0.00], [-0.10,0.01,0.00], [0.04,-0.03,0.00], [0.00,-0.00,0.13], [0.00,0.00,-0.04]]), + (12, [[0.79,0.81,0.00], [-0.03,0.12,0.00], [-0.11,-0.03,0.00], [-0.06,-0.05,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) ]), 'userAnnotationGroups': [ @@ -240,18 +240,18 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of elements': 10 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 1.40, 0.39, 0.00 ], [ -0.01, -0.02, 0.00 ], [ 0.05, -0.03, 0.00 ], [ 0.06, -0.02, 0.00 ], [ 0.00, 0.00, 0.08 ], [ 0.00, 0.00, 0.05 ] ] ), - (2, [[ 1.39, 0.37, 0.00 ], [ -0.04, -0.07, 0.00 ], [ 0.13, -0.06, 0.00 ], [ 0.09, -0.04, 0.00 ], [ 0.00, 0.00, 0.15 ], [ 0.00, 0.00, 0.08 ] ] ), - (3, [[ 1.36, 0.30, 0.00 ], [ -0.06, -0.13, 0.00 ], [ 0.25, -0.13, 0.00 ], [ 0.11, -0.06, 0.00 ], [ 0.00, 0.00, 0.28 ], [ 0.00, 0.00, 0.12 ] ] ), - (4, [[ 1.29, 0.17, 0.00 ], [ -0.09, -0.17, 0.00 ], [ 0.35, -0.18, 0.00 ], [ 0.06, -0.04, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, 0.06 ] ] ), - (5, [[ 1.20, 0.00, 0.00 ], [ -0.16, -0.29, 0.00 ], [ 0.37, -0.20, 0.00 ], [ 0.00, -0.03, 0.00 ], [ 0.00, 0.00, 0.39 ], [ 0.00, 0.00, 0.01 ] ] ), - (6, [[ 1.09, -0.18, 0.00 ], [ -0.14, -0.21, 0.00 ], [ 0.36, -0.23, 0.00 ], [ -0.05, -0.05, 0.00 ], [ 0.00, 0.00, 0.40 ], [ 0.00, 0.00, -0.01 ] ] ), - (7, [[ 0.92, -0.42, 0.00 ], [ -0.23, -0.17, 0.00 ], [ 0.24, -0.31, 0.00 ], [ -0.16, -0.06, 0.00 ], [ 0.00, 0.00, 0.37 ], [ 0.00, 0.00, -0.04 ] ] ), - (8, [[ 0.66, -0.51, 0.00 ], [ -0.29, 0.02, 0.00 ], [ 0.04, -0.35, 0.00 ], [ -0.20, 0.06, 0.00 ], [ 0.00, 0.00, 0.31 ], [ 0.00, 0.00, -0.10 ] ] ), - (9, [[ 0.41, -0.37, 0.00 ], [ -0.17, 0.23, 0.00 ], [ -0.15, -0.19, 0.00 ], [ -0.05, 0.16, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, -0.09 ] ] ), - (10, [[ 0.35, -0.11, 0.00 ], [ -0.10, 0.22, 0.00 ], [ -0.07, -0.06, 0.00 ], [ 0.03, 0.05, 0.00 ], [ 0.00, 0.00, 0.09 ], [ 0.00, 0.00, -0.02 ] ] ), - (11, [[ 0.23, 0.05, 0.00 ], [ -0.14, 0.10, 0.00 ], [ -0.05, -0.07, 0.00 ], [ -0.03, -0.10, 0.00 ], [ 0.00, 0.00, 0.09 ], [ 0.00, 0.00, 0.01 ] ] ) + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[1.40,0.39,0.00], [-0.00,-0.01,-0.00], [0.05,-0.02,0.00], [0.07,-0.05,0.00], [0.00,0.00,0.08], [0.00,0.00,0.06]]), + (2, [[1.39,0.37,0.00], [-0.02,-0.05,0.00], [0.13,-0.07,0.00], [0.09,-0.05,0.00], [0.00,0.00,0.15], [0.00,0.00,0.08]]), + (3, [[1.35,0.29,0.00], [-0.05,-0.10,0.00], [0.25,-0.13,0.00], [0.11,-0.06,0.00], [0.00,0.00,0.28], [0.00,0.00,0.12]]), + (4, [[1.29,0.17,0.00], [-0.07,-0.15,0.00], [0.35,-0.18,0.00], [0.06,-0.05,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), + (5, [[1.20,0.00,0.00], [-0.10,-0.18,0.00], [0.36,-0.23,0.00], [0.01,-0.03,0.00], [0.00,0.00,0.40], [0.00,0.00,0.01]]), + (6, [[1.09,-0.19,0.00], [-0.14,-0.21,0.00], [0.36,-0.23,0.00], [-0.05,-0.03,0.00], [0.00,0.00,0.40], [0.00,0.00,-0.01]]), + (7, [[0.92,-0.42,0.00], [-0.23,-0.17,0.00], [0.24,-0.31,0.00], [-0.18,-0.04,0.00], [0.00,0.00,0.37], [0.00,0.00,-0.05]]), + (8, [[0.66,-0.51,0.00], [-0.29,0.03,0.00], [0.01,-0.32,-0.00], [-0.21,0.05,0.00], [0.00,0.00,0.31], [0.00,0.00,-0.09]]), + (9, [[0.41,-0.37,0.00], [-0.17,0.23,0.00], [-0.17,-0.21,0.00], [-0.03,0.13,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.11]]), + (10, [[0.35,-0.11,0.00], [-0.10,0.21,0.00], [-0.07,-0.06,0.00], [0.05,0.06,0.00], [0.00,0.00,0.09], [0.00,0.00,-0.04]]), + (11, [[0.23,0.05,0.00], [-0.13,0.10,0.00], [-0.05,-0.07,0.00], [-0.01,-0.08,0.00], [0.00,0.00,0.09], [0.00,0.00,0.04]]) ]), 'userAnnotationGroups': [ @@ -301,19 +301,19 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[ 1.67, 0.64, 0.00 ], [ 0.00, -0.03, 0.00 ], [ 0.07, 0.01, 0.00 ], [ -0.17, -0.03, 0.00 ], [ 0.00, 0.00, 0.08 ], [ 0.00, 0.00, -0.24 ] ] ), - (2, [[ 1.67, 0.57, 0.00 ], [ 0.00, -0.11, 0.00 ], [ 0.18, 0.01, 0.00 ], [ -0.03, -0.05, 0.00 ], [ 0.00, 0.00, 0.16 ], [ 0.00, 0.00, -0.08 ] ] ), - (3, [[ 1.66, 0.43, 0.00 ], [ -0.03, -0.15, 0.00 ], [ 0.31, -0.07, 0.00 ], [ 0.09, -0.09, 0.00 ], [ 0.00, 0.00, 0.27 ], [ 0.00, 0.00, 0.09 ] ] ), - (4, [[ 1.60, 0.27, 0.00 ], [ -0.08, -0.15, 0.00 ], [ 0.35, -0.18, 0.00 ], [ -0.01, -0.12, 0.00 ], [ 0.00, 0.00, 0.33 ], [ 0.00, 0.00, 0.05 ] ] ), - (5, [[ 1.51, 0.14, 0.00 ], [ -0.12, -0.11, 0.00 ], [ 0.30, -0.32, 0.00 ], [ -0.09, -0.11, 0.00 ], [ 0.00, 0.00, 0.37 ], [ 0.00, 0.00, 0.02 ] ] ), - (6, [[ 1.37, 0.05, 0.00 ], [ -0.16, -0.07, 0.00 ], [ 0.18, -0.39, 0.00 ], [ -0.12, -0.06, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, 0.01 ] ] ), - (7, [[ 1.20, 0.00, 0.00 ], [ -0.20, -0.01, 0.00 ], [ 0.05, -0.44, 0.00 ], [ -0.26, -0.03, 0.00 ], [ 0.00, 0.00, 0.38 ], [ 0.00, 0.00, -0.02 ] ] ), - (8, [[ 0.98, 0.04, 0.00 ], [ -0.21, 0.09, 0.00 ], [ -0.15, -0.41, 0.00 ], [ -0.18, 0.08, 0.00 ], [ 0.00, 0.00, 0.36 ], [ 0.00, 0.00, -0.02 ] ] ), - (9, [[ 0.79, 0.17, 0.00 ], [ -0.15, 0.18, 0.00 ], [ -0.25, -0.29, 0.00 ], [ -0.00, 0.15, 0.00 ], [ 0.00, 0.00, 0.33 ], [ 0.00, 0.00, -0.05 ] ] ), - (10, [[ 0.69, 0.38, 0.00 ], [ -0.05, 0.21, 0.00 ], [ -0.22, -0.17, 0.00 ], [ 0.04, 0.18, 0.00 ], [ 0.00, 0.00, 0.27 ], [ 0.00, 0.00, -0.11 ] ] ), - (11, [[ 0.69, 0.57, 0.00 ], [ -0.02, 0.16, 0.00 ], [ -0.16, -0.03, 0.00 ], [ 0.09, 0.03, 0.00 ], [ 0.00, 0.00, 0.12 ], [ 0.00, 0.00, -0.04 ] ] ), - (12, [[ 0.66, 0.69, 0.00 ], [ -0.04, 0.12, 0.00 ], [ -0.11, -0.04, 0.00 ], [ 0.01, -0.02, 0.00 ], [ 0.00, 0.00, 0.12 ], [ 0.00, 0.00, 0.01 ] ] ), - (13, [[ 0.62, 0.80, 0.00 ], [ -0.04, 0.10, 0.00 ], [ -0.12, -0.07, 0.00 ], [ -0.05, -0.05, 0.00 ], [ 0.00, 0.00, 0.15 ], [ 0.00, 0.00, -0.01 ] ] ) + (1, [[1.670,0.640,0.000], [0.004,-0.035,0.000], [0.060,0.000,0.000], [0.117,0.020,0.000], [-0.000,0.000,0.080], [0.000,0.000,0.077]]), + (2, [[1.670,0.570,0.000], [-0.004,-0.105,0.000], [0.180,0.000,0.000], [0.123,-0.020,0.000], [-0.000,0.000,0.160], [0.000,0.000,0.083]]), + (3, [[1.660,0.430,0.000], [-0.033,-0.152,0.000], [0.310,-0.060,0.000], [0.080,-0.087,0.000], [0.000,0.000,0.250], [0.000,0.000,0.072]]), + (4, [[1.600,0.270,0.000], [-0.077,-0.146,0.000], [0.330,-0.180,0.000], [-0.024,-0.117,0.001], [0.000,0.000,0.300], [0.000,0.000,0.040]]), + (5, [[1.510,0.140,0.000], [-0.116,-0.118,0.000], [0.266,-0.295,0.001], [-0.086,-0.103,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), + (6, [[1.370,0.040,0.000], [-0.159,-0.072,0.000], [0.157,-0.384,-0.000], [-0.123,-0.063,-0.001], [0.000,0.000,0.360], [0.000,0.000,0.015]]), + (7, [[1.200,0.000,0.000], [-0.200,-0.005,0.000], [0.020,-0.420,0.000], [-0.156,-0.003,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), + (8, [[0.980,0.040,0.000], [-0.212,0.087,0.000], [-0.160,-0.380,0.000], [-0.155,0.074,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), + (9, [[0.790,0.170,0.000], [-0.152,0.177,0.000], [-0.290,-0.270,0.000], [-0.060,0.120,0.005], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), + (10, [[0.690,0.380,0.000], [-0.047,0.208,0.000], [-0.280,-0.140,0.010], [0.076,0.108,-0.001], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), + (11, [[0.690,0.570,-0.000], [-0.019,0.156,0.000], [-0.150,-0.050,0.000], [0.075,0.042,-0.004], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), + (12, [[0.660,0.690,0.000], [-0.035,0.115,0.000], [-0.110,-0.040,0.000], [0.009,-0.000,0.000], [0.000,0.000,0.120], [0.000,0.000,0.015]]), + (13, [[0.620,0.800,0.000], [-0.045,0.105,0.000], [-0.130,-0.050,0.000], [-0.049,-0.020,0.000], [0.000,0.000,0.150], [0.000,0.000,0.045]]) ]), 'userAnnotationGroups': [ @@ -372,13 +372,13 @@ class MeshType_3d_stomach1(Scaffold_base): (7, [[1.30,0.00,0.00], [-0.19,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), (8, [[1.10,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), (9, [[0.90,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), - (10, [[0.70,0.00,0.00], [-0.18,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.04,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.04]]), + (10, [[0.70,0.00,0.00], [-0.18,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.00]]), (11, [[0.55,0.00,0.00], [-0.15,0.00,0.00], [0.00,-0.44,0.00], [0.00,0.10,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.10]]), (12, [[0.40,0.00,0.00], [-0.12,0.00,0.00], [0.00,-0.31,0.00], [0.00,0.12,0.00], [0.00,0.00,0.31], [0.00,0.00,-0.12]]), - (13, [[0.30,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,-0.05]]), - (14, [[0.20,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,-0.05]]), - (15, [[0.10,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,0.05]]), - (16, [[0.00,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.20], [0.00,0.00,0.05]]) + (13, [[0.30,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]), + (14, [[0.20,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]), + (15, [[0.10,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00, 0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]), + (16, [[0.00,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00, 0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]) ]), 'userAnnotationGroups': [ @@ -650,6 +650,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements around duodenum': 16, 'Number of elements between fundus apex and cardia': 3, 'Number of elements between cardia and duodenum': 6, + 'Target element unit length': 0.1, 'Number of elements through wall': 4, 'Wall thickness': 0.0525, 'Mucosa relative thickness': 0.55, @@ -718,6 +719,7 @@ def getOrderedOptionNames(): 'Number of elements around duodenum', 'Number of elements between fundus apex and cardia', 'Number of elements between cardia and duodenum', + 'Target element unit length', 'Number of elements through wall', 'Wall thickness', 'Mucosa relative thickness', @@ -843,10 +845,10 @@ def generateBaseMesh(cls, region, options): # Geometric coordinates fm = region.getFieldmodule() - coordinates = findOrCreateFieldCoordinates(fm) + coordinates = find_or_create_field_coordinates(fm) geometricCentralPath = StomachCentralPath(region, geometricCentralPath, stomachTermsAlong) - geometricCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path.exf") + # geometricCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path.exf") arcLengthOfGroupsAlong = geometricCentralPath.arcLengthOfGroupsAlong # Pre-calculate element numbers in each group @@ -882,78 +884,78 @@ def generateBaseMesh(cls, region, options): options=options, nodeIdentifier=1, elementIdentifier=1, splitCoordinates=False, materialCoordinates=False) - # Material coordinates - stomach_coordinates = findOrCreateFieldCoordinates(fm, name="stomach coordinates") - allAnnotationGroupsMaterial = [] - tmp_region = region.createRegion() - tmp_fm = tmp_region.getFieldmodule() - with ChangeManager(tmp_fm): - tmp_stomach_coordinates = findOrCreateFieldCoordinates(tmp_fm, name="stomach coordinates") - - materialCentralPath = StomachCentralPath(tmp_region, materialCentralPath, stomachTermsAlong) - materialCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path_material.exf") - - allAnnotationGroupsMaterial, nextNodeIdentifier, nextElementIdentifier = \ - createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, - allAnnotationGroupsMaterial, elementCountGroupList, - centralPath=materialCentralPath, options=options, nodeIdentifier=1, - elementIdentifier=1, splitCoordinates=False, materialCoordinates=True) - - # Write two coordinates - sir = tmp_region.createStreaminformationRegion() - srm = sir.createStreamresourceMemory() - tmp_region.write(sir) - result, buffer = srm.getBuffer() - - sir = region.createStreaminformationRegion() - srm = sir.createStreamresourceMemoryBuffer(buffer) - region.read(sir) - - del srm - del sir - del tmp_stomach_coordinates - del tmp_fm - del tmp_region - - # Create markers - markerTermNameStomachCoordinatesMap = { - 'body-antrum junction along the greater curvature on luminal surface': [0.6020919166990195, -0.45004378032192227, 0.0], - 'body-antrum junction along the greater curvature on serosa': [0.6, -0.5, 0.0], - 'distal point of lower esophageal sphincter serosa on the greater curvature of stomach': [1.280068326927052, 0.7999733714717442, 4.9153708368810965e-16], - 'distal point of lower esophageal sphincter serosa on the lesser curvature of stomach': [1.1200683310311637, 0.8000096111703247, 5.132730495672042e-16], - 'esophagogastric junction along the greater curvature on luminal surface': [1.3499430436270714, 0.44878481258293096, -4.212552457001039e-17], - 'esophagogastric junction along the greater curvature on serosa': [1.3499935896233386, 0.4987847870339471, -2.4350160282618435e-17], - 'esophagogastric junction along the lesser curvature on luminal surface': [1.0489058130975502, 0.4491717442850351, 3.0345621453573164e-16], - 'esophagogastric junction along the lesser curvature on serosa': [1.050012637401148, 0.4991433628042418, 2.8296958630895795e-16], - 'gastroduodenal junction along the greater curvature on luminal surface': [0.2, -0.15, 0.0], - 'gastroduodenal junction along the greater curvature on serosa': [0.2, -0.2, 0.0], - 'gastroduodenal junction along the lesser curvature on luminal surface': [0.2, 0.15, 0.0], - 'gastroduodenal junction along the lesser curvature on serosa': [0.20, 0.20, 0.00], - 'limiting ridge at the greater curvature on the luminal surface' if limitingRidge else - 'fundus-body junction along the greater curvature on luminal surface': [1.1997241080276948, -0.4500013598322351, -0.0002446732391805909], - 'limiting ridge at the greater curvature on serosa' if limitingRidge else - 'fundus-body junction along the greater curvature on serosa': [1.2, -0.5, 0.0] - } - if elementsCountThroughWall == 4: - markerTermNameStomachCoordinatesCMLMMap = { - 'body-antrum junction along the greater curvature on circular-longitudinal muscle interface': [0.6005229791747548, -0.48751094508048054, 0.0], - 'esophagogastric junction along the greater curvature on circular-longitudinal muscle interface': [1.349980953124272, 0.4862847934211931, -2.8794001354466424e-17], - 'esophagogastric junction along the lesser curvature on circular-longitudinal muscle interface': [1.0497365634804512, 0.4866625412064305, 3.2195156437946623e-16], - 'gastroduodenal junction along the greater curvature on circular-longitudinal muscle interface': [0.2, -0.1875, 0.0], - 'gastroduodenal junction along the lesser curvature on circular-longitudinal muscle interface': [0.2, 0.1875, 0.0], - 'limiting ridge at the greater curvature on the circular-longitudinal muscle interface' if limitingRidge - else 'fundus-body junction along the greater curvature on circular-longitudinal muscle interface': [1.199934138287874, -0.48750032317766967, -6.116839191743296e-05] - } - markerTermNameStomachCoordinatesMap.update(markerTermNameStomachCoordinatesCMLMMap) - - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) - - for termName, stomachCoordinatesValues in markerTermNameStomachCoordinatesMap.items(): - annotationGroup = findOrCreateAnnotationGroupForTerm( - allAnnotationGroups, region, get_stomach_term(termName), isMarker=True) - annotationGroup.createMarkerNode(nodeIdentifier, stomach_coordinates, stomachCoordinatesValues) - nodeIdentifier += 1 + # # Material coordinates + # stomach_coordinates = find_or_create_field_coordinates(fm, name="stomach coordinates") + # allAnnotationGroupsMaterial = [] + # tmp_region = region.createRegion() + # tmp_fm = tmp_region.getFieldmodule() + # with ChangeManager(tmp_fm): + # tmp_stomach_coordinates = find_or_create_field_coordinates(tmp_fm, name="stomach coordinates") + # + # materialCentralPath = StomachCentralPath(tmp_region, materialCentralPath, stomachTermsAlong) + # materialCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path_material.exf") + # + # allAnnotationGroupsMaterial, nextNodeIdentifier, nextElementIdentifier = \ + # createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, + # allAnnotationGroupsMaterial, elementCountGroupList, + # centralPath=materialCentralPath, options=options, nodeIdentifier=1, + # elementIdentifier=1, splitCoordinates=False, materialCoordinates=True) + # + # # Write two coordinates + # sir = tmp_region.createStreaminformationRegion() + # srm = sir.createStreamresourceMemory() + # tmp_region.write(sir) + # result, buffer = srm.getBuffer() + # + # sir = region.createStreaminformationRegion() + # srm = sir.createStreamresourceMemoryBuffer(buffer) + # region.read(sir) + # + # del srm + # del sir + # del tmp_stomach_coordinates + # del tmp_fm + # del tmp_region + + # # Create markers + # markerTermNameStomachCoordinatesMap = { + # 'body-antrum junction along the greater curvature on luminal surface': [0.6020919166990195, -0.45004378032192227, 0.0], + # 'body-antrum junction along the greater curvature on serosa': [0.6, -0.5, 0.0], + # 'distal point of lower esophageal sphincter serosa on the greater curvature of stomach': [1.280068326927052, 0.7999733714717442, 4.9153708368810965e-16], + # 'distal point of lower esophageal sphincter serosa on the lesser curvature of stomach': [1.1200683310311637, 0.8000096111703247, 5.132730495672042e-16], + # 'esophagogastric junction along the greater curvature on luminal surface': [1.3499430436270714, 0.44878481258293096, -4.212552457001039e-17], + # 'esophagogastric junction along the greater curvature on serosa': [1.3499935896233386, 0.4987847870339471, -2.4350160282618435e-17], + # 'esophagogastric junction along the lesser curvature on luminal surface': [1.0489058130975502, 0.4491717442850351, 3.0345621453573164e-16], + # 'esophagogastric junction along the lesser curvature on serosa': [1.050012637401148, 0.4991433628042418, 2.8296958630895795e-16], + # 'gastroduodenal junction along the greater curvature on luminal surface': [0.2, -0.15, 0.0], + # 'gastroduodenal junction along the greater curvature on serosa': [0.2, -0.2, 0.0], + # 'gastroduodenal junction along the lesser curvature on luminal surface': [0.2, 0.15, 0.0], + # 'gastroduodenal junction along the lesser curvature on serosa': [0.20, 0.20, 0.00], + # 'limiting ridge at the greater curvature on the luminal surface' if limitingRidge else + # 'fundus-body junction along the greater curvature on luminal surface': [1.1997241080276948, -0.4500013598322351, -0.0002446732391805909], + # 'limiting ridge at the greater curvature on serosa' if limitingRidge else + # 'fundus-body junction along the greater curvature on serosa': [1.2, -0.5, 0.0] + # } + # if elementsCountThroughWall == 4: + # markerTermNameStomachCoordinatesCMLMMap = { + # 'body-antrum junction along the greater curvature on circular-longitudinal muscle interface': [0.6005229791747548, -0.48751094508048054, 0.0], + # 'esophagogastric junction along the greater curvature on circular-longitudinal muscle interface': [1.349980953124272, 0.4862847934211931, -2.8794001354466424e-17], + # 'esophagogastric junction along the lesser curvature on circular-longitudinal muscle interface': [1.0497365634804512, 0.4866625412064305, 3.2195156437946623e-16], + # 'gastroduodenal junction along the greater curvature on circular-longitudinal muscle interface': [0.2, -0.1875, 0.0], + # 'gastroduodenal junction along the lesser curvature on circular-longitudinal muscle interface': [0.2, 0.1875, 0.0], + # 'limiting ridge at the greater curvature on the circular-longitudinal muscle interface' if limitingRidge + # else 'fundus-body junction along the greater curvature on circular-longitudinal muscle interface': [1.199934138287874, -0.48750032317766967, -6.116839191743296e-05] + # } + # markerTermNameStomachCoordinatesMap.update(markerTermNameStomachCoordinatesCMLMMap) + # + # nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + # nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) + # + # for termName, stomachCoordinatesValues in markerTermNameStomachCoordinatesMap.items(): + # annotationGroup = findOrCreateAnnotationGroupForTerm( + # allAnnotationGroups, region, get_stomach_term(termName), isMarker=True) + # annotationGroup.createMarkerNode(nodeIdentifier, stomach_coordinates, stomachCoordinatesValues) + # nodeIdentifier += 1 return allAnnotationGroups, None @@ -972,257 +974,257 @@ def refineMesh(cls, meshrefinement, options): refineElementsCountThroughWall) return - @classmethod - def defineFaceAnnotations(cls, region, options, annotationGroups): - """ - Add face annotation groups from the highest dimension mesh. - Must have defined faces and added subelements for highest dimension groups. - :param region: Zinc region containing model. - :param options: Dict containing options. See getDefaultOptions(). - :param annotationGroups: List of annotation groups for top-level elements. - New face annotation groups are appended to this list. - """ - - limitingRidge = options['Limiting ridge'] - elementsCountThroughWall = options['Number of elements through wall'] - - stomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("stomach")) - dorsalStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("dorsal stomach")) - ventralStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("ventral stomach")) - bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("body of stomach")) - cardiaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("cardia of stomach")) - duodenumGroup = getAnnotationGroupForTerm(annotationGroups, get_smallintestine_term("duodenum")) - fundusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("fundus of stomach")) - antrumGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric antrum")) - pylorusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric canal")) - esoGroup = getAnnotationGroupForTerm(annotationGroups, get_esophagus_term("esophagus")) - nearLCGroup = getAnnotationGroupForTerm(annotationGroups, - ("elements adjacent to lesser curvature", "None")) - - # Create new groups - stomachLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("luminal surface of stomach")) - stomachSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("serosa of stomach")) - bodyLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("luminal surface of body of stomach")) - bodySerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("serosa of body of stomach")) - cardiaLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term( - "luminal surface of cardia of stomach")) - cardiaSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("serosa of cardia of stomach")) - duodenumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_smallintestine_term("luminal surface of duodenum")) - duodenumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_smallintestine_term("serosa of duodenum")) - esoLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_esophagus_term("luminal surface of esophagus")) - esoSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_esophagus_term("serosa of esophagus")) - fundusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term( - "luminal surface of fundus of stomach")) - fundusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("serosa of fundus of stomach")) - antrumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("luminal surface of pyloric antrum")) - antrumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("serosa of pyloric antrum")) - pylorusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("luminal surface of pyloric canal")) - pylorusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("serosa of pyloric canal")) - gastroduodenalJunctionGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("gastroduodenal junction")) - - fm = region.getFieldmodule() - mesh2d = fm.findMeshByDimension(2) - mesh1d = fm.findMeshByDimension(1) - - is_exterior = fm.createFieldIsExterior() - is_exterior_face_outer = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) - is_exterior_face_inner = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) - - is_gastroduod = fm.createFieldAnd(duodenumGroup.getGroup(), pylorusGroup.getGroup()) - gastroduodenalJunctionGroup.getMeshGroup(mesh2d).addElementsConditional(is_gastroduod) - - is_dorsal = dorsalStomachGroup.getGroup() - is_ventral = ventralStomachGroup.getGroup() - is_curvatures = fm.createFieldAnd(is_dorsal, is_ventral) - - is_nearLC = nearLCGroup.getGroup() - is_lesserCurvature = fm.createFieldAnd(is_curvatures, is_nearLC) - lesserCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("lesser curvature of stomach")) - lesserCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_lesserCurvature) - - is_nearGC = fm.createFieldNot(is_nearLC) - is_greaterCurvature = fm.createFieldAnd(is_curvatures, is_nearGC) - greaterCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("greater curvature of stomach")) - greaterCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_greaterCurvature) - - if elementsCountThroughWall == 4: - CMLMInterfaceGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of stomach")) - circularMuscleGroup = getAnnotationGroupForTerm(annotationGroups, - get_stomach_term("circular muscle layer of stomach")) - longitudinalMuscleGroup = \ - getAnnotationGroupForTerm(annotationGroups, get_stomach_term("longitudinal muscle layer of stomach")) - is_CM = circularMuscleGroup.getGroup() - is_LM = longitudinalMuscleGroup.getGroup() - is_CMLMInterface = fm.createFieldAnd(is_CM, is_LM) - CMLMInterfaceGroup.getMeshGroup(mesh2d).addElementsConditional(is_CMLMInterface) - is_curvatures_CMLM = fm.createFieldAnd(is_curvatures, is_CMLMInterface) - is_greaterCurvature_CMLM = fm.createFieldAnd(is_greaterCurvature, is_CMLMInterface) - is_lesserCurvature_CMLM = fm.createFieldAnd(is_lesserCurvature, is_CMLMInterface) - - dorsalStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of dorsal stomach")) - ventralStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of ventral stomach")) - is_dorsal_CMLM = fm.createFieldAnd(is_dorsal, is_CMLMInterface) - dorsalStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_dorsal_CMLM) - is_ventral_CMLM = fm.createFieldAnd(is_ventral, is_CMLMInterface) - ventralStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_ventral_CMLM) - - gastroduod_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of gastroduodenal junction")) - is_gastroduod_CMLM = fm.createFieldAnd(is_gastroduod, is_CMLMInterface) - gastroduod_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_gastroduod_CMLM) - - bodyCurvaturesCMLMGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of body of stomach along the gastric-omentum attachment")) - duodenumCurvaturesCMLMGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_smallintestine_term("circular-longitudinal muscle interface of " - "first segment of the duodenum along the " - "gastric-omentum attachment")) - esoCurvaturesCMLMGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_esophagus_term( - "circular-longitudinal muscle interface of esophagus along the cut margin")) - fundusCurvaturesCMLMGroup =\ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of fundus of stomach along the greater curvature")) - antrumGreaterCurvatureCMLMGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of pyloric antrum along the greater curvature")) - antrumLesserCurvatureCMLMGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of pyloric antrum along the lesser curvature")) - pylorusGreaterCurvatureCMLMGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of pyloric canal along the greater curvature")) - pylorusLesserCurvatureCMLMGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "circular-longitudinal muscle interface of pyloric canal along the lesser curvature")) - - sectionCurvaturesCMLMGroups = [None, bodyCurvaturesCMLMGroup, None, duodenumCurvaturesCMLMGroup, - esoCurvaturesCMLMGroup, fundusCurvaturesCMLMGroup, - antrumGreaterCurvatureCMLMGroup, pylorusGreaterCurvatureCMLMGroup, - antrumLesserCurvatureCMLMGroup, pylorusLesserCurvatureCMLMGroup] - - sectionGroups = [stomachGroup, bodyGroup, cardiaGroup, duodenumGroup, esoGroup, fundusGroup, antrumGroup, - pylorusGroup] - sectionSerosaGroups = [stomachSerosaGroup, bodySerosaGroup, cardiaSerosaGroup, duodenumSerosaGroup, - esoSerosaGroup, fundusSerosaGroup, antrumSerosaGroup, - pylorusSerosaGroup] - sectionLuminalGroups = [stomachLuminalGroup, bodyLuminalGroup, cardiaLuminalGroup, duodenumLuminalGroup, - esoLuminalGroup, fundusLuminalGroup, antrumLuminalGroup, - pylorusLuminalGroup] - - for i in range(len(sectionGroups)): - is_section = sectionGroups[i].getGroup() - is_sectionSerosa = fm.createFieldAnd(is_section, is_exterior_face_outer) - sectionSerosaGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionSerosa) - is_sectionLuminal = fm.createFieldAnd(is_section, is_exterior_face_inner) - sectionLuminalGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionLuminal) - - if elementsCountThroughWall == 4: - if sectionGroups[i] is antrumGroup or sectionGroups[i] is pylorusGroup: - is_sectionGreaterCurvatureCMLM = fm.createFieldAnd(is_section, is_greaterCurvature_CMLM) - is_sectionLesserCurvatureCMLM = fm.createFieldAnd(is_section, is_lesserCurvature_CMLM) - if sectionCurvaturesCMLMGroups[i]: - sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ - addElementsConditional(is_sectionGreaterCurvatureCMLM) - sectionCurvaturesCMLMGroups[i+2].getMeshGroup(mesh1d). \ - addElementsConditional(is_sectionLesserCurvatureCMLM) - else: - is_sectionCurvaturesCMLM = fm.createFieldAnd(is_section, is_curvatures_CMLM) - if sectionCurvaturesCMLMGroups[i]: - sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ - addElementsConditional(is_sectionCurvaturesCMLM) - - if limitingRidge: - limitingRidgeGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("forestomach-glandular stomach junction")) - innerLimitingRidgeGroup = \ - findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("limiting ridge on luminal surface")) - outerLimitingRidgeGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - get_stomach_term("limiting ridge on serosa")) - - is_antrum = antrumGroup.getGroup() - is_body = bodyGroup.getGroup() - is_cardia = cardiaGroup.getGroup() - is_fundus = fundusGroup.getGroup() - is_limitingRidgeBody = fm.createFieldAnd(is_fundus, is_body) - is_limitingRidgeCardia = fm.createFieldAnd(is_body, is_cardia) - is_limitingRidgeAntrum = fm.createFieldAnd(is_antrum, is_cardia) - is_limitingRidgeBodyCardia = fm.createFieldOr(is_limitingRidgeBody, is_limitingRidgeCardia) - is_limitingRidgeAntrumCardia = fm.createFieldOr(is_limitingRidgeAntrum, is_limitingRidgeCardia) - is_limitingRidge = fm.createFieldOr(is_limitingRidgeBodyCardia, is_limitingRidgeAntrumCardia) - - if elementsCountThroughWall == 4: - mucosaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("mucosa of stomach")) - is_mucosa = mucosaGroup.getGroup() - is_bodyMucosa = fm.createFieldAnd(is_body, is_mucosa) - is_antrumMucosa = fm.createFieldAnd(is_antrum, is_mucosa) - is_bodyAntrumMucosa = fm.createFieldOr(is_bodyMucosa, is_antrumMucosa) - - is_xi1Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), - fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) - is_xi1All = fm.createFieldOr(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), - fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) - is_xi1BodyAntrumMucosaAll = fm.createFieldAnd(is_bodyAntrumMucosa, is_xi1All) - is_limitingRidgeAroundCardia = fm.createFieldAnd(is_xi1BodyAntrumMucosaAll, - fm.createFieldNot(is_xi1Interior)) - - is_xi2Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), - fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_1)) - is_xi2ZeroBodyMucosa = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), is_bodyMucosa) - is_limitingRidgeBodyBoundary = fm.createFieldAnd(is_xi2ZeroBodyMucosa, - fm.createFieldNot(is_xi2Interior)) - - is_limitingRidgeMucosa = fm.createFieldOr(is_limitingRidgeAroundCardia, is_limitingRidgeBodyBoundary) - is_limitingRidge = fm.createFieldOr(is_limitingRidge, is_limitingRidgeMucosa) - - limitingRidgeGroup.getMeshGroup(mesh2d).addElementsConditional(is_limitingRidge) - - is_xi3Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0), - fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) - is_xi3ZeroLimitingRidge = fm.createFieldAnd(is_limitingRidge, - fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) - is_xi3OneLimitingRidge = fm.createFieldAnd(is_limitingRidge, - fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) - - is_limitingRidgeInner = fm.createFieldAnd(is_xi3ZeroLimitingRidge, fm.createFieldNot(is_xi3Interior)) - innerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeInner) - - is_limitingRidgeOuter = fm.createFieldAnd(is_xi3OneLimitingRidge, fm.createFieldNot(is_xi3Interior)) - outerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeOuter) - - if elementsCountThroughWall == 4: - limitingRidge_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - "limiting ridge on circular-longitudinal muscle interface")) - is_limitingRidgeCMLM = fm.createFieldAnd(is_CMLMInterface, is_limitingRidge) - limitingRidge_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeCMLM) - - annotationGroups.remove(nearLCGroup) + # @classmethod + # def defineFaceAnnotations(cls, region, options, annotationGroups): + # """ + # Add face annotation groups from the highest dimension mesh. + # Must have defined faces and added subelements for highest dimension groups. + # :param region: Zinc region containing model. + # :param options: Dict containing options. See getDefaultOptions(). + # :param annotationGroups: List of annotation groups for top-level elements. + # New face annotation groups are appended to this list. + # """ + # + # limitingRidge = options['Limiting ridge'] + # elementsCountThroughWall = options['Number of elements through wall'] + # + # stomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("stomach")) + # dorsalStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("dorsal stomach")) + # ventralStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("ventral stomach")) + # bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("body of stomach")) + # cardiaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("cardia of stomach")) + # duodenumGroup = getAnnotationGroupForTerm(annotationGroups, get_smallintestine_term("duodenum")) + # fundusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("fundus of stomach")) + # antrumGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric antrum")) + # pylorusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric canal")) + # esoGroup = getAnnotationGroupForTerm(annotationGroups, get_esophagus_term("esophagus")) + # nearLCGroup = getAnnotationGroupForTerm(annotationGroups, + # ("elements adjacent to lesser curvature", "None")) + # + # # Create new groups + # stomachLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("luminal surface of stomach")) + # stomachSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("serosa of stomach")) + # bodyLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("luminal surface of body of stomach")) + # bodySerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("serosa of body of stomach")) + # cardiaLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term( + # "luminal surface of cardia of stomach")) + # cardiaSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("serosa of cardia of stomach")) + # duodenumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_smallintestine_term("luminal surface of duodenum")) + # duodenumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_smallintestine_term("serosa of duodenum")) + # esoLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_esophagus_term("luminal surface of esophagus")) + # esoSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_esophagus_term("serosa of esophagus")) + # fundusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term( + # "luminal surface of fundus of stomach")) + # fundusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("serosa of fundus of stomach")) + # antrumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("luminal surface of pyloric antrum")) + # antrumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("serosa of pyloric antrum")) + # pylorusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("luminal surface of pyloric canal")) + # pylorusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("serosa of pyloric canal")) + # gastroduodenalJunctionGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("gastroduodenal junction")) + # + # fm = region.getFieldmodule() + # mesh2d = fm.findMeshByDimension(2) + # mesh1d = fm.findMeshByDimension(1) + # + # is_exterior = fm.createFieldIsExterior() + # is_exterior_face_outer = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) + # is_exterior_face_inner = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) + # + # is_gastroduod = fm.createFieldAnd(duodenumGroup.getGroup(), pylorusGroup.getGroup()) + # gastroduodenalJunctionGroup.getMeshGroup(mesh2d).addElementsConditional(is_gastroduod) + # + # is_dorsal = dorsalStomachGroup.getGroup() + # is_ventral = ventralStomachGroup.getGroup() + # is_curvatures = fm.createFieldAnd(is_dorsal, is_ventral) + # + # is_nearLC = nearLCGroup.getGroup() + # is_lesserCurvature = fm.createFieldAnd(is_curvatures, is_nearLC) + # lesserCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("lesser curvature of stomach")) + # lesserCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_lesserCurvature) + # + # is_nearGC = fm.createFieldNot(is_nearLC) + # is_greaterCurvature = fm.createFieldAnd(is_curvatures, is_nearGC) + # greaterCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("greater curvature of stomach")) + # greaterCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_greaterCurvature) + # + # if elementsCountThroughWall == 4: + # CMLMInterfaceGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of stomach")) + # circularMuscleGroup = getAnnotationGroupForTerm(annotationGroups, + # get_stomach_term("circular muscle layer of stomach")) + # longitudinalMuscleGroup = \ + # getAnnotationGroupForTerm(annotationGroups, get_stomach_term("longitudinal muscle layer of stomach")) + # is_CM = circularMuscleGroup.getGroup() + # is_LM = longitudinalMuscleGroup.getGroup() + # is_CMLMInterface = fm.createFieldAnd(is_CM, is_LM) + # CMLMInterfaceGroup.getMeshGroup(mesh2d).addElementsConditional(is_CMLMInterface) + # is_curvatures_CMLM = fm.createFieldAnd(is_curvatures, is_CMLMInterface) + # is_greaterCurvature_CMLM = fm.createFieldAnd(is_greaterCurvature, is_CMLMInterface) + # is_lesserCurvature_CMLM = fm.createFieldAnd(is_lesserCurvature, is_CMLMInterface) + # + # dorsalStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of dorsal stomach")) + # ventralStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of ventral stomach")) + # is_dorsal_CMLM = fm.createFieldAnd(is_dorsal, is_CMLMInterface) + # dorsalStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_dorsal_CMLM) + # is_ventral_CMLM = fm.createFieldAnd(is_ventral, is_CMLMInterface) + # ventralStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_ventral_CMLM) + # + # gastroduod_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of gastroduodenal junction")) + # is_gastroduod_CMLM = fm.createFieldAnd(is_gastroduod, is_CMLMInterface) + # gastroduod_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_gastroduod_CMLM) + # + # bodyCurvaturesCMLMGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of body of stomach along the gastric-omentum attachment")) + # duodenumCurvaturesCMLMGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_smallintestine_term("circular-longitudinal muscle interface of " + # "first segment of the duodenum along the " + # "gastric-omentum attachment")) + # esoCurvaturesCMLMGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_esophagus_term( + # "circular-longitudinal muscle interface of esophagus along the cut margin")) + # fundusCurvaturesCMLMGroup =\ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of fundus of stomach along the greater curvature")) + # antrumGreaterCurvatureCMLMGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of pyloric antrum along the greater curvature")) + # antrumLesserCurvatureCMLMGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of pyloric antrum along the lesser curvature")) + # pylorusGreaterCurvatureCMLMGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of pyloric canal along the greater curvature")) + # pylorusLesserCurvatureCMLMGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "circular-longitudinal muscle interface of pyloric canal along the lesser curvature")) + # + # sectionCurvaturesCMLMGroups = [None, bodyCurvaturesCMLMGroup, None, duodenumCurvaturesCMLMGroup, + # esoCurvaturesCMLMGroup, fundusCurvaturesCMLMGroup, + # antrumGreaterCurvatureCMLMGroup, pylorusGreaterCurvatureCMLMGroup, + # antrumLesserCurvatureCMLMGroup, pylorusLesserCurvatureCMLMGroup] + # + # sectionGroups = [stomachGroup, bodyGroup, cardiaGroup, duodenumGroup, esoGroup, fundusGroup, antrumGroup, + # pylorusGroup] + # sectionSerosaGroups = [stomachSerosaGroup, bodySerosaGroup, cardiaSerosaGroup, duodenumSerosaGroup, + # esoSerosaGroup, fundusSerosaGroup, antrumSerosaGroup, + # pylorusSerosaGroup] + # sectionLuminalGroups = [stomachLuminalGroup, bodyLuminalGroup, cardiaLuminalGroup, duodenumLuminalGroup, + # esoLuminalGroup, fundusLuminalGroup, antrumLuminalGroup, + # pylorusLuminalGroup] + # + # for i in range(len(sectionGroups)): + # is_section = sectionGroups[i].getGroup() + # is_sectionSerosa = fm.createFieldAnd(is_section, is_exterior_face_outer) + # sectionSerosaGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionSerosa) + # is_sectionLuminal = fm.createFieldAnd(is_section, is_exterior_face_inner) + # sectionLuminalGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionLuminal) + # + # if elementsCountThroughWall == 4: + # if sectionGroups[i] is antrumGroup or sectionGroups[i] is pylorusGroup: + # is_sectionGreaterCurvatureCMLM = fm.createFieldAnd(is_section, is_greaterCurvature_CMLM) + # is_sectionLesserCurvatureCMLM = fm.createFieldAnd(is_section, is_lesserCurvature_CMLM) + # if sectionCurvaturesCMLMGroups[i]: + # sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ + # addElementsConditional(is_sectionGreaterCurvatureCMLM) + # sectionCurvaturesCMLMGroups[i+2].getMeshGroup(mesh1d). \ + # addElementsConditional(is_sectionLesserCurvatureCMLM) + # else: + # is_sectionCurvaturesCMLM = fm.createFieldAnd(is_section, is_curvatures_CMLM) + # if sectionCurvaturesCMLMGroups[i]: + # sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ + # addElementsConditional(is_sectionCurvaturesCMLM) + # + # if limitingRidge: + # limitingRidgeGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("forestomach-glandular stomach junction")) + # innerLimitingRidgeGroup = \ + # findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("limiting ridge on luminal surface")) + # outerLimitingRidgeGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + # get_stomach_term("limiting ridge on serosa")) + # + # is_antrum = antrumGroup.getGroup() + # is_body = bodyGroup.getGroup() + # is_cardia = cardiaGroup.getGroup() + # is_fundus = fundusGroup.getGroup() + # is_limitingRidgeBody = fm.createFieldAnd(is_fundus, is_body) + # is_limitingRidgeCardia = fm.createFieldAnd(is_body, is_cardia) + # is_limitingRidgeAntrum = fm.createFieldAnd(is_antrum, is_cardia) + # is_limitingRidgeBodyCardia = fm.createFieldOr(is_limitingRidgeBody, is_limitingRidgeCardia) + # is_limitingRidgeAntrumCardia = fm.createFieldOr(is_limitingRidgeAntrum, is_limitingRidgeCardia) + # is_limitingRidge = fm.createFieldOr(is_limitingRidgeBodyCardia, is_limitingRidgeAntrumCardia) + # + # if elementsCountThroughWall == 4: + # mucosaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("mucosa of stomach")) + # is_mucosa = mucosaGroup.getGroup() + # is_bodyMucosa = fm.createFieldAnd(is_body, is_mucosa) + # is_antrumMucosa = fm.createFieldAnd(is_antrum, is_mucosa) + # is_bodyAntrumMucosa = fm.createFieldOr(is_bodyMucosa, is_antrumMucosa) + # + # is_xi1Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), + # fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) + # is_xi1All = fm.createFieldOr(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), + # fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) + # is_xi1BodyAntrumMucosaAll = fm.createFieldAnd(is_bodyAntrumMucosa, is_xi1All) + # is_limitingRidgeAroundCardia = fm.createFieldAnd(is_xi1BodyAntrumMucosaAll, + # fm.createFieldNot(is_xi1Interior)) + # + # is_xi2Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), + # fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_1)) + # is_xi2ZeroBodyMucosa = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), is_bodyMucosa) + # is_limitingRidgeBodyBoundary = fm.createFieldAnd(is_xi2ZeroBodyMucosa, + # fm.createFieldNot(is_xi2Interior)) + # + # is_limitingRidgeMucosa = fm.createFieldOr(is_limitingRidgeAroundCardia, is_limitingRidgeBodyBoundary) + # is_limitingRidge = fm.createFieldOr(is_limitingRidge, is_limitingRidgeMucosa) + # + # limitingRidgeGroup.getMeshGroup(mesh2d).addElementsConditional(is_limitingRidge) + # + # is_xi3Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0), + # fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) + # is_xi3ZeroLimitingRidge = fm.createFieldAnd(is_limitingRidge, + # fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) + # is_xi3OneLimitingRidge = fm.createFieldAnd(is_limitingRidge, + # fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) + # + # is_limitingRidgeInner = fm.createFieldAnd(is_xi3ZeroLimitingRidge, fm.createFieldNot(is_xi3Interior)) + # innerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeInner) + # + # is_limitingRidgeOuter = fm.createFieldAnd(is_xi3OneLimitingRidge, fm.createFieldNot(is_xi3Interior)) + # outerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeOuter) + # + # if elementsCountThroughWall == 4: + # limitingRidge_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + # "limiting ridge on circular-longitudinal muscle interface")) + # is_limitingRidgeCMLM = fm.createFieldAnd(is_CMLMInterface, is_limitingRidge) + # limitingRidge_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeCMLM) + # + # annotationGroups.remove(nearLCGroup) class StomachCentralPath: """ @@ -1386,6 +1388,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementsCountAroundDuod = options['Number of elements around duodenum'] elementsAlongFundusApexToCardia = options['Number of elements between fundus apex and cardia'] elementsAlongCardiaToDuod = options['Number of elements between cardia and duodenum'] + targetLength = options['Target element unit length'] elementsCountThroughWall = options['Number of elements through wall'] mucosaRelThickness = options['Mucosa relative thickness'] submucosaRelThickness = options['Submucosa relative thickness'] @@ -1513,6 +1516,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio cd3PlusSections = [] cd3MinusSections = [] + targetLengthTS = 0.025 + for i in (list(range(1, len(elementCountGroupList))) + [0]): # start from body, go back to fundus cxGroup = centralPath.cxGroups[i + 1] cd1Group = centralPath.cd1Groups[i + 1] @@ -1521,6 +1526,15 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio cd12Group = centralPath.cd12Groups[i + 1] cd13Group = centralPath.cd13Groups[i + 1] + for n2 in range(len(cxGroup)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxGroup[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd2Group[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd1Group[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, cd3Group[n2]) + nodeIdentifier += 1 + if materialCoordinates and i == len(elementCountGroupList) - 1: for n in range(len(cxGroup)): cd12Group[n] = zero @@ -1528,13 +1542,14 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # Break body into equal sized elements, all others vary smoothly from end derivative of last section # Except for fundus which start at zero derivative and ends at start derivative for body - elementsOutSection = elementCountGroupList[i] + elementsOutSection = math.ceil(arcLengthRatioForGroupsFromFundusApex[i]/targetLengthTS) cxSection, cd1Section, pe, pxi, psf = interp.sampleCubicHermiteCurvesSmooth( cxGroup, cd1Group, elementsOutSection, derivativeMagnitudeStart=None if (i == 1) else 0.0 if (i == 0) else vector.magnitude(cd1Sections[-1][-1]), derivativeMagnitudeEnd=None if (i != 0) else vector.magnitude(cd1Sections[0][0])) cd2Section = interp.interpolateSampleCubicHermite(cd2Group, cd12Group, pe, pxi, psf)[0] cd3Section = interp.interpolateSampleCubicHermite(cd3Group, cd13Group, pe, pxi, psf)[0] + pxiPlus = [xi + deltaXi for xi in pxi] cxPlusSection = interp.interpolateSampleCubicHermite(cxGroup, cd1Group, pe, pxiPlus, psf)[0] cd2PlusSection = interp.interpolateSampleCubicHermite(cd2Group, cd12Group, pe, pxiPlus, psf)[0] @@ -1561,6 +1576,13 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio cxMinusSections, cd2MinusSections, cd3MinusSections]: values.insert(0, values.pop()) + nodeStartEndSections = [] + startNode = 0 + for i in range(len(cxSections)): + endNode = startNode + len(cxSections[i]) - 1 + nodeStartEndSections.append([startNode, endNode]) + startNode = endNode + # Create ellipses cxApex = cxSections[0][0] xApex = [cxApex for n1 in range(elementsCountAroundDuod)] @@ -1598,9 +1620,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio pxPlus = sampleEllipsePoints(cxPlusSections[s][n2], cd2PlusSections[s][n2], cd3PlusSections[s][n2], 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] pxPlus.pop() + pxMinus = sampleEllipsePoints(cxMinusSections[s][n2], cd2MinusSections[s][n2], cd3MinusSections[s][n2], 0.0, math.pi * 2.0, elementsCountAroundDuod)[0] pxMinus.pop() + d2Around = [sub(pxPlus[n], pxMinus[n]) for n in range(len(pxPlus))] d2CurvatureAround = [0.0 for n in range(len(pd1))] @@ -1613,26 +1637,21 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xGEJ = px[elementsAroundHalfDuod] # Scale d1 and d2 at apex - d1EllipseAroundAll[0][0] = \ - vector.setMagnitude(d1EllipseAroundAll[0][0], - interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d1EllipseAroundAll[0][0], - xEllipseAroundAll[1][elementsAroundQuarterDuod], - d2EllipseAroundAll[1][elementsAroundQuarterDuod], True)) - d2EllipseAroundAll[0][0] = \ - vector.setMagnitude(d2EllipseAroundAll[0][0], - interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][0], d2EllipseAroundAll[0][0], - xEllipseAroundAll[1][0], d2EllipseAroundAll[1][0], - True)) + for n in range(len(xEllipseAroundAll[0])): + d1EllipseAroundAll[0][n] = \ + vector.setMagnitude(d1EllipseAroundAll[0][n], + interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][n], d2EllipseAroundAll[0][n], + xEllipseAroundAll[1][n], d2EllipseAroundAll[1][n], + True)) + d2EllipseAroundAll[0][n] = \ + vector.setMagnitude(d2EllipseAroundAll[0][n], + interp.computeCubicHermiteArcLength(xEllipseAroundAll[0][n], d2EllipseAroundAll[0][n], + xEllipseAroundAll[1][n], d2EllipseAroundAll[1][n], + True)) # Create track surface # Find d2 - elementsCountAlongTS = 20 d2Raw = [] - xRawSampled = [] - d2RawSampled = [] - arcLengthsAlongTS = [] - # d2 = zero - for n1 in range(elementsCountAroundDuod): xAlong = [] d2Along = [] @@ -1642,45 +1661,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along, fixAllDirections=True) d2Raw.append(d2Smoothed) - # sample - xAlongSampled, d2AlongSampled = interp.sampleCubicHermiteCurves(xAlong, d2Along, elementsCountAlongTS)[0:2] - xRawSampled.append(xAlongSampled) - d2RawSampled.append(d2AlongSampled) - - if n1 in [elementsAroundQuarterDuod, elementsAroundHalfDuod, - elementsAroundHalfDuod + elementsAroundQuarterDuod]: - arcLength = 0.0 - for n2 in range(len(xAlongSampled) - 1): - arcLength += interp.getCubicHermiteArcLength(xAlongSampled[n2], d2AlongSampled[n2], - xAlongSampled[n2 + 1], d2AlongSampled[n2 + 1]) - arcLengthsAlongTS.append(arcLength) - # Rearrange d2 for n2 in range(len(xEllipseAroundAll)): for n1 in range(elementsCountAroundDuod): d2EllipseAroundAll[n2][n1] = d2Raw[n1][n2] - # Rearrange sampled x and d2 - xAroundTS = [] - d1AroundTS = [[zero for n1 in range(elementsCountAroundDuod)]] - d2AroundTS = [] - - for n2 in range(elementsCountAlongTS + 1): - xAround= [] - d1Around = [] - d2Around = [] - for n1 in range(elementsCountAroundDuod): - xAround.append(xRawSampled[n1][n2]) - d2Around.append(d2RawSampled[n1][n2]) - xAroundTS.append(xAround) - d2AroundTS.append(d2Around) - - if n2: - for n1 in range(elementsCountAroundDuod): - d1Around.append(findDerivativeBetweenPoints(xAround[n1], xAround[(n1 + 1) % elementsCountAroundDuod])) - d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - d1AroundTS.append(d1Around) - # Copy points on lesser curvature before putting annulus xTopCurvature = [] for n2 in range(len(xEllipseAroundAll)): @@ -1690,21 +1675,61 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xTrackSurface = [] d1TrackSurface = [] d2TrackSurface = [] - for n2 in range(len(xAroundTS)): - for n1 in range(elementsCountAroundDuod): - xTrackSurface.append(xAroundTS[n2][n1]) - d1TrackSurface.append(d1AroundTS[n2][n1]) - d2TrackSurface.append(d2AroundTS[n2][n1]) - trackSurfaceStomach = TrackSurface(elementsCountAroundDuod, len(xAroundTS) - 1, + for n2 in range(len(xEllipseAroundAll)): + for n1 in range(len(xEllipseAroundAll[n2])): + xTrackSurface.append(xEllipseAroundAll[n2][n1]) + d1TrackSurface.append(d1EllipseAroundAll[n2][n1]) + d2TrackSurface.append(d2EllipseAroundAll[n2][n1]) + + trackSurfaceStomach = TrackSurface(elementsCountAroundDuod, len(xEllipseAroundAll) - 1, xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) # Visualise track surface - tmpRegion = region.createRegion() - trackSurfaceStomach.generateMesh(tmpRegion) - tmpRegion.getFieldmodule().defineAllFaces() - tmpRegion.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_tracksurface.exf") - del tmpRegion + # tmpRegion = region.createRegion() + # trackSurfaceStomach.generateMesh(tmpRegion) + + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + startNodeIdentifier = nodeIdentifier = max(get_maximum_node_identifier(nodes), 0) + 1 + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + + mesh = fm.findMeshByDimension(2) + elementIdentifier = max(get_maximum_element_identifier(mesh), 0) + 1 + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE) + bicubicHermiteBasis = fm.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) + # remove cross derivative terms + for n in range(4): + eft.setFunctionNumberOfTerms(n * 4 + 4, 0) + elementtemplate.defineField(coordinates, -1, eft) + + fieldcache = fm.createFieldcache() + with ChangeManager(fm): + for n1 in range(len(trackSurfaceStomach.nx)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + fieldcache.setNode(node) + coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, trackSurfaceStomach.nx[n1]) + coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, trackSurfaceStomach.nd1[n1]) + coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, trackSurfaceStomach.nd2[n1]) + nodeIdentifier += 1 + + del n1 + nodesCount1 = trackSurfaceStomach.elementsCount1 + 1 + for e2 in range(trackSurfaceStomach.elementsCount2): + for e1 in range(trackSurfaceStomach.elementsCount1): + nid1 = startNodeIdentifier + e2 * nodesCount1 + e1 + nids = [nid1, nid1 + 1, nid1 + nodesCount1, nid1 + nodesCount1 + 1] + element = mesh.createElement(elementIdentifier, elementtemplate) + element.setNodesByIdentifier(eft, nids) + elementIdentifier += 1 + + # tmpRegion.getFieldmodule().defineAllFaces() + # tmpRegion.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_tracksurface.exf") + # del tmpRegion # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction GEJSettings['Number of elements around ostium'] = elementsCountAroundEso @@ -1744,1322 +1769,1346 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup], wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=coordinates) - stomachStartNode = nextNodeIdentifier - nodeIdentifier = nextNodeIdentifier - elementIdentifier = nextElementIdentifier - - if materialCoordinates: - GEJSettings['Unit scale'] = unitScale - GEJSettings['Ostium diameter'] = ostiumDiameter - GEJSettings['Ostium length'] = ostiumLength - GEJSettings['Ostium wall thickness'] = ostiumWallThickness - GEJSettings['Ostium wall relative thicknesses'] = ostiumWallRelThicknesses - GEJSettings['Vessel inner diameter'] = vesselInnerDiameter - GEJSettings['Vessel wall thickness'] = vesselWallThickness - GEJSettings['Vessel wall relative thicknesses'] = vesselWallRelThicknesses - GEJSettings['Vessel angle 1 degrees'] = vesselAngle1 - GEJSettings['Vessel angle 2 degrees'] = vesselAngle2 - - # Create location of annulus - xAnnulusOuter = [[] for x in range(elementsCountAroundEso)] - xAnnulusOuterPosition = [[] for x in range(elementsCountAroundEso)] - d1AnnulusNorm = [] - d1AnnulusOuter = [] - for n1 in range(elementsCountAroundEso): - normD2 = vector.normalise(o1_d2[-1][n1]) - d1AnnulusNorm.append(normD2) - d1AnnulusOuter.append(vector.setMagnitude(o1_d2[-1][n1], sf)) - x = [o1_x[-1][n1][c] + sf * normD2[c] for c in range(3)] - nearestPosition = trackSurfaceStomach.findNearestPosition(x) - xAnnulusOuterPosition[n1] = nearestPosition - xAnnulusOuter[n1] = trackSurfaceStomach.evaluateCoordinates(nearestPosition) - - d2AnnulusOuter = [] - for n in range(elementsCountAroundEso): - d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundEso]) - d2AnnulusOuter.append(d) - d2AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) - d3Annulus = [] - for n in range(elementsCountAroundEso): - d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) - d3Annulus.append(d3) - annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) - - # Adjust annulus derivatives - # Make d2 on second half of eso point towards duodenum - for n1 in range(elementsAroundHalfEso - 1): - idx = n1 + elementsAroundHalfEso + 1 - rotAxis = d3Annulus[idx] - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - d2 = d2AnnulusOuter[idx] - d2AnnulusOuter[idx] = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + - rotFrame[j][2] * d2[2] for j in range(3)] - - # Make d1 on first half of eso point towards esophagus - for n1 in range(1, elementsAroundHalfEso): - rotAxis = d3Annulus[n1] - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - d1 = d1AnnulusOuter[n1] - d1AnnulusOuter[n1] = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + - rotFrame[j][2] * d1[2] for j in range(3)] - - # Flip d1 and d2 on xAnnulusOuter[0] - d1 = d1AnnulusOuter[0] # original d1 - rotAxis = d3Annulus[0] - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - d1Rot = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] - - d2 = d2AnnulusOuter[0] # original d2 - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - - d2AnnulusOuter[0] = d1Rot # d2 is now d1 - d1AnnulusOuter[0] = d2Rot # d1 is now d2 - curvature = annulusD2Curvature[0] - - # Flip d1 and d2 on xAnnulusOuter[halfEso] - d1 = d1AnnulusOuter[elementsAroundHalfEso] # original d1 - d2 = d2AnnulusOuter[elementsAroundHalfEso] # original d2 - d2AnnulusOuter[elementsAroundHalfEso] = d1 # d2 is now d1 - d1AnnulusOuter[elementsAroundHalfEso] = d2 # d1 is now d2 - curvature = annulusD2Curvature[halfEso] - - # x along GC and LC row - needs to be in 2 parts - # GC - xAlongGCHalfDuod = [] - endGCEsoP2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] - - for n2 in range(len(xEllipseAroundAll)): - xPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) - p2 = trackSurfaceStomach.getProportion(xPosition) - if p2[1] < endGCEsoP2: - # xAlongGCHalfDuod.append(xAroundAllTransformed[n2][elementsAroundHalfDuod if n2 else 0]) - xAlongGCHalfDuod.append(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) - else: - break - - xAlongGCHalfDuod.append(xAnnulusOuter[0]) - - rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * elementsAroundHalfDuod - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) - d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + rotFrame[j][2] * d2Apex[2] for j in range(3)] - - d2AlongGCHalfDuod = [d2ApexRot] - for n2 in range(1, len(xAlongGCHalfDuod) - 1): - d = findDerivativeBetweenPoints(xAlongGCHalfDuod[n2], xAlongGCHalfDuod[n2 + 1]) - d2AlongGCHalfDuod.append(d) - d2AlongGCHalfDuod.append(d2AnnulusOuter[0]) - - xSampledAlongGCHalfDuod, d2SampledAlongGCHalfDuod = \ - interp.sampleCubicHermiteCurvesSmooth(xAlongGCHalfDuod + [o1_x[-1][0]], d2AlongGCHalfDuod + [d2AnnulusOuter[0]], - elementsAlongFundusApexToCardia + 1, - derivativeMagnitudeEnd=vector.magnitude(d2AnnulusOuter[0]))[0:2] - - d2SampledAlongGCHalfDuod = \ - interp.smoothCubicHermiteDerivativesLine(xSampledAlongGCHalfDuod, d2SampledAlongGCHalfDuod, - fixEndDerivative=True) - - xAlongGCHalfDuod = xSampledAlongGCHalfDuod[:-1] - d2AlongGCHalfDuod = d2SampledAlongGCHalfDuod[:-1] - for n2 in range(len(xAlongGCHalfDuod)): - xEllipseAroundAll[n2][elementsAroundHalfDuod] = xAlongGCHalfDuod[n2] - - # LC part - elementsInBody = elementCountGroupList[1] - xAnnulusOuterHalfEsoPosition = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[elementsAroundHalfEso]) - startLCAnnulus = trackSurfaceStomach.getProportion(xAnnulusOuterHalfEsoPosition) - - xAlongLCHalfDuod = [xAnnulusOuter[elementsAroundHalfEso]] - n2IdxEndBody = elementCountGroupList[0] + elementCountGroupList[1] - - if elementsInBody - elementsAroundQuarterEso + 1 > 1: - xPositionEndBody = \ - trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2IdxEndBody][elementsAroundHalfDuod]) - xProportionEndBody = trackSurfaceStomach.getProportion(xPositionEndBody) - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceStomach.createHermiteCurvePoints( - startLCAnnulus[0], startLCAnnulus[1], xProportionEndBody[0], xProportionEndBody[1], - elementsInBody - elementsAroundQuarterEso + 1, derivativeStart=d2AnnulusOuter[elementsAroundHalfEso]) - - nxNew, nd1New = \ - trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, - derivativeMagnitudeStart=vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso]))[0:2] - xAlongLCHalfDuod += nxNew[1:-1] - - for n2 in range(sum(elementCountGroupList) - sum(elementCountGroupList[:2]) + 1): - xAlongLCHalfDuod.append(xEllipseAroundAll[n2IdxEndBody + n2][elementsAroundHalfDuod]) - - d2AlongLCHalfDuod = [d2AnnulusOuter[elementsAroundHalfEso]] - for n2 in range(1, len(xAlongLCHalfDuod)): - d = findDerivativeBetweenPoints(xAlongLCHalfDuod[n2 - 1], xAlongLCHalfDuod[n2]) - d2AlongLCHalfDuod.append(d) - d2AlongLCHalfDuod[-1] = cd1Sections[-1][-1] - - if materialCoordinates: - # Break point along at body-antrum and pylorus-duod intersection and smooth separately to keep derivative at - # body end - d2AlongBody = \ - interp.smoothCubicHermiteDerivativesLine( - xAlongLCHalfDuod[:elementsInBody - elementsAroundQuarterEso + 2], - d2AlongLCHalfDuod[:elementsInBody - elementsAroundQuarterEso + 2], - fixStartDirection=True, fixEndDirection=True) - - for n in range(elementCountGroupList[-1] + 1): - d2AlongLCHalfDuod[-(n + 1)] = cd1Sections[-1][-1] - - d2AlongBodyToPylorus = \ - interp.smoothCubicHermiteDerivativesLine( - xAlongLCHalfDuod[elementsInBody - elementsAroundQuarterEso + 1:-n], - d2AlongLCHalfDuod[elementsInBody - elementsAroundQuarterEso + 1:-n], - fixStartDirection=True, fixEndDirection=True) - d2AlongDuod = \ - interp.smoothCubicHermiteDerivativesLine( - xAlongLCHalfDuod[-(n + 1):], d2AlongLCHalfDuod[-(n + 1):], fixStartDirection=True, fixEndDirection=True) - d2AlongLCHalfDuod = d2AlongBody[:-1] + d2AlongBodyToPylorus[:-1] + d2AlongDuod - else: - d2AlongLCHalfDuod = \ - interp.smoothCubicHermiteDerivativesLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, - fixStartDerivative=True, fixEndDirection=True) - - for n2 in range(len(xAlongLCHalfDuod)): - xEllipseAroundAll[n2 + elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2][elementsAroundHalfDuod] = \ - xAlongLCHalfDuod[n2] - - xAlongCurvatures = xAlongGCHalfDuod + xAlongLCHalfDuod - d2AlongCurvatures = d2AlongGCHalfDuod + d2AlongLCHalfDuod - - esoCount = 1 - # Find arclengths to points on quarter, GC and 3-quarter fundus as trackSurface search for nearest position doesnt - # work well near apex - proportionsAlongQuarterMidThree = [] - count = 0 - for n1 in [elementsAroundQuarterDuod, elementsAroundHalfDuod, elementsAroundQuarterDuod + elementsAroundHalfDuod]: - xAlong = [] - arcLength = 0.0 - proportions = [] - for n2 in range(elementsAlongFundusApexToCardia): - xAlong.append(xEllipseAroundAll[n2][n1]) - - rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * n1 - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) - d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + - rotFrame[j][2] * d2Apex[2] for j in range(3)] - d2Along = [d2ApexRot] - - for n2 in range(len(xAlong) - 1): - d2Along.append(findDerivativeBetweenPoints(xAlong[n2], xAlong[n2 + 1])) - - for n2 in range(len(xAlong) - 1): - arcLength += interp.getCubicHermiteArcLength(xAlong[n2], d2Along[n2], xAlong[n2 + 1], d2Along[n2 + 1]) - proportion = arcLength / arcLengthsAlongTS[count] - proportions.append(proportion) - proportionsAlongQuarterMidThree.append(proportions) - count += 1 - - for n2 in range(1, len(xEllipseAroundAll) - 1): - startAnnulus = n2 == elementsAlongFundusApexToCardia - endAnnulus = n2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 - interiorAnnulus = \ - elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 - - if startAnnulus or interiorAnnulus or endAnnulus: - xEllipseAroundAll[n2][elementsAroundHalfDuod - 1] = xAnnulusOuter[esoCount] - d1EllipseAroundAll[n2][elementsAroundHalfDuod - 1] = d1AnnulusOuter[esoCount] - xEllipseAroundAll[n2][elementsAroundHalfDuod + 1] = xAnnulusOuter[-esoCount] - d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1] = d1AnnulusOuter[-esoCount] - - if startAnnulus or endAnnulus: - xEllipseAroundAll[n2][elementsAroundHalfDuod] = \ - xAnnulusOuter[0 if startAnnulus else elementsAroundHalfEso] - - xPositionA = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundQuarterDuod]) - xProportionA = trackSurfaceStomach.getProportion(xPositionA) - xPositionB = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[esoCount]) - xProportionB = trackSurfaceStomach.getProportion(xPositionB) - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceStomach.createHermiteCurvePoints( - xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], elementsAroundQuarterDuod - 1, - derivativeStart=d1EllipseAroundAll[n2][elementsAroundQuarterDuod]) - - nx, nd1 = \ - trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, - derivativeMagnitudeStart=vector.magnitude(d1EllipseAroundAll[n2][elementsAroundQuarterDuod]))[0:2] - - xEllipseAroundAll[n2][elementsAroundQuarterDuod + 1:elementsAroundHalfDuod - 1] = nx[1:-1] - d1EllipseAroundAll[n2][elementsAroundQuarterDuod + 1:elementsAroundHalfDuod - 1] = nd1[1:-1] - - # Smooth two halves separately and join together again with d1 at xOuterAnnulus[0] and - # xOuterAnnulus[elementsAroundHalfEso] - d1SmoothedFirstHalf = \ - interp.smoothCubicHermiteDerivativesLine(xEllipseAroundAll[n2][:elementsAroundHalfDuod], - d1EllipseAroundAll[n2][:elementsAroundHalfDuod], - fixEndDerivative=True if interiorAnnulus else None) - - if interiorAnnulus: - d1EllipseAroundAll[n2][:elementsAroundHalfDuod] = d1SmoothedFirstHalf - else: - d1SmoothedFirstHalf[-1] = vector.setMagnitude(d1SmoothedFirstHalf[-1], - 0.5 * (vector.magnitude(d1SmoothedFirstHalf[-2]) + - vector.magnitude(d1AnnulusOuter[1]))) - - xPositionA = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[-esoCount]) - xProportionA = trackSurfaceStomach.getProportion(xPositionA) - xPositionB = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundHalfDuod + - elementsAroundQuarterDuod]) - xProportionB = trackSurfaceStomach.getProportion(xPositionB) - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceStomach.createHermiteCurvePoints( - xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - elementsAroundQuarterDuod - 1, - derivativeEnd=d1EllipseAroundAll[n2][elementsAroundHalfDuod + elementsAroundQuarterDuod]) - - nx, nd1 = \ - trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, - derivativeMagnitudeEnd=vector.magnitude(d1EllipseAroundAll[n2][elementsAroundHalfDuod + - elementsAroundQuarterDuod]))[0:2] - - xEllipseAroundAll[n2][elementsAroundHalfDuod + 2:elementsAroundHalfDuod + elementsAroundQuarterDuod] = \ - nx[1:-1] - d1EllipseAroundAll[n2][elementsAroundHalfDuod + 2:elementsAroundHalfDuod + elementsAroundQuarterDuod] = \ - nd1[1:-1] - - esoCount += 1 - if startAnnulus or endAnnulus: - d1SmoothedSecondHalf = \ - interp.smoothCubicHermiteDerivativesLine( - xEllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + [xEllipseAroundAll[n2][0]], - d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + [d1SmoothedFirstHalf[0]], - fixEndDerivative=True) - d1SmoothedSecondHalf[0] = vector.setMagnitude(d1SmoothedSecondHalf[0], - 0.5 * (vector.magnitude(d1SmoothedFirstHalf[1]) + - vector.magnitude(d1AnnulusOuter[1]))) - - d1EllipseAroundAll[n2] = d1SmoothedFirstHalf + \ - [d1AnnulusOuter[0 if startAnnulus else elementsAroundHalfEso]] + \ - d1SmoothedSecondHalf[:-1] - else: - d1Smoothed = \ - interp.smoothCubicHermiteDerivativesLine(xEllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + - [xEllipseAroundAll[n2][0]], - d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + - [d1EllipseAroundAll[n2][0]], - fixStartDerivative=True, fixEndDerivative=True) - - d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] = d1Smoothed[:-1] - - del xEllipseAroundAll[n2][elementsAroundHalfDuod] - del d1EllipseAroundAll[n2][elementsAroundHalfDuod] - del d2EllipseAroundAll[n2][elementsAroundHalfDuod] - - elif 0 < n2 < elementsAlongFundusApexToCardia or \ - elementsAlongFundusApexToCardia + elementsAroundHalfEso - 1 <= n2 < elementsAlongFundusApexToCardia + \ - elementsAroundHalfEso + elementsInBody - elementsAroundQuarterEso - 1: - if 0 < n2 < elementsAlongFundusApexToCardia: - xToSample = [xEllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ - [xAlongGCHalfDuod[n2]] + \ - [xEllipseAroundAll[n2][elementsAroundQuarterDuod + elementsAroundHalfDuod]] - xToSampleProportion0 = [0.25, 0.5, 0.75] - xToSampleProportion1 = [proportionsAlongQuarterMidThree[0][n2 - 1], - proportionsAlongQuarterMidThree[1][n2 - 1], - proportionsAlongQuarterMidThree[2][n2 - 1]] - else: - n2Idx = n2 - (elementsAlongFundusApexToCardia + elementsAroundHalfEso - 1) + 1 - xToSample = [xEllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ - [xAlongLCHalfDuod[n2Idx]] + \ - [xEllipseAroundAll[n2][elementsAroundQuarterDuod + elementsAroundHalfDuod]] - - d1ToSample = [d1EllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ - [d1EllipseAroundAll[n2][elementsAroundHalfDuod]] + \ - [d1EllipseAroundAll[n2][elementsAroundHalfDuod + elementsAroundQuarterDuod]] - - if 0 < n2 < elementsAlongFundusApexToCardia: - xProportionA = [xToSampleProportion0[0], xToSampleProportion1[0]] - xProportionB = [xToSampleProportion0[1], xToSampleProportion1[1]] - xProportionC = [xToSampleProportion0[2], xToSampleProportion1[2]] - - else: - xPositionA = trackSurfaceStomach.findNearestPosition(xToSample[0]) - xProportionA = trackSurfaceStomach.getProportion(xPositionA) - xPositionB = trackSurfaceStomach.findNearestPosition(xToSample[1]) - xProportionB = trackSurfaceStomach.getProportion(xPositionB) - xPositionC = trackSurfaceStomach.findNearestPosition(xToSample[2]) - xProportionC = trackSurfaceStomach.getProportion(xPositionC) - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceStomach.createHermiteCurvePoints( - xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - elementsAroundQuarterDuod, derivativeStart=d1ToSample[0], derivativeEnd=d1ToSample[1]) - if n2 == 1: - sampledProportionsOneLeft = proportions - nxLeft, nd1Left = \ - trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=vector.magnitude(d1ToSample[0]))[0:2] - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceStomach.createHermiteCurvePoints( - xProportionB[0], xProportionB[1], xProportionC[0], xProportionC[1], elementsAroundQuarterDuod, - derivativeStart=d1ToSample[1], derivativeEnd=d1ToSample[2]) - if n2 == 1: - sampledProportionsOneRight = proportions - nxRight, nd1Right = \ - trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, derivativeMagnitudeEnd=vector.magnitude(d1ToSample[2]))[0:2] - - xNew = nxLeft[1:] + nxRight[1:-1] - d1New = nd1Left[1:] + nd1Right[1:-1] - - xEllipseAroundAll[n2][elementsAroundQuarterDuod + 1:-elementsAroundQuarterDuod] = xNew - d1EllipseAroundAll[n2][elementsAroundQuarterDuod + 1:-elementsAroundQuarterDuod] = d1New - - d1EllipseAroundAll[n2] = interp.smoothCubicHermiteDerivativesLoop(xEllipseAroundAll[n2], - d1EllipseAroundAll[n2]) - - # Calculate and smooth d2 - xAlongAll = [] - for n1 in range(elementsAroundHalfDuod - 1): - xAlong = [] - for n2 in range(len(xEllipseAroundAll)): - xAlong.append(xEllipseAroundAll[n2][n1 if n2 else 0]) - xAlongAll.append(xAlong) - - # Row with annulus - left - xAlong = [] - for n2 in range(len(xEllipseAroundAll)): - xAlong.append(xEllipseAroundAll[n2][elementsAroundHalfDuod - 1 if n2 else 0]) - xAlongAll.append(xAlong) - - xAlongAll.append(xAlongCurvatures) + # stomachStartNode = nextNodeIdentifier + # nodeIdentifier = nextNodeIdentifier + # elementIdentifier = nextElementIdentifier - for n1 in range(elementsAroundHalfDuod - 1): - xAlong = [] - for n2 in range(len(xEllipseAroundAll)): - if n2 == 0: - ringIdx = 0 - elif elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - ringIdx = n1 + elementsAroundHalfDuod - else: - ringIdx = n1 + elementsAroundHalfDuod + 1 - xAlong.append(xEllipseAroundAll[n2][ringIdx]) - xAlongAll.append(xAlong) - - d2AlongAll = [] - for n1 in range(elementsCountAroundDuod): - rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * n1 - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) - d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + - rotFrame[j][2] * d2Apex[2] for j in range(3)] - - if n1 == elementsAroundHalfDuod: # Process LC and GC - # GC - # Resample point downstream from apex - nx = \ - trackSurfaceStomach.createHermiteCurvePoints( - sampledProportionsOneLeft[-2][0], sampledProportionsOneLeft[-2][1], - sampledProportionsOneRight[1][0], sampledProportionsOneRight[1][1], 2, - derivativeStart=d1EllipseAroundAll[1][elementsAroundHalfDuod - 1], - derivativeEnd=d1EllipseAroundAll[1][elementsAroundHalfDuod + 1])[0] - - xEllipseAroundAll[1][elementsAroundHalfDuod] = nx[1] - - d1EllipseAroundAll[1] = interp.smoothCubicHermiteDerivativesLoop(xEllipseAroundAll[1], - d1EllipseAroundAll[1]) - - xAlongGCHalfDuodNew = [] - for n2 in range(elementsAlongFundusApexToCardia + 1): - xAlongGCHalfDuodNew.append(xEllipseAroundAll[n2][elementsAroundHalfDuod]) - - d2AlongGCHalfDuodNew = [d2ApexRot] - for n2 in range(1, len(xAlongGCHalfDuodNew) - 1): - d = findDerivativeBetweenPoints(xAlongGCHalfDuodNew[n2], xAlongGCHalfDuodNew[n2 + 1]) - d2AlongGCHalfDuodNew.append(d) - d2AlongGCHalfDuodNew.append(d2AnnulusOuter[0]) - - d2AlongGCHalfDuodNew = \ - interp.smoothCubicHermiteDerivativesLine(xAlongGCHalfDuodNew + [o1_x[-1][0]], - d2AlongGCHalfDuodNew + [d2AnnulusOuter[0]], - fixEndDerivative=True)[:-1] - d2AlongCurvatures[:len(d2AlongGCHalfDuodNew)] = d2AlongGCHalfDuodNew - d2AlongAll.append(d2AlongCurvatures) - - else: - d2Along = [d2ApexRot] - for n2 in range(1, len(xAlongAll[n1])): - d = findDerivativeBetweenPoints(xAlongAll[n1][n2 - 1], xAlongAll[n1][n2]) - d2Along.append(d) - d2Along[-1] = cd1Sections[-1][-1] - - if materialCoordinates: - # Break point along at body-antrum and pylorus-duod intersection and smooth separately to keep - # derivative at body end - d2AlongFundusBody = \ - interp.smoothCubicHermiteDerivativesLine( - xAlongAll[n1][:elementCountGroupList[0] + elementCountGroupList[1] + 1], - d2Along[:elementCountGroupList[0] + elementCountGroupList[1] + 1], - fixStartDirection=True, fixEndDirection=True) - - for n in range(elementCountGroupList[-1] + 1): - d2Along[-(n + 1)] = cd1Sections[-1][-1] - - d2AlongBodyToPylorus = \ - interp.smoothCubicHermiteDerivativesLine( - xAlongAll[n1][elementCountGroupList[0] + elementCountGroupList[1]:-n], - d2Along[elementCountGroupList[0] + elementCountGroupList[1]:-n], - fixStartDirection=True, fixEndDirection=True) - - d2AlongDuod = \ - interp.smoothCubicHermiteDerivativesLine( - xAlongAll[n1][-(n + 1):], d2Along[-(n + 1):], fixStartDirection=True, fixEndDirection=True) - - d2Along = d2AlongFundusBody[:-1] + d2AlongBodyToPylorus[:-1] + d2AlongDuod - else: - d2Along = interp.smoothCubicHermiteDerivativesLine(xAlongAll[n1], d2Along, fixStartDirection=True, - fixEndDirection=True) - if n1 == elementsAroundHalfDuod - 1 or n1 == elementsAroundHalfDuod + 1: - d2Along[elementsAlongFundusApexToCardia] = \ - vector.setMagnitude(d2Along[elementsAlongFundusApexToCardia], - 0.5 * (vector.magnitude(d2Along[elementsAlongFundusApexToCardia]) + - vector.magnitude(d2AnnulusOuter[1]))) - d2Along[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2] = \ - vector.setMagnitude(d2Along[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2], - 0.5 * (vector.magnitude(d2Along[elementsAlongFundusApexToCardia + - elementsAroundHalfEso - 2]) + - vector.magnitude(d2AnnulusOuter[1]))) - d2AlongAll.append(d2Along) - - # Replace d2 for points sitting on annulus - for n2 in range(2, elementsAroundHalfEso - 1): - n2Idx = n2 + elementsAlongFundusApexToCardia - 1 - d2AlongAll[elementsAroundHalfDuod - 1][n2Idx] = d2AnnulusOuter[n2] - d2AlongAll[elementsAroundHalfDuod + 1][n2Idx] = d2AnnulusOuter[-n2] - - # Re-arrange back to around followed by along - for n2 in range(len(xEllipseAroundAll)): - incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ - elementsAroundHalfEso - 2 - for n1 in range(len(xEllipseAroundAll[n2]) + (1 if incompleteRingsWithinEso else 0)): - if incompleteRingsWithinEso: - if n1 == elementsAroundHalfDuod: - pass - else: - d2EllipseAroundAll[n2][n1 - (1 if n1 > elementsAroundHalfDuod else 0)] = d2AlongAll[n1][n2] - elif n2 >= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - d2EllipseAroundAll[n2][n1] = \ - d2AlongAll[n1][n2 - (elementsAroundHalfEso + 1 - 4 if n1 == elementsAroundHalfDuod else 0)] - else: - d2EllipseAroundAll[n2][n1] = d2AlongAll[n1][n2] - - xOuter = xEllipseAroundAll - d1Outer = d1EllipseAroundAll - d2Outer = d2EllipseAroundAll - - # Calculate d3 - d3UnitOuter = [] - for n2 in range(len(xOuter)): - d3Around = [] - for n1 in range(len(xOuter[n2])): - if n2 == 0: - d3Around.append(rotAxisApex) - else: - d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) - d3UnitOuter.append(d3Around) - - # Calculate curvature around - d1Curvature = [] - d1Curvature.append([1.0 for n in range(len(xOuter[0]))]) # Will be replaced in later step - esoCount = 1 - for n2 in range(1, len(xOuter)): - incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ - elementsAroundHalfEso - 2 - completeRingsOnCardia = (n2 == elementsAlongFundusApexToCardia or n2 == elementsAlongFundusApexToCardia + - elementsAroundHalfEso - 2) - if incompleteRingsWithinEso: - d2 = o1_d2[-1][esoCount] - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(o1_d1[-1][esoCount]), - vector.normalise(o1_d2[-1][esoCount]))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod] + [o1_x[-1][esoCount]], - d1Outer[n2][:elementsAroundHalfDuod] + [d2Rot], - d3UnitOuter[n2][:elementsAroundHalfDuod] + [rotAxis]) - curvature = interp.getCubicHermiteCurvature(xAnnulusOuter[esoCount], d1AnnulusOuter[esoCount], - o1_x[-1][esoCount], d2Rot, - d3UnitOuter[n2][elementsAroundHalfDuod - 1], 0.0) - d1CurvatureFirstHalf[-2] = curvature - - d3 = vector.normalise(vector.crossproduct3(vector.normalise(o1_d1[-1][-esoCount]), - vector.normalise(o1_d2[-1][-esoCount]))) - d1CurvatureSecondHalf = findCurvatureAlongLine([o1_x[-1][-esoCount]] + - xOuter[n2][elementsAroundHalfDuod:] + [xOuter[n2][0]], - [o1_d2[-1][-esoCount]] + - d1Outer[n2][elementsAroundHalfDuod:] + [d1Outer[n2][0]], - [d3] + d3UnitOuter[n2][elementsAroundHalfDuod:] + - [d3UnitOuter[n2][0]])[:-1] - - curvature = interp.getCubicHermiteCurvature(o1_x[-1][-esoCount], o1_d2[-1][-esoCount], - xAnnulusOuter[-esoCount], d1AnnulusOuter[-esoCount], - d3UnitOuter[n2][elementsAroundHalfDuod], 1.0) - d1CurvatureSecondHalf[1] = curvature - d1Curvature.append(d1CurvatureFirstHalf[:-1] + d1CurvatureSecondHalf[1:]) - esoCount += 1 - - elif completeRingsOnCardia: - d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod], - d1Outer[n2][:elementsAroundHalfDuod], - d3UnitOuter[n2][:elementsAroundHalfDuod]) - - d1CurvatureSecondHalf = findCurvatureAlongLine(xOuter[n2][elementsAroundHalfDuod + 1:] + [xOuter[n2][0]], - d1Outer[n2][elementsAroundHalfDuod + 1:] + [d1Outer[n2][0]], - d3UnitOuter[n2][elementsAroundHalfDuod + 1:] + - [d3UnitOuter[n2][0]])[:-1] - - midPtCurvature = annulusD2Curvature[0 if n2 == elementsAlongFundusApexToCardia else elementsAroundHalfEso] - d1Curvature.append(d1CurvatureFirstHalf + [midPtCurvature] + d1CurvatureSecondHalf) - esoCount += 1 - else: - d1Curvature.append(findD1CurvatureAround(xOuter[n2], d1Outer[n2], d3UnitOuter[n2])) - - # Populate d3Along for use to calculate curvature along - d3UnitAlongAll = [] - for n1 in range(elementsAroundHalfDuod - 1): - d3Along = [] - for n2 in range(len(d3UnitOuter)): - d3Along.append(d3UnitOuter[n2][n1 if n2 else 0]) - d3UnitAlongAll.append(d3Along) - - # Row wth annulus - left - d3Along = [] - for n2 in range(len(d3UnitOuter)): - d3Along.append(d3UnitOuter[n2][elementsAroundHalfDuod - 1 if n2 else 0]) - d3UnitAlongAll.append(d3Along) - - # GC and LC row - needs to be in 2 parts - # GC part - d3AlongGCHalfDuod = [] - for n2 in range(elementsAlongFundusApexToCardia + 1): - d3AlongGCHalfDuod.append(d3UnitOuter[n2][elementsAroundHalfDuod if n2 else 0]) - - # LC part - d3AlongLCHalfDuod = [] - for n2 in range(elementsAlongCardiaToDuod + 1): - d3AlongLCHalfDuod.append(d3UnitOuter[n2 + elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2] - [elementsAroundHalfDuod]) - d3Along = d3AlongGCHalfDuod + d3AlongLCHalfDuod - d3UnitAlongAll.append(d3Along) - - for n1 in range(elementsAroundHalfDuod - 1): - d3Along = [] - for n2 in range(len(d3UnitOuter)): - if n2 == 0: - ringIdx = 0 - elif elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - ringIdx = n1 + elementsAroundHalfDuod - else: - ringIdx = n1 + elementsAroundHalfDuod + 1 - d3Along.append(d3UnitOuter[n2][ringIdx]) - d3UnitAlongAll.append(d3Along) - - # Calculate curvature along - d2CurvatureAlong = [] - for n1 in range(len(xAlongAll)): - if n1 == elementsAroundHalfDuod: # Process LC and GC - # GC - d2CurvatureAlongGCHalfDuod = findCurvatureAlongLine(xAlongGCHalfDuod, d2AlongGCHalfDuod, d3AlongGCHalfDuod) - # LC - d2CurvatureAlongLCHalfDuod = findCurvatureAlongLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, d3AlongLCHalfDuod) - d2CurvaturesAlongCurvature = d2CurvatureAlongGCHalfDuod + d2CurvatureAlongLCHalfDuod - d2CurvatureAlong.append(d2CurvaturesAlongCurvature) - else: - curvature = findCurvatureAlongLine(xAlongAll[n1], d2AlongAll[n1], d3UnitAlongAll[n1]) - # replace with curvature from annulus - if n1 == elementsAroundHalfDuod - 1 or n1 == elementsAroundHalfDuod + 1: - for n2 in range(2, elementsAroundHalfEso - 1): - n2Idx = n2 + elementsAlongFundusApexToCardia + 1 - curvature[n2Idx] = annulusD2Curvature[(n2 + 1 if elementsAroundHalfDuod - 1 else -(n2 + 1))] - d2CurvatureAlong.append(curvature) - - # Re-arrange back to around followed by along + # Calculate arclength at quarter line between lesser and greater curvature for each region + xQuarterEllipseAll = [] + d2QuarterEllipseAll = [] for n2 in range(len(xEllipseAroundAll)): - incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ - elementsAroundHalfEso - 2 - for n1 in range(len(xEllipseAroundAll[n2]) + (1 if incompleteRingsWithinEso else 0)): - if incompleteRingsWithinEso: - if n1 == elementsAroundHalfDuod: - pass - else: - d2Curvature[n2][n1 - (1 if n1 > elementsAroundHalfDuod else 0)] = d2CurvatureAlong[n1][n2] - elif n2 >= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - d2Curvature[n2][n1] = \ - d2CurvatureAlong[n1][n2 - (elementsAroundHalfEso + 1 - 4 if n1 == elementsAroundHalfDuod else 0)] - else: - d2Curvature[n2][n1] = d2CurvatureAlong[n1][n2] - - # Replace d1Curvature at apex with d2Curvature - for n1 in range(elementsCountAroundDuod): - d1Curvature[0][n1] = d2Curvature[0][n1] - - # Create inner nodes - xList = [] - d1List = [] - d2List = [] - d3List = [] - nodeIdx = stomachStartNode - idxMat = [] - - if elementsCountThroughWall > 1: - thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, - longitudinalRelThickness, longitudinalRelThickness] - thicknessProportions = [thicknessProportion / sum(thicknessProportionsUI[:-1]) - for thicknessProportion in thicknessProportionsUI] - - xi3List = [] - xi3 = 0.0 - for i in range(len(thicknessProportions) - 1): - xi3 += thicknessProportions[i] - xi3List.append(xi3) - - for n2 in range(len(xOuter)): - idxThroughWall = [] - for n3 in range(elementsCountThroughWall + 1): - xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 - idxAround = [] - for n1 in range(1 if n2 == 0 else len(xOuter[n2])): - # Coordinates - norm = d3UnitOuter[n2][n1] - xOut = xOuter[n2][n1] - xIn = [xOut[i] - norm[i] * wallThickness for i in range(3)] - dWall = [wallThickness * c for c in norm] - x = interp.interpolateCubicHermite(xIn, dWall, xOut, dWall, xi3) - xList.append(x) - - # d1 - factor = 1.0 + wallThickness * (1.0 - xi3) * d1Curvature[n2][n1] - d1 = [factor * c for c in d1Outer[n2][n1]] - d1List.append(d1) - - # d2 - factor = 1.0 + wallThickness * (1.0 - xi3) * d2Curvature[n2][n1] - d2 = [factor * c for c in d2Outer[n2][n1]] - d2List.append(d2) - - # d3 - d3 = [c * wallThickness * (thicknessProportions[n3 + 1] if elementsCountThroughWall > 1 else 1.0) - for c in norm] - d3List.append(d3) - - idxAround.append(nodeIdx) - nodeIdx += 1 - idxThroughWall.append(idxAround) - idxMat.append(idxThroughWall) - - nodeIdxGC = [] - for n2 in range(len(idxMat)): - for n3 in range(len(idxMat[n2])): - if n2 == 0: - nodeIdxGC += idxMat[n2][n3] - else: - nodeIdxGC.append(idxMat[n2][n3][0]) - - for n2 in range(1, elementsAlongFundusApexToCardia + 1): - for n3 in range(len(idxMat[n2])): - nodeIdxGC.append(idxMat[n2][n3][int(0.5 * len(xOuter[n2]))]) - - nodeIdxLC = [] - for n2 in range(elementsAlongCardiaToDuod + 1): - for n3 in range(len(idxMat[n2])): - nodeIdxLC.append( - idxMat[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 + n2][n3][elementsAroundHalfDuod]) - - for n2 in range(len(xList)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xList[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1List[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2List[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n2]) - 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 += 1 - - annotationGroupsAlong = [] - for i in range(len(elementCountGroupList)): - elementsCount = elementCountGroupList[i] - for n in range(elementsCount): - annotationGroupsAlong.append(annotationGroupAlong[i]) - - # Create elements - fundusMucosaElementIdentifiers = [] - elementIdxMat = [] - n = 0 - for n2 in range(elementsAlongEsophagus): - elementIdxThroughWall = [] - for n3 in range(elementsThroughEsophagusWall): - elementIdxAround = [] - for n1 in range(elementsCountAroundEso): - n += 1 - elementIdxAround.append(n) - elementIdxThroughWall.append(elementIdxAround) - elementIdxMat.append(elementIdxThroughWall) - - if useCubicHermiteThroughWall: - eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives) - else: - eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) - eftStandard = eftfactory.createEftBasic() - - elementtemplateStandard = mesh.createElementtemplate() - elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) - elementtemplateStandard.defineField(coordinates, -1, eftStandard) - - elementtemplateX = mesh.createElementtemplate() - elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) - - fundusElements = elementCountGroupList[0] - radiansPerElementAroundDuod = math.pi * 2.0 / elementsCountAroundDuod - - for e2 in range(len(xOuter) - 1): - elementIdxThroughWall = [] - if e2 == 0: # pole - for e3 in range(elementsCountThroughWall): - elementIdxAround = [] - for e1 in range(elementsCountAroundDuod): - va = e1 - vb = (e1 + 1) % elementsCountAroundDuod - eft1 = eftfactory.createEftShellPoleBottom(va*100, vb*100) - elementtemplateX.defineField(coordinates, -1, eft1) - element = mesh.createElement(elementIdentifier, elementtemplateX) - bni1 = e3 + stomachStartNode - bni2 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + e1 - bni3 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + \ - (e1 + 1) % elementsCountAroundDuod - nodeIdentifiers = [bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAroundDuod, - bni3 + elementsCountAroundDuod] - - element.setNodesByIdentifier(eft1, nodeIdentifiers) - # set general linear map coefficients - radiansAround = e1 * radiansPerElementAroundDuod - radiansAroundNext = ((e1 + 1) % elementsCountAroundDuod) * radiansPerElementAroundDuod - scalefactors = [ - -1.0, - math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, - math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod, - math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, - math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod - ] - element.setScaleFactors(eft1, scalefactors) - if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: - fundusMucosaElementIdentifiers.append(elementIdentifier) - elementIdxAround.append(elementIdentifier) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - elementIdxThroughWall.append(elementIdxAround) - elementIdxMat.append(elementIdxThroughWall) - - elif 0 < e2 < elementsAlongFundusApexToCardia or \ - e2 > elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: - for e3 in range(elementsCountThroughWall): - elementIdxAround = [] - for e1 in range(len(xOuter[e2])): - eft1 = eftStandard - scaleFactors = [] - elementtemplate1 = elementtemplateStandard - bni111 = idxMat[e2][e3][e1] - bni211 = idxMat[e2][e3][(e1 + 1) % len(idxMat[e2][e3])] - bni121 = idxMat[e2 + 1][e3][e1] - bni221 = idxMat[e2 + 1][e3][(e1 + 1) % len(idxMat[e2 + 1][e3])] - bni112 = idxMat[e2][e3 + 1][e1] - bni212 = idxMat[e2][e3 + 1][(e1 + 1) % len(idxMat[e2][e3])] - bni122 = idxMat[e2 + 1][e3 + 1][e1] - bni222 = idxMat[e2 + 1][e3 + 1][(e1 + 1) % len(idxMat[e2 + 1][e3])] - nodeIdentifiers = [bni111, bni211, bni121, bni221, - bni112, bni212, bni122, bni222] - - if e2 == elementsAlongFundusApexToCardia - 1: - if e1 == int(0.5 * len(xOuter[e2]) - 2): - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(0.5 * len(xOuter[e2]) - 1): - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(0.5 * len(xOuter[e2])): - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(0.5 * len(xOuter[e2]) + 1): - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - if e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - if e1 == int(0.5 * len(xOuter[e2]) - 2): - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(0.5 * len(xOuter[e2]) - 1): - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(0.5 * len(xOuter[e2])): - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(0.5 * len(xOuter[e2]) + 1): - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - element = mesh.createElement(elementIdentifier, elementtemplate1) - element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - element.setScaleFactors(eft1, scaleFactors) - if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: - fundusMucosaElementIdentifiers.append(elementIdentifier) - elementIdxAround.append(elementIdentifier) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - elementIdxThroughWall.append(elementIdxAround) - elementIdxMat.append(elementIdxThroughWall) - - elif elementsAlongFundusApexToCardia <= e2 <= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: - for e3 in range(elementsCountThroughWall): - elementIdxAround = [] - for e1 in range(elementsCountAroundDuod - 2): - eft1 = eftStandard - scaleFactors = [] - elementtemplate1 = elementtemplateStandard - if e1 > elementsAroundHalfDuod - 2: - if elementsAlongFundusApexToCardia == e2: # first ring in eso - e1IdxBni1 = e1 + 2 - e1IdxBni3 = e1 + 1 - elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: - # last ring in esophagus - e1IdxBni1 = e1 + 1 - e1IdxBni3 = e1 + 2 - elif elementsAlongFundusApexToCardia < e2 < elementsAlongFundusApexToCardia + \ - elementsAroundHalfEso - 3: # incomplete rings interior of eso - e1IdxBni1 = e1 + 1 - e1IdxBni3 = e1 + 1 - else: - e1IdxBni1 = e1 - e1IdxBni3 = e1 - bni1 = idxMat[e2][e3][e1IdxBni1] - bni2 = idxMat[e2][e3][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] - bni3 = idxMat[e2 + 1][e3][e1IdxBni3] - bni4 = idxMat[e2 + 1][e3][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] - bni5 = idxMat[e2][e3 + 1][e1IdxBni1] - bni6 = idxMat[e2][e3 + 1][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] - bni7 = idxMat[e2 + 1][e3 + 1][e1IdxBni3] - bni8 = idxMat[e2 + 1][e3 + 1][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] - nodeIdentifiers = [bni1, bni2, bni3, bni4, bni5, bni6, bni7, bni8] - - if e2 == elementsAlongFundusApexToCardia and e1 == elementsAroundHalfDuod - 2: - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3 and \ - e1 == elementsAroundHalfDuod - 2: - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3 and \ - e1 == elementsAroundHalfDuod - 1: - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - elif e2 == elementsAlongFundusApexToCardia and e1 == elementsAroundHalfDuod - 1: - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - element = mesh.createElement(elementIdentifier, elementtemplate1) - element.setNodesByIdentifier(eft1, nodeIdentifiers) - if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: - fundusMucosaElementIdentifiers.append(elementIdentifier) - elementIdxAround.append(elementIdentifier) - if scaleFactors: - element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - elementIdxThroughWall.append(elementIdxAround) - elementIdxMat.append(elementIdxThroughWall) - - # Annulus - # Assemble endPoints for annulus - endPoints_x = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - endPoints_d1 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - endPoints_d2 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - endNode_Id = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - endDerivativesMap = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - endProportions = [] - - for n3 in range(elementsCountThroughWall + 1): - n1 = 0 - for nAround in range(elementsCountAroundEso): - if nAround == 0: - idx = idxMat[elementsAlongFundusApexToCardia][n3][elementsAroundHalfDuod] - elif 0 < nAround < elementsAroundHalfEso: - idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][elementsAroundHalfDuod - 1] - n1 += 1 - elif nAround == elementsAroundHalfEso: - n1 -= 1 - idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][elementsAroundHalfDuod] - else: - idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][ - elementsAroundHalfDuod + (1 if (n1 == elementsAroundHalfEso - 2 or n1 == 0) else 0)] - n1 -= 1 - - endPoints_x[n3][nAround] = xList[idx - stomachStartNode] - endPoints_d1[n3][nAround] = d1List[idx - stomachStartNode] - endPoints_d2[n3][nAround] = d2List[idx - stomachStartNode] - endNode_Id[n3][nAround] = idx - - if n3 == elementsCountThroughWall: # outer layer - endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) - endProportions.append(trackSurfaceStomach.getProportion(endPosition)) - - for n3 in range(elementsCountThroughWall + 1): - for nAround in range(elementsCountAroundEso): - if nAround == 0: - endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, -1, 0), None) - elif nAround == 1: - endDerivativesMap[n3][nAround] = ((-1, 1, 0), (-1, -1, 0), None) - elif 1 < nAround < elementsAroundHalfEso - 1: - endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == elementsAroundHalfEso - 1: - endDerivativesMap[n3][nAround] = ((1, 1, 0), (-1, 1, 0), None) - elif nAround == elementsAroundHalfEso: - endDerivativesMap[n3][nAround] = (None, None, None) - elif nAround == elementsAroundHalfEso + 1: - endDerivativesMap[n3][nAround] = ((1, -1, 0), (1, 1, 0), None) - elif elementsAroundHalfEso + 1 < nAround < elementsCountAroundEso - 1: - endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) - elif nAround == elementsCountAroundEso - 1: - endDerivativesMap[n3][nAround] = ((-1, -1, 0), (1, -1, 0), None) - - startProportions = [] - for n in range(elementsCountAroundEso): - startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) - - cardiaGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, - get_stomach_term("cardia of stomach")) - cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) - if cardiaGroup not in allAnnotationGroups: - allAnnotationGroups.append(cardiaGroup) - - lastDuodenumElementIdentifier = elementIdentifier - - stomachWallAnnotationGroups = [] - if elementsCountThroughWall == 4: - stomachWallAnnotationGroups = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], - [longitudinalMuscleGroup]] - - # Remove mucosa layer from annulus - if elementsCountThroughWall == 4 and limitingRidge: - o1_x = o1_x[1:] - o1_d1 = o1_d1[1:] - o1_d2 = o1_d2[1:] - o1_NodeId = o1_NodeId[1:] - endPoints_x = endPoints_x[1:] - endPoints_d1 = endPoints_d1[1:] - endPoints_d2 = endPoints_d2[1:] - endNode_Id = endNode_Id[1:] - endDerivativesMap = endDerivativesMap[1:] - stomachWallAnnotationGroups = stomachWallAnnotationGroups[1:] - - nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( - nodes, mesh, nodeIdentifier, elementIdentifier, - o1_x, o1_d1, o1_d2, None, o1_NodeId, None, - endPoints_x, endPoints_d1, endPoints_d2, None, endNode_Id, endDerivativesMap, - elementsCountRadial=elementsCountAcrossCardia, meshGroups=[stomachMeshGroup, cardiaMeshGroup], - wallAnnotationGroups=stomachWallAnnotationGroups, - tracksurface=trackSurfaceStomach, - startProportions=startProportions, endProportions=endProportions, - rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, - coordinates=coordinates) - - elementIdxThroughWall = [] - n = lastDuodenumElementIdentifier - 1 - for n3 in range(elementsCountThroughWall): - elementIdxAround = [] - for n1 in range(elementsCountAroundEso): - n += 1 - elementIdxAround.append(n) - elementIdxThroughWall.append(elementIdxAround) - elementIdxMat.append(elementIdxThroughWall) - - # delete mucosa layer in fundus when there is a limiting ridge - mesh_destroy_elements_and_nodes_by_identifiers(mesh, fundusMucosaElementIdentifiers) - - # Create annotation groups for dorsal and ventral parts of the stomach - dorsalGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("dorsal stomach")) - ventralGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("ventral stomach")) - dorsalMeshGroup = dorsalGroup.getMeshGroup(mesh) - ventralMeshGroup = ventralGroup.getMeshGroup(mesh) - - for e2 in range(len(elementIdxMat)): - for e3 in range(len(elementIdxMat[e2])): - for e1 in range(len(elementIdxMat[e2][e3])): - elementIdx = elementIdxMat[e2][e3][e1] - element = mesh.findElementByIdentifier(elementIdx) - if e1 < 0.5 * len(elementIdxMat[e2][e3]): - ventralMeshGroup.addElement(element) - else: - dorsalMeshGroup.addElement(element) - if dorsalGroup not in allAnnotationGroups: - allAnnotationGroups.append(dorsalGroup) - if ventralGroup not in allAnnotationGroups: - allAnnotationGroups.append(ventralGroup) - - nodesOnLCMargin = [] - for n2 in range(elementsAlongEsophagus + 1): - for n3 in range(elementsThroughEsophagusWall + 1): - nodeIdxOnLCMargin = 1 + elementsAroundHalfEso + \ - n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ - n3 * elementsCountAroundEso - nodesOnLCMargin.append(nodeIdxOnLCMargin) - allNodesOnLC = nodesOnLCMargin + nodeIdxLC - - nearLCGroup = AnnotationGroup(region, ("elements adjacent to lesser curvature", "None")) - - elementIter = mesh.createElementiterator() - element = elementIter.next() - while element.isValid(): - eft = element.getElementfieldtemplate(coordinates, -1) - nodeIdentifiers = get_element_node_identifiers(element, eft) - for n in range(len(nodeIdentifiers)): - if nodeIdentifiers[n] in allNodesOnLC: - nearLCGroup.getMeshGroup(mesh).addElement(element) - break - element = elementIter.next() - allAnnotationGroups.append(nearLCGroup) - - # Create split coordinate field - if splitCoordinates: - nodesOnSplitMargin = [] - - for n2 in range(elementsAlongEsophagus + 1): - for n3 in range(elementsThroughEsophagusWall + 1): - nodeIdxOnGCMargin = 1 + n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ - n3 * elementsCountAroundEso - nodesOnSplitMargin.append(nodeIdxOnGCMargin) - nodeIdxOnLCMargin = 1 + elementsAroundHalfEso + \ - n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ - n3 * elementsCountAroundEso - nodesOnSplitMargin.append(nodeIdxOnLCMargin) - - nodesOnSplitMargin += nodeIdxGC + nodeIdxLC - - splitCoordinates = findOrCreateFieldCoordinates(fm, name="split coordinates") - splitNodetemplate1 = nodes.createNodetemplate() - splitNodetemplate1.defineField(splitCoordinates) - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_VALUE, 1) - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - if useCrossDerivatives: - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) - if useCubicHermiteThroughWall: - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS3, 1) - if useCrossDerivatives: - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) - splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) - - splitNodetemplate2 = nodes.createNodetemplate() - splitNodetemplate2.defineField(splitCoordinates) - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_VALUE, 2) - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS1, 2) - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS2, 2) - if useCrossDerivatives: - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 2) - if useCubicHermiteThroughWall: - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS3, 2) - if useCrossDerivatives: - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 2) - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 2) - splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 2) - - nodeIter = nodes.createNodeiterator() - node = nodeIter.next() - while node.isValid(): - # if not markerPoints.containsNode(node): - cache.setNode(node) - identifier = node.getIdentifier() - marginNode = identifier in nodesOnSplitMargin - x = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, 3)[1] - d1 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, 3)[1] - d2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, 3)[1] - if useCrossDerivatives: - d1d2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, 3)[1] - if useCubicHermiteThroughWall: - d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, 3)[1] - if useCrossDerivatives: - d1d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, 3)[1] - d2d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, 3)[1] - d1d2d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, 3)[1] - - node.merge(splitNodetemplate2 if marginNode else splitNodetemplate1) - versionCount = 2 if marginNode else 1 - for vn in range(versionCount): - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, vn + 1, x) - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, vn + 1, d1) - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, vn + 1, d2) - if useCrossDerivatives: - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, vn + 1, d1d2) - if useCubicHermiteThroughWall: - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, vn + 1, d3) - if useCrossDerivatives: - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, vn + 1, d1d3) - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, vn + 1, d2d3) - splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, vn + 1, d1d2d3) - node = nodeIter.next() - - elementIter = mesh.createElementiterator() - element = elementIter.next() - splitElementtemplate1 = mesh.createElementtemplate() - splitElementtemplate2 = mesh.createElementtemplate() - - count = 0 - elementsInOstium = elementsCountAroundEso * elementsAlongEsophagus * elementsThroughEsophagusWall - closedLoopElementId = nextElementIdentifier - elementsCountAroundEso * elementsCountAcrossCardia - \ - elementsCountAroundDuod * elementsCountThroughWall * (elementsAlongCardiaToDuod + 1) - - allValueLabels = [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, - Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3, - Node.VALUE_LABEL_D2_DS2DS3, Node.VALUE_LABEL_D3_DS1DS2DS3] - - while element.isValid(): - eft = element.getElementfieldtemplate(coordinates, -1) - nodeIdentifiers = get_element_node_identifiers(element, eft) - elementId = element.getIdentifier() - marginDorsal = False - for n in range(len(nodeIdentifiers)): - marginElement = nodeIdentifiers[n] in nodesOnSplitMargin - if marginElement: - count += 1 - if count < 3 and (elementId <= elementsInOstium or elementId > closedLoopElementId): - marginDorsal = True - elif count >= 3 and (elementId <= elementsInOstium or elementId > closedLoopElementId): - if count == 4: - count = 0 - elif elementsInOstium < elementId < elementsInOstium + len(xOuter[0]) + 1: - marginDorsal = True - count = 0 - elif elementsInOstium + len(xOuter[0]) < elementId < elementsInOstium + len(xOuter[0]) * 2 + 1: - count = 0 - elif count < 2 and elementId > elementsInOstium + 2 * (len(xOuter[0])): - marginDorsal = True - elif count >= 2 and elementId > elementsInOstium + 2 * (len(xOuter[0])): - if count == 2: - count = 0 - break - - if marginDorsal: - # Find nodes on margin to remap with version 2 - lnRemapV2 = [] - for n in range(len(nodeIdentifiers)): - if nodeIdentifiers[n] in nodesOnSplitMargin: - lnRemapV2.append(n + 1) - eft2 = eft - remapEftNodeValueLabelsVersion(eft2, lnRemapV2, allValueLabels, 2) - - splitElementtemplate2.defineField(splitCoordinates, -1, eft2) - element.merge(splitElementtemplate2) - element.setNodesByIdentifier(eft2, nodeIdentifiers) - if eft2.getNumberOfLocalScaleFactors() > 0: - element.setScaleFactor(eft2, 1, -1.0) - else: - splitElementtemplate1.defineField(splitCoordinates, -1, eft) - element.merge(splitElementtemplate1) - element.setNodesByIdentifier(eft, nodeIdentifiers) - if eft.getNumberOfLocalScaleFactors() == 1: - element.setScaleFactors(eft, [-1.0]) - - element = elementIter.next() - - allAnnotationGroups.append(nearLCGroup) + xQuarterEllipseAll.append(xEllipseAroundAll[n2][elementsAroundQuarterDuod]) + d2QuarterEllipseAll.append(d2EllipseAroundAll[n2][elementsAroundQuarterDuod]) + totalQuarterLength = interp.getCubicHermiteCurvesLength(xQuarterEllipseAll, d2QuarterEllipseAll) + + ratioArcLengthSections = [] + for i in range(len(nodeStartEndSections)): + xList = [] + d2List = [] + for n in range(nodeStartEndSections[i][0], nodeStartEndSections[i][1] + 1): + xList.append(xQuarterEllipseAll[n]) + d2List.append(d2QuarterEllipseAll[n]) + quarterLengthSection = interp.getCubicHermiteCurvesLength(xList, d2List) + ratioArcLengthSections.append(quarterLengthSection/totalQuarterLength) + + elementsAlongSections = [math.ceil(c / targetLength) for c in ratioArcLengthSections] + print(elementsAlongSections) + + # if materialCoordinates: + # GEJSettings['Unit scale'] = unitScale + # GEJSettings['Ostium diameter'] = ostiumDiameter + # GEJSettings['Ostium length'] = ostiumLength + # GEJSettings['Ostium wall thickness'] = ostiumWallThickness + # GEJSettings['Ostium wall relative thicknesses'] = ostiumWallRelThicknesses + # GEJSettings['Vessel inner diameter'] = vesselInnerDiameter + # GEJSettings['Vessel wall thickness'] = vesselWallThickness + # GEJSettings['Vessel wall relative thicknesses'] = vesselWallRelThicknesses + # GEJSettings['Vessel angle 1 degrees'] = vesselAngle1 + # GEJSettings['Vessel angle 2 degrees'] = vesselAngle2 + # + # # Create location of annulus + # xAnnulusOuter = [[] for x in range(elementsCountAroundEso)] + # xAnnulusOuterPosition = [[] for x in range(elementsCountAroundEso)] + # d1AnnulusNorm = [] + # d1AnnulusOuter = [] + # for n1 in range(elementsCountAroundEso): + # normD2 = vector.normalise(o1_d2[-1][n1]) + # d1AnnulusNorm.append(normD2) + # d1AnnulusOuter.append(vector.setMagnitude(o1_d2[-1][n1], sf)) + # x = [o1_x[-1][n1][c] + sf * normD2[c] for c in range(3)] + # nearestPosition = trackSurfaceStomach.findNearestPosition(x) + # xAnnulusOuterPosition[n1] = nearestPosition + # xAnnulusOuter[n1] = trackSurfaceStomach.evaluateCoordinates(nearestPosition) + # + # d2AnnulusOuter = [] + # for n in range(elementsCountAroundEso): + # d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundEso]) + # d2AnnulusOuter.append(d) + # d2AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) + # d3Annulus = [] + # for n in range(elementsCountAroundEso): + # d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) + # d3Annulus.append(d3) + # annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + # + # # Adjust annulus derivatives + # # Make d2 on second half of eso point towards duodenum + # for n1 in range(elementsAroundHalfEso - 1): + # idx = n1 + elementsAroundHalfEso + 1 + # rotAxis = d3Annulus[idx] + # rotAngle = math.pi + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) + # d2 = d2AnnulusOuter[idx] + # d2AnnulusOuter[idx] = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + + # rotFrame[j][2] * d2[2] for j in range(3)] + # + # # Make d1 on first half of eso point towards esophagus + # for n1 in range(1, elementsAroundHalfEso): + # rotAxis = d3Annulus[n1] + # rotAngle = math.pi + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) + # d1 = d1AnnulusOuter[n1] + # d1AnnulusOuter[n1] = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + + # rotFrame[j][2] * d1[2] for j in range(3)] + # + # # Flip d1 and d2 on xAnnulusOuter[0] + # d1 = d1AnnulusOuter[0] # original d1 + # rotAxis = d3Annulus[0] + # rotAngle = math.pi + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) + # d1Rot = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] + # + # d2 = d2AnnulusOuter[0] # original d2 + # rotAngle = math.pi + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) + # d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + # + # d2AnnulusOuter[0] = d1Rot # d2 is now d1 + # d1AnnulusOuter[0] = d2Rot # d1 is now d2 - curvature = annulusD2Curvature[0] + # + # # Flip d1 and d2 on xAnnulusOuter[halfEso] + # d1 = d1AnnulusOuter[elementsAroundHalfEso] # original d1 + # d2 = d2AnnulusOuter[elementsAroundHalfEso] # original d2 + # d2AnnulusOuter[elementsAroundHalfEso] = d1 # d2 is now d1 + # d1AnnulusOuter[elementsAroundHalfEso] = d2 # d1 is now d2 - curvature = annulusD2Curvature[halfEso] + # + # # x along GC and LC row - needs to be in 2 parts + # # GC + # xAlongGCHalfDuod = [] + # endGCEsoP2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] + # + # for n2 in range(len(xEllipseAroundAll)): + # xPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) + # p2 = trackSurfaceStomach.getProportion(xPosition) + # if p2[1] < endGCEsoP2: + # # xAlongGCHalfDuod.append(xAroundAllTransformed[n2][elementsAroundHalfDuod if n2 else 0]) + # xAlongGCHalfDuod.append(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) + # else: + # break + # + # xAlongGCHalfDuod.append(xAnnulusOuter[0]) + # + # rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * elementsAroundHalfDuod + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) + # d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + rotFrame[j][2] * d2Apex[2] for j in range(3)] + # + # d2AlongGCHalfDuod = [d2ApexRot] + # for n2 in range(1, len(xAlongGCHalfDuod) - 1): + # d = findDerivativeBetweenPoints(xAlongGCHalfDuod[n2], xAlongGCHalfDuod[n2 + 1]) + # d2AlongGCHalfDuod.append(d) + # d2AlongGCHalfDuod.append(d2AnnulusOuter[0]) + # + # xSampledAlongGCHalfDuod, d2SampledAlongGCHalfDuod = \ + # interp.sampleCubicHermiteCurvesSmooth(xAlongGCHalfDuod + [o1_x[-1][0]], d2AlongGCHalfDuod + [d2AnnulusOuter[0]], + # elementsAlongFundusApexToCardia + 1, + # derivativeMagnitudeEnd=vector.magnitude(d2AnnulusOuter[0]))[0:2] + # + # d2SampledAlongGCHalfDuod = \ + # interp.smoothCubicHermiteDerivativesLine(xSampledAlongGCHalfDuod, d2SampledAlongGCHalfDuod, + # fixEndDerivative=True) + # + # xAlongGCHalfDuod = xSampledAlongGCHalfDuod[:-1] + # d2AlongGCHalfDuod = d2SampledAlongGCHalfDuod[:-1] + # for n2 in range(len(xAlongGCHalfDuod)): + # xEllipseAroundAll[n2][elementsAroundHalfDuod] = xAlongGCHalfDuod[n2] + # + # # LC part + # elementsInBody = elementCountGroupList[1] + # xAnnulusOuterHalfEsoPosition = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[elementsAroundHalfEso]) + # startLCAnnulus = trackSurfaceStomach.getProportion(xAnnulusOuterHalfEsoPosition) + # + # xAlongLCHalfDuod = [xAnnulusOuter[elementsAroundHalfEso]] + # n2IdxEndBody = elementCountGroupList[0] + elementCountGroupList[1] + # + # if elementsInBody - elementsAroundQuarterEso + 1 > 1: + # xPositionEndBody = \ + # trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2IdxEndBody][elementsAroundHalfDuod]) + # xProportionEndBody = trackSurfaceStomach.getProportion(xPositionEndBody) + # + # nx, nd1, nd2, nd3, proportions = \ + # trackSurfaceStomach.createHermiteCurvePoints( + # startLCAnnulus[0], startLCAnnulus[1], xProportionEndBody[0], xProportionEndBody[1], + # elementsInBody - elementsAroundQuarterEso + 1, derivativeStart=d2AnnulusOuter[elementsAroundHalfEso]) + # + # nxNew, nd1New = \ + # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( + # nx, nd1, nd2, nd3, proportions, + # derivativeMagnitudeStart=vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso]))[0:2] + # xAlongLCHalfDuod += nxNew[1:-1] + # + # for n2 in range(sum(elementCountGroupList) - sum(elementCountGroupList[:2]) + 1): + # xAlongLCHalfDuod.append(xEllipseAroundAll[n2IdxEndBody + n2][elementsAroundHalfDuod]) + # + # d2AlongLCHalfDuod = [d2AnnulusOuter[elementsAroundHalfEso]] + # for n2 in range(1, len(xAlongLCHalfDuod)): + # d = findDerivativeBetweenPoints(xAlongLCHalfDuod[n2 - 1], xAlongLCHalfDuod[n2]) + # d2AlongLCHalfDuod.append(d) + # d2AlongLCHalfDuod[-1] = cd1Sections[-1][-1] + # + # if materialCoordinates: + # # Break point along at body-antrum and pylorus-duod intersection and smooth separately to keep derivative at + # # body end + # d2AlongBody = \ + # interp.smoothCubicHermiteDerivativesLine( + # xAlongLCHalfDuod[:elementsInBody - elementsAroundQuarterEso + 2], + # d2AlongLCHalfDuod[:elementsInBody - elementsAroundQuarterEso + 2], + # fixStartDirection=True, fixEndDirection=True) + # + # for n in range(elementCountGroupList[-1] + 1): + # d2AlongLCHalfDuod[-(n + 1)] = cd1Sections[-1][-1] + # + # d2AlongBodyToPylorus = \ + # interp.smoothCubicHermiteDerivativesLine( + # xAlongLCHalfDuod[elementsInBody - elementsAroundQuarterEso + 1:-n], + # d2AlongLCHalfDuod[elementsInBody - elementsAroundQuarterEso + 1:-n], + # fixStartDirection=True, fixEndDirection=True) + # d2AlongDuod = \ + # interp.smoothCubicHermiteDerivativesLine( + # xAlongLCHalfDuod[-(n + 1):], d2AlongLCHalfDuod[-(n + 1):], fixStartDirection=True, fixEndDirection=True) + # d2AlongLCHalfDuod = d2AlongBody[:-1] + d2AlongBodyToPylorus[:-1] + d2AlongDuod + # else: + # d2AlongLCHalfDuod = \ + # interp.smoothCubicHermiteDerivativesLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, + # fixStartDerivative=True, fixEndDirection=True) + # + # for n2 in range(len(xAlongLCHalfDuod)): + # xEllipseAroundAll[n2 + elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2][elementsAroundHalfDuod] = \ + # xAlongLCHalfDuod[n2] + # + # xAlongCurvatures = xAlongGCHalfDuod + xAlongLCHalfDuod + # d2AlongCurvatures = d2AlongGCHalfDuod + d2AlongLCHalfDuod + # + # esoCount = 1 + # # Find arclengths to points on quarter, GC and 3-quarter fundus as trackSurface search for nearest position doesnt + # # work well near apex + # proportionsAlongQuarterMidThree = [] + # count = 0 + # for n1 in [elementsAroundQuarterDuod, elementsAroundHalfDuod, elementsAroundQuarterDuod + elementsAroundHalfDuod]: + # xAlong = [] + # arcLength = 0.0 + # proportions = [] + # for n2 in range(elementsAlongFundusApexToCardia): + # xAlong.append(xEllipseAroundAll[n2][n1]) + # + # rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * n1 + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) + # d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + + # rotFrame[j][2] * d2Apex[2] for j in range(3)] + # d2Along = [d2ApexRot] + # + # for n2 in range(len(xAlong) - 1): + # d2Along.append(findDerivativeBetweenPoints(xAlong[n2], xAlong[n2 + 1])) + # + # for n2 in range(len(xAlong) - 1): + # arcLength += interp.getCubicHermiteArcLength(xAlong[n2], d2Along[n2], xAlong[n2 + 1], d2Along[n2 + 1]) + # proportion = arcLength / arcLengthsAlongTS[count] + # proportions.append(proportion) + # proportionsAlongQuarterMidThree.append(proportions) + # count += 1 + # + # for n2 in range(1, len(xEllipseAroundAll) - 1): + # startAnnulus = n2 == elementsAlongFundusApexToCardia + # endAnnulus = n2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 + # interiorAnnulus = \ + # elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 + # + # if startAnnulus or interiorAnnulus or endAnnulus: + # xEllipseAroundAll[n2][elementsAroundHalfDuod - 1] = xAnnulusOuter[esoCount] + # d1EllipseAroundAll[n2][elementsAroundHalfDuod - 1] = d1AnnulusOuter[esoCount] + # xEllipseAroundAll[n2][elementsAroundHalfDuod + 1] = xAnnulusOuter[-esoCount] + # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1] = d1AnnulusOuter[-esoCount] + # + # if startAnnulus or endAnnulus: + # xEllipseAroundAll[n2][elementsAroundHalfDuod] = \ + # xAnnulusOuter[0 if startAnnulus else elementsAroundHalfEso] + # + # xPositionA = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundQuarterDuod]) + # xProportionA = trackSurfaceStomach.getProportion(xPositionA) + # xPositionB = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[esoCount]) + # xProportionB = trackSurfaceStomach.getProportion(xPositionB) + # + # nx, nd1, nd2, nd3, proportions = \ + # trackSurfaceStomach.createHermiteCurvePoints( + # xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], elementsAroundQuarterDuod - 1, + # derivativeStart=d1EllipseAroundAll[n2][elementsAroundQuarterDuod]) + # + # nx, nd1 = \ + # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( + # nx, nd1, nd2, nd3, proportions, + # derivativeMagnitudeStart=vector.magnitude(d1EllipseAroundAll[n2][elementsAroundQuarterDuod]))[0:2] + # + # xEllipseAroundAll[n2][elementsAroundQuarterDuod + 1:elementsAroundHalfDuod - 1] = nx[1:-1] + # d1EllipseAroundAll[n2][elementsAroundQuarterDuod + 1:elementsAroundHalfDuod - 1] = nd1[1:-1] + # + # # Smooth two halves separately and join together again with d1 at xOuterAnnulus[0] and + # # xOuterAnnulus[elementsAroundHalfEso] + # d1SmoothedFirstHalf = \ + # interp.smoothCubicHermiteDerivativesLine(xEllipseAroundAll[n2][:elementsAroundHalfDuod], + # d1EllipseAroundAll[n2][:elementsAroundHalfDuod], + # fixEndDerivative=True if interiorAnnulus else None) + # + # if interiorAnnulus: + # d1EllipseAroundAll[n2][:elementsAroundHalfDuod] = d1SmoothedFirstHalf + # else: + # d1SmoothedFirstHalf[-1] = vector.setMagnitude(d1SmoothedFirstHalf[-1], + # 0.5 * (vector.magnitude(d1SmoothedFirstHalf[-2]) + + # vector.magnitude(d1AnnulusOuter[1]))) + # + # xPositionA = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[-esoCount]) + # xProportionA = trackSurfaceStomach.getProportion(xPositionA) + # xPositionB = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundHalfDuod + + # elementsAroundQuarterDuod]) + # xProportionB = trackSurfaceStomach.getProportion(xPositionB) + # + # nx, nd1, nd2, nd3, proportions = \ + # trackSurfaceStomach.createHermiteCurvePoints( + # xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + # elementsAroundQuarterDuod - 1, + # derivativeEnd=d1EllipseAroundAll[n2][elementsAroundHalfDuod + elementsAroundQuarterDuod]) + # + # nx, nd1 = \ + # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( + # nx, nd1, nd2, nd3, proportions, + # derivativeMagnitudeEnd=vector.magnitude(d1EllipseAroundAll[n2][elementsAroundHalfDuod + + # elementsAroundQuarterDuod]))[0:2] + # + # xEllipseAroundAll[n2][elementsAroundHalfDuod + 2:elementsAroundHalfDuod + elementsAroundQuarterDuod] = \ + # nx[1:-1] + # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 2:elementsAroundHalfDuod + elementsAroundQuarterDuod] = \ + # nd1[1:-1] + # + # esoCount += 1 + # if startAnnulus or endAnnulus: + # d1SmoothedSecondHalf = \ + # interp.smoothCubicHermiteDerivativesLine( + # xEllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + [xEllipseAroundAll[n2][0]], + # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + [d1SmoothedFirstHalf[0]], + # fixEndDerivative=True) + # d1SmoothedSecondHalf[0] = vector.setMagnitude(d1SmoothedSecondHalf[0], + # 0.5 * (vector.magnitude(d1SmoothedFirstHalf[1]) + + # vector.magnitude(d1AnnulusOuter[1]))) + # + # d1EllipseAroundAll[n2] = d1SmoothedFirstHalf + \ + # [d1AnnulusOuter[0 if startAnnulus else elementsAroundHalfEso]] + \ + # d1SmoothedSecondHalf[:-1] + # else: + # d1Smoothed = \ + # interp.smoothCubicHermiteDerivativesLine(xEllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + + # [xEllipseAroundAll[n2][0]], + # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + + # [d1EllipseAroundAll[n2][0]], + # fixStartDerivative=True, fixEndDerivative=True) + # + # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] = d1Smoothed[:-1] + # + # del xEllipseAroundAll[n2][elementsAroundHalfDuod] + # del d1EllipseAroundAll[n2][elementsAroundHalfDuod] + # del d2EllipseAroundAll[n2][elementsAroundHalfDuod] + # + # elif 0 < n2 < elementsAlongFundusApexToCardia or \ + # elementsAlongFundusApexToCardia + elementsAroundHalfEso - 1 <= n2 < elementsAlongFundusApexToCardia + \ + # elementsAroundHalfEso + elementsInBody - elementsAroundQuarterEso - 1: + # if 0 < n2 < elementsAlongFundusApexToCardia: + # xToSample = [xEllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ + # [xAlongGCHalfDuod[n2]] + \ + # [xEllipseAroundAll[n2][elementsAroundQuarterDuod + elementsAroundHalfDuod]] + # xToSampleProportion0 = [0.25, 0.5, 0.75] + # xToSampleProportion1 = [proportionsAlongQuarterMidThree[0][n2 - 1], + # proportionsAlongQuarterMidThree[1][n2 - 1], + # proportionsAlongQuarterMidThree[2][n2 - 1]] + # else: + # n2Idx = n2 - (elementsAlongFundusApexToCardia + elementsAroundHalfEso - 1) + 1 + # xToSample = [xEllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ + # [xAlongLCHalfDuod[n2Idx]] + \ + # [xEllipseAroundAll[n2][elementsAroundQuarterDuod + elementsAroundHalfDuod]] + # + # d1ToSample = [d1EllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ + # [d1EllipseAroundAll[n2][elementsAroundHalfDuod]] + \ + # [d1EllipseAroundAll[n2][elementsAroundHalfDuod + elementsAroundQuarterDuod]] + # + # if 0 < n2 < elementsAlongFundusApexToCardia: + # xProportionA = [xToSampleProportion0[0], xToSampleProportion1[0]] + # xProportionB = [xToSampleProportion0[1], xToSampleProportion1[1]] + # xProportionC = [xToSampleProportion0[2], xToSampleProportion1[2]] + # + # else: + # xPositionA = trackSurfaceStomach.findNearestPosition(xToSample[0]) + # xProportionA = trackSurfaceStomach.getProportion(xPositionA) + # xPositionB = trackSurfaceStomach.findNearestPosition(xToSample[1]) + # xProportionB = trackSurfaceStomach.getProportion(xPositionB) + # xPositionC = trackSurfaceStomach.findNearestPosition(xToSample[2]) + # xProportionC = trackSurfaceStomach.getProportion(xPositionC) + # + # nx, nd1, nd2, nd3, proportions = \ + # trackSurfaceStomach.createHermiteCurvePoints( + # xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + # elementsAroundQuarterDuod, derivativeStart=d1ToSample[0], derivativeEnd=d1ToSample[1]) + # if n2 == 1: + # sampledProportionsOneLeft = proportions + # nxLeft, nd1Left = \ + # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( + # nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=vector.magnitude(d1ToSample[0]))[0:2] + # + # nx, nd1, nd2, nd3, proportions = \ + # trackSurfaceStomach.createHermiteCurvePoints( + # xProportionB[0], xProportionB[1], xProportionC[0], xProportionC[1], elementsAroundQuarterDuod, + # derivativeStart=d1ToSample[1], derivativeEnd=d1ToSample[2]) + # if n2 == 1: + # sampledProportionsOneRight = proportions + # nxRight, nd1Right = \ + # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( + # nx, nd1, nd2, nd3, proportions, derivativeMagnitudeEnd=vector.magnitude(d1ToSample[2]))[0:2] + # + # xNew = nxLeft[1:] + nxRight[1:-1] + # d1New = nd1Left[1:] + nd1Right[1:-1] + # + # xEllipseAroundAll[n2][elementsAroundQuarterDuod + 1:-elementsAroundQuarterDuod] = xNew + # d1EllipseAroundAll[n2][elementsAroundQuarterDuod + 1:-elementsAroundQuarterDuod] = d1New + # + # d1EllipseAroundAll[n2] = interp.smoothCubicHermiteDerivativesLoop(xEllipseAroundAll[n2], + # d1EllipseAroundAll[n2]) + # + # # Calculate and smooth d2 + # xAlongAll = [] + # for n1 in range(elementsAroundHalfDuod - 1): + # xAlong = [] + # for n2 in range(len(xEllipseAroundAll)): + # xAlong.append(xEllipseAroundAll[n2][n1 if n2 else 0]) + # xAlongAll.append(xAlong) + # + # # Row with annulus - left + # xAlong = [] + # for n2 in range(len(xEllipseAroundAll)): + # xAlong.append(xEllipseAroundAll[n2][elementsAroundHalfDuod - 1 if n2 else 0]) + # xAlongAll.append(xAlong) + # + # xAlongAll.append(xAlongCurvatures) + # + # for n1 in range(elementsAroundHalfDuod - 1): + # xAlong = [] + # for n2 in range(len(xEllipseAroundAll)): + # if n2 == 0: + # ringIdx = 0 + # elif elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: + # ringIdx = n1 + elementsAroundHalfDuod + # else: + # ringIdx = n1 + elementsAroundHalfDuod + 1 + # xAlong.append(xEllipseAroundAll[n2][ringIdx]) + # xAlongAll.append(xAlong) + # + # d2AlongAll = [] + # for n1 in range(elementsCountAroundDuod): + # rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * n1 + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) + # d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + + # rotFrame[j][2] * d2Apex[2] for j in range(3)] + # + # if n1 == elementsAroundHalfDuod: # Process LC and GC + # # GC + # # Resample point downstream from apex + # nx = \ + # trackSurfaceStomach.createHermiteCurvePoints( + # sampledProportionsOneLeft[-2][0], sampledProportionsOneLeft[-2][1], + # sampledProportionsOneRight[1][0], sampledProportionsOneRight[1][1], 2, + # derivativeStart=d1EllipseAroundAll[1][elementsAroundHalfDuod - 1], + # derivativeEnd=d1EllipseAroundAll[1][elementsAroundHalfDuod + 1])[0] + # + # xEllipseAroundAll[1][elementsAroundHalfDuod] = nx[1] + # + # d1EllipseAroundAll[1] = interp.smoothCubicHermiteDerivativesLoop(xEllipseAroundAll[1], + # d1EllipseAroundAll[1]) + # + # xAlongGCHalfDuodNew = [] + # for n2 in range(elementsAlongFundusApexToCardia + 1): + # xAlongGCHalfDuodNew.append(xEllipseAroundAll[n2][elementsAroundHalfDuod]) + # + # d2AlongGCHalfDuodNew = [d2ApexRot] + # for n2 in range(1, len(xAlongGCHalfDuodNew) - 1): + # d = findDerivativeBetweenPoints(xAlongGCHalfDuodNew[n2], xAlongGCHalfDuodNew[n2 + 1]) + # d2AlongGCHalfDuodNew.append(d) + # d2AlongGCHalfDuodNew.append(d2AnnulusOuter[0]) + # + # d2AlongGCHalfDuodNew = \ + # interp.smoothCubicHermiteDerivativesLine(xAlongGCHalfDuodNew + [o1_x[-1][0]], + # d2AlongGCHalfDuodNew + [d2AnnulusOuter[0]], + # fixEndDerivative=True)[:-1] + # d2AlongCurvatures[:len(d2AlongGCHalfDuodNew)] = d2AlongGCHalfDuodNew + # d2AlongAll.append(d2AlongCurvatures) + # + # else: + # d2Along = [d2ApexRot] + # for n2 in range(1, len(xAlongAll[n1])): + # d = findDerivativeBetweenPoints(xAlongAll[n1][n2 - 1], xAlongAll[n1][n2]) + # d2Along.append(d) + # d2Along[-1] = cd1Sections[-1][-1] + # + # if materialCoordinates: + # # Break point along at body-antrum and pylorus-duod intersection and smooth separately to keep + # # derivative at body end + # d2AlongFundusBody = \ + # interp.smoothCubicHermiteDerivativesLine( + # xAlongAll[n1][:elementCountGroupList[0] + elementCountGroupList[1] + 1], + # d2Along[:elementCountGroupList[0] + elementCountGroupList[1] + 1], + # fixStartDirection=True, fixEndDirection=True) + # + # for n in range(elementCountGroupList[-1] + 1): + # d2Along[-(n + 1)] = cd1Sections[-1][-1] + # + # d2AlongBodyToPylorus = \ + # interp.smoothCubicHermiteDerivativesLine( + # xAlongAll[n1][elementCountGroupList[0] + elementCountGroupList[1]:-n], + # d2Along[elementCountGroupList[0] + elementCountGroupList[1]:-n], + # fixStartDirection=True, fixEndDirection=True) + # + # d2AlongDuod = \ + # interp.smoothCubicHermiteDerivativesLine( + # xAlongAll[n1][-(n + 1):], d2Along[-(n + 1):], fixStartDirection=True, fixEndDirection=True) + # + # d2Along = d2AlongFundusBody[:-1] + d2AlongBodyToPylorus[:-1] + d2AlongDuod + # else: + # d2Along = interp.smoothCubicHermiteDerivativesLine(xAlongAll[n1], d2Along, fixStartDirection=True, + # fixEndDirection=True) + # if n1 == elementsAroundHalfDuod - 1 or n1 == elementsAroundHalfDuod + 1: + # d2Along[elementsAlongFundusApexToCardia] = \ + # vector.setMagnitude(d2Along[elementsAlongFundusApexToCardia], + # 0.5 * (vector.magnitude(d2Along[elementsAlongFundusApexToCardia]) + + # vector.magnitude(d2AnnulusOuter[1]))) + # d2Along[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2] = \ + # vector.setMagnitude(d2Along[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2], + # 0.5 * (vector.magnitude(d2Along[elementsAlongFundusApexToCardia + + # elementsAroundHalfEso - 2]) + + # vector.magnitude(d2AnnulusOuter[1]))) + # d2AlongAll.append(d2Along) + # + # # Replace d2 for points sitting on annulus + # for n2 in range(2, elementsAroundHalfEso - 1): + # n2Idx = n2 + elementsAlongFundusApexToCardia - 1 + # d2AlongAll[elementsAroundHalfDuod - 1][n2Idx] = d2AnnulusOuter[n2] + # d2AlongAll[elementsAroundHalfDuod + 1][n2Idx] = d2AnnulusOuter[-n2] + # + # # Re-arrange back to around followed by along + # for n2 in range(len(xEllipseAroundAll)): + # incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ + # elementsAroundHalfEso - 2 + # for n1 in range(len(xEllipseAroundAll[n2]) + (1 if incompleteRingsWithinEso else 0)): + # if incompleteRingsWithinEso: + # if n1 == elementsAroundHalfDuod: + # pass + # else: + # d2EllipseAroundAll[n2][n1 - (1 if n1 > elementsAroundHalfDuod else 0)] = d2AlongAll[n1][n2] + # elif n2 >= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: + # d2EllipseAroundAll[n2][n1] = \ + # d2AlongAll[n1][n2 - (elementsAroundHalfEso + 1 - 4 if n1 == elementsAroundHalfDuod else 0)] + # else: + # d2EllipseAroundAll[n2][n1] = d2AlongAll[n1][n2] + # + # xOuter = xEllipseAroundAll + # d1Outer = d1EllipseAroundAll + # d2Outer = d2EllipseAroundAll + # + # # Calculate d3 + # d3UnitOuter = [] + # for n2 in range(len(xOuter)): + # d3Around = [] + # for n1 in range(len(xOuter[n2])): + # if n2 == 0: + # d3Around.append(rotAxisApex) + # else: + # d3Around.append(vector.normalise( + # vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) + # d3UnitOuter.append(d3Around) + # + # # Calculate curvature around + # d1Curvature = [] + # d1Curvature.append([1.0 for n in range(len(xOuter[0]))]) # Will be replaced in later step + # esoCount = 1 + # for n2 in range(1, len(xOuter)): + # incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ + # elementsAroundHalfEso - 2 + # completeRingsOnCardia = (n2 == elementsAlongFundusApexToCardia or n2 == elementsAlongFundusApexToCardia + + # elementsAroundHalfEso - 2) + # if incompleteRingsWithinEso: + # d2 = o1_d2[-1][esoCount] + # rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(o1_d1[-1][esoCount]), + # vector.normalise(o1_d2[-1][esoCount]))) + # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + # d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + # d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod] + [o1_x[-1][esoCount]], + # d1Outer[n2][:elementsAroundHalfDuod] + [d2Rot], + # d3UnitOuter[n2][:elementsAroundHalfDuod] + [rotAxis]) + # curvature = interp.getCubicHermiteCurvature(xAnnulusOuter[esoCount], d1AnnulusOuter[esoCount], + # o1_x[-1][esoCount], d2Rot, + # d3UnitOuter[n2][elementsAroundHalfDuod - 1], 0.0) + # d1CurvatureFirstHalf[-2] = curvature + # + # d3 = vector.normalise(vector.crossproduct3(vector.normalise(o1_d1[-1][-esoCount]), + # vector.normalise(o1_d2[-1][-esoCount]))) + # d1CurvatureSecondHalf = findCurvatureAlongLine([o1_x[-1][-esoCount]] + + # xOuter[n2][elementsAroundHalfDuod:] + [xOuter[n2][0]], + # [o1_d2[-1][-esoCount]] + + # d1Outer[n2][elementsAroundHalfDuod:] + [d1Outer[n2][0]], + # [d3] + d3UnitOuter[n2][elementsAroundHalfDuod:] + + # [d3UnitOuter[n2][0]])[:-1] + # + # curvature = interp.getCubicHermiteCurvature(o1_x[-1][-esoCount], o1_d2[-1][-esoCount], + # xAnnulusOuter[-esoCount], d1AnnulusOuter[-esoCount], + # d3UnitOuter[n2][elementsAroundHalfDuod], 1.0) + # d1CurvatureSecondHalf[1] = curvature + # d1Curvature.append(d1CurvatureFirstHalf[:-1] + d1CurvatureSecondHalf[1:]) + # esoCount += 1 + # + # elif completeRingsOnCardia: + # d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod], + # d1Outer[n2][:elementsAroundHalfDuod], + # d3UnitOuter[n2][:elementsAroundHalfDuod]) + # + # d1CurvatureSecondHalf = findCurvatureAlongLine(xOuter[n2][elementsAroundHalfDuod + 1:] + [xOuter[n2][0]], + # d1Outer[n2][elementsAroundHalfDuod + 1:] + [d1Outer[n2][0]], + # d3UnitOuter[n2][elementsAroundHalfDuod + 1:] + + # [d3UnitOuter[n2][0]])[:-1] + # + # midPtCurvature = annulusD2Curvature[0 if n2 == elementsAlongFundusApexToCardia else elementsAroundHalfEso] + # d1Curvature.append(d1CurvatureFirstHalf + [midPtCurvature] + d1CurvatureSecondHalf) + # esoCount += 1 + # else: + # d1Curvature.append(findD1CurvatureAround(xOuter[n2], d1Outer[n2], d3UnitOuter[n2])) + # + # # Populate d3Along for use to calculate curvature along + # d3UnitAlongAll = [] + # for n1 in range(elementsAroundHalfDuod - 1): + # d3Along = [] + # for n2 in range(len(d3UnitOuter)): + # d3Along.append(d3UnitOuter[n2][n1 if n2 else 0]) + # d3UnitAlongAll.append(d3Along) + # + # # Row wth annulus - left + # d3Along = [] + # for n2 in range(len(d3UnitOuter)): + # d3Along.append(d3UnitOuter[n2][elementsAroundHalfDuod - 1 if n2 else 0]) + # d3UnitAlongAll.append(d3Along) + # + # # GC and LC row - needs to be in 2 parts + # # GC part + # d3AlongGCHalfDuod = [] + # for n2 in range(elementsAlongFundusApexToCardia + 1): + # d3AlongGCHalfDuod.append(d3UnitOuter[n2][elementsAroundHalfDuod if n2 else 0]) + # + # # LC part + # d3AlongLCHalfDuod = [] + # for n2 in range(elementsAlongCardiaToDuod + 1): + # d3AlongLCHalfDuod.append(d3UnitOuter[n2 + elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2] + # [elementsAroundHalfDuod]) + # d3Along = d3AlongGCHalfDuod + d3AlongLCHalfDuod + # d3UnitAlongAll.append(d3Along) + # + # for n1 in range(elementsAroundHalfDuod - 1): + # d3Along = [] + # for n2 in range(len(d3UnitOuter)): + # if n2 == 0: + # ringIdx = 0 + # elif elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: + # ringIdx = n1 + elementsAroundHalfDuod + # else: + # ringIdx = n1 + elementsAroundHalfDuod + 1 + # d3Along.append(d3UnitOuter[n2][ringIdx]) + # d3UnitAlongAll.append(d3Along) + # + # # Calculate curvature along + # d2CurvatureAlong = [] + # for n1 in range(len(xAlongAll)): + # if n1 == elementsAroundHalfDuod: # Process LC and GC + # # GC + # d2CurvatureAlongGCHalfDuod = findCurvatureAlongLine(xAlongGCHalfDuod, d2AlongGCHalfDuod, d3AlongGCHalfDuod) + # # LC + # d2CurvatureAlongLCHalfDuod = findCurvatureAlongLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, d3AlongLCHalfDuod) + # d2CurvaturesAlongCurvature = d2CurvatureAlongGCHalfDuod + d2CurvatureAlongLCHalfDuod + # d2CurvatureAlong.append(d2CurvaturesAlongCurvature) + # else: + # curvature = findCurvatureAlongLine(xAlongAll[n1], d2AlongAll[n1], d3UnitAlongAll[n1]) + # # replace with curvature from annulus + # if n1 == elementsAroundHalfDuod - 1 or n1 == elementsAroundHalfDuod + 1: + # for n2 in range(2, elementsAroundHalfEso - 1): + # n2Idx = n2 + elementsAlongFundusApexToCardia + 1 + # curvature[n2Idx] = annulusD2Curvature[(n2 + 1 if elementsAroundHalfDuod - 1 else -(n2 + 1))] + # d2CurvatureAlong.append(curvature) + # + # # Re-arrange back to around followed by along + # for n2 in range(len(xEllipseAroundAll)): + # incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ + # elementsAroundHalfEso - 2 + # for n1 in range(len(xEllipseAroundAll[n2]) + (1 if incompleteRingsWithinEso else 0)): + # if incompleteRingsWithinEso: + # if n1 == elementsAroundHalfDuod: + # pass + # else: + # d2Curvature[n2][n1 - (1 if n1 > elementsAroundHalfDuod else 0)] = d2CurvatureAlong[n1][n2] + # elif n2 >= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: + # d2Curvature[n2][n1] = \ + # d2CurvatureAlong[n1][n2 - (elementsAroundHalfEso + 1 - 4 if n1 == elementsAroundHalfDuod else 0)] + # else: + # d2Curvature[n2][n1] = d2CurvatureAlong[n1][n2] + # + # # Replace d1Curvature at apex with d2Curvature + # for n1 in range(elementsCountAroundDuod): + # d1Curvature[0][n1] = d2Curvature[0][n1] + # + # # Create inner nodes + # xList = [] + # d1List = [] + # d2List = [] + # d3List = [] + # nodeIdx = stomachStartNode + # idxMat = [] + # + # if elementsCountThroughWall > 1: + # thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, + # longitudinalRelThickness, longitudinalRelThickness] + # thicknessProportions = [thicknessProportion / sum(thicknessProportionsUI[:-1]) + # for thicknessProportion in thicknessProportionsUI] + # + # xi3List = [] + # xi3 = 0.0 + # for i in range(len(thicknessProportions) - 1): + # xi3 += thicknessProportions[i] + # xi3List.append(xi3) + # + # for n2 in range(len(xOuter)): + # idxThroughWall = [] + # for n3 in range(elementsCountThroughWall + 1): + # xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 + # idxAround = [] + # for n1 in range(1 if n2 == 0 else len(xOuter[n2])): + # # Coordinates + # norm = d3UnitOuter[n2][n1] + # xOut = xOuter[n2][n1] + # xIn = [xOut[i] - norm[i] * wallThickness for i in range(3)] + # dWall = [wallThickness * c for c in norm] + # x = interp.interpolateCubicHermite(xIn, dWall, xOut, dWall, xi3) + # xList.append(x) + # + # # d1 + # factor = 1.0 + wallThickness * (1.0 - xi3) * d1Curvature[n2][n1] + # d1 = [factor * c for c in d1Outer[n2][n1]] + # d1List.append(d1) + # + # # d2 + # factor = 1.0 + wallThickness * (1.0 - xi3) * d2Curvature[n2][n1] + # d2 = [factor * c for c in d2Outer[n2][n1]] + # d2List.append(d2) + # + # # d3 + # d3 = [c * wallThickness * (thicknessProportions[n3 + 1] if elementsCountThroughWall > 1 else 1.0) + # for c in norm] + # d3List.append(d3) + # + # idxAround.append(nodeIdx) + # nodeIdx += 1 + # idxThroughWall.append(idxAround) + # idxMat.append(idxThroughWall) + # + # nodeIdxGC = [] + # for n2 in range(len(idxMat)): + # for n3 in range(len(idxMat[n2])): + # if n2 == 0: + # nodeIdxGC += idxMat[n2][n3] + # else: + # nodeIdxGC.append(idxMat[n2][n3][0]) + # + # for n2 in range(1, elementsAlongFundusApexToCardia + 1): + # for n3 in range(len(idxMat[n2])): + # nodeIdxGC.append(idxMat[n2][n3][int(0.5 * len(xOuter[n2]))]) + # + # nodeIdxLC = [] + # for n2 in range(elementsAlongCardiaToDuod + 1): + # for n3 in range(len(idxMat[n2])): + # nodeIdxLC.append( + # idxMat[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 + n2][n3][elementsAroundHalfDuod]) + # + # for n2 in range(len(xList)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xList[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1List[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2List[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n2]) + # 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 += 1 + # + # annotationGroupsAlong = [] + # for i in range(len(elementCountGroupList)): + # elementsCount = elementCountGroupList[i] + # for n in range(elementsCount): + # annotationGroupsAlong.append(annotationGroupAlong[i]) + # + # # Create elements + # fundusMucosaElementIdentifiers = [] + # elementIdxMat = [] + # n = 0 + # for n2 in range(elementsAlongEsophagus): + # elementIdxThroughWall = [] + # for n3 in range(elementsThroughEsophagusWall): + # elementIdxAround = [] + # for n1 in range(elementsCountAroundEso): + # n += 1 + # elementIdxAround.append(n) + # elementIdxThroughWall.append(elementIdxAround) + # elementIdxMat.append(elementIdxThroughWall) + # + # if useCubicHermiteThroughWall: + # eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives) + # else: + # eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) + # eftStandard = eftfactory.createEftBasic() + # + # elementtemplateStandard = mesh.createElementtemplate() + # elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) + # elementtemplateStandard.defineField(coordinates, -1, eftStandard) + # + # elementtemplateX = mesh.createElementtemplate() + # elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + # + # fundusElements = elementCountGroupList[0] + # radiansPerElementAroundDuod = math.pi * 2.0 / elementsCountAroundDuod + # + # for e2 in range(len(xOuter) - 1): + # elementIdxThroughWall = [] + # if e2 == 0: # pole + # for e3 in range(elementsCountThroughWall): + # elementIdxAround = [] + # for e1 in range(elementsCountAroundDuod): + # va = e1 + # vb = (e1 + 1) % elementsCountAroundDuod + # eft1 = eftfactory.createEftShellPoleBottom(va*100, vb*100) + # elementtemplateX.defineField(coordinates, -1, eft1) + # element = mesh.createElement(elementIdentifier, elementtemplateX) + # bni1 = e3 + stomachStartNode + # bni2 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + e1 + # bni3 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + \ + # (e1 + 1) % elementsCountAroundDuod + # nodeIdentifiers = [bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAroundDuod, + # bni3 + elementsCountAroundDuod] + # + # element.setNodesByIdentifier(eft1, nodeIdentifiers) + # # set general linear map coefficients + # radiansAround = e1 * radiansPerElementAroundDuod + # radiansAroundNext = ((e1 + 1) % elementsCountAroundDuod) * radiansPerElementAroundDuod + # scalefactors = [ + # -1.0, + # math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, + # math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod, + # math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, + # math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod + # ] + # element.setScaleFactors(eft1, scalefactors) + # if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: + # fundusMucosaElementIdentifiers.append(elementIdentifier) + # elementIdxAround.append(elementIdentifier) + # elementIdentifier += 1 + # annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + # if annotationGroups: + # allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + # for annotationGroup in annotationGroups: + # meshGroup = annotationGroup.getMeshGroup(mesh) + # meshGroup.addElement(element) + # elementIdxThroughWall.append(elementIdxAround) + # elementIdxMat.append(elementIdxThroughWall) + # + # elif 0 < e2 < elementsAlongFundusApexToCardia or \ + # e2 > elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: + # for e3 in range(elementsCountThroughWall): + # elementIdxAround = [] + # for e1 in range(len(xOuter[e2])): + # eft1 = eftStandard + # scaleFactors = [] + # elementtemplate1 = elementtemplateStandard + # bni111 = idxMat[e2][e3][e1] + # bni211 = idxMat[e2][e3][(e1 + 1) % len(idxMat[e2][e3])] + # bni121 = idxMat[e2 + 1][e3][e1] + # bni221 = idxMat[e2 + 1][e3][(e1 + 1) % len(idxMat[e2 + 1][e3])] + # bni112 = idxMat[e2][e3 + 1][e1] + # bni212 = idxMat[e2][e3 + 1][(e1 + 1) % len(idxMat[e2][e3])] + # bni122 = idxMat[e2 + 1][e3 + 1][e1] + # bni222 = idxMat[e2 + 1][e3 + 1][(e1 + 1) % len(idxMat[e2 + 1][e3])] + # nodeIdentifiers = [bni111, bni211, bni121, bni221, + # bni112, bni212, bni122, bni222] + # + # if e2 == elementsAlongFundusApexToCardia - 1: + # if e1 == int(0.5 * len(xOuter[e2]) - 2): + # eft1 = eftfactory.createEftNoCrossDerivatives() + # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # elif e1 == int(0.5 * len(xOuter[e2]) - 1): + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # elif e1 == int(0.5 * len(xOuter[e2])): + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # elif e1 == int(0.5 * len(xOuter[e2]) + 1): + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # if e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: + # if e1 == int(0.5 * len(xOuter[e2]) - 2): + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # elif e1 == int(0.5 * len(xOuter[e2]) - 1): + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # elif e1 == int(0.5 * len(xOuter[e2])): + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # elif e1 == int(0.5 * len(xOuter[e2]) + 1): + # eft1 = eftfactory.createEftNoCrossDerivatives() + # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # element = mesh.createElement(elementIdentifier, elementtemplate1) + # element.setNodesByIdentifier(eft1, nodeIdentifiers) + # if scaleFactors: + # element.setScaleFactors(eft1, scaleFactors) + # if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: + # fundusMucosaElementIdentifiers.append(elementIdentifier) + # elementIdxAround.append(elementIdentifier) + # elementIdentifier += 1 + # annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + # if annotationGroups: + # allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + # for annotationGroup in annotationGroups: + # meshGroup = annotationGroup.getMeshGroup(mesh) + # meshGroup.addElement(element) + # elementIdxThroughWall.append(elementIdxAround) + # elementIdxMat.append(elementIdxThroughWall) + # + # elif elementsAlongFundusApexToCardia <= e2 <= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: + # for e3 in range(elementsCountThroughWall): + # elementIdxAround = [] + # for e1 in range(elementsCountAroundDuod - 2): + # eft1 = eftStandard + # scaleFactors = [] + # elementtemplate1 = elementtemplateStandard + # if e1 > elementsAroundHalfDuod - 2: + # if elementsAlongFundusApexToCardia == e2: # first ring in eso + # e1IdxBni1 = e1 + 2 + # e1IdxBni3 = e1 + 1 + # elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: + # # last ring in esophagus + # e1IdxBni1 = e1 + 1 + # e1IdxBni3 = e1 + 2 + # elif elementsAlongFundusApexToCardia < e2 < elementsAlongFundusApexToCardia + \ + # elementsAroundHalfEso - 3: # incomplete rings interior of eso + # e1IdxBni1 = e1 + 1 + # e1IdxBni3 = e1 + 1 + # else: + # e1IdxBni1 = e1 + # e1IdxBni3 = e1 + # bni1 = idxMat[e2][e3][e1IdxBni1] + # bni2 = idxMat[e2][e3][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] + # bni3 = idxMat[e2 + 1][e3][e1IdxBni3] + # bni4 = idxMat[e2 + 1][e3][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] + # bni5 = idxMat[e2][e3 + 1][e1IdxBni1] + # bni6 = idxMat[e2][e3 + 1][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] + # bni7 = idxMat[e2 + 1][e3 + 1][e1IdxBni3] + # bni8 = idxMat[e2 + 1][e3 + 1][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] + # nodeIdentifiers = [bni1, bni2, bni3, bni4, bni5, bni6, bni7, bni8] + # + # if e2 == elementsAlongFundusApexToCardia and e1 == elementsAroundHalfDuod - 2: + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3 and \ + # e1 == elementsAroundHalfDuod - 2: + # eft1 = eftfactory.createEftNoCrossDerivatives() + # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3 and \ + # e1 == elementsAroundHalfDuod - 1: + # scaleFactors = [-1.0] + # eft1 = eftfactory.createEftNoCrossDerivatives() + # setEftScaleFactorIds(eft1, [1], []) + # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # elif e2 == elementsAlongFundusApexToCardia and e1 == elementsAroundHalfDuod - 1: + # eft1 = eftfactory.createEftNoCrossDerivatives() + # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + # elementtemplateX.defineField(coordinates, -1, eft1) + # elementtemplate1 = elementtemplateX + # + # element = mesh.createElement(elementIdentifier, elementtemplate1) + # element.setNodesByIdentifier(eft1, nodeIdentifiers) + # if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: + # fundusMucosaElementIdentifiers.append(elementIdentifier) + # elementIdxAround.append(elementIdentifier) + # if scaleFactors: + # element.setScaleFactors(eft1, scaleFactors) + # elementIdentifier += 1 + # annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + # if annotationGroups: + # allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + # for annotationGroup in annotationGroups: + # meshGroup = annotationGroup.getMeshGroup(mesh) + # meshGroup.addElement(element) + # elementIdxThroughWall.append(elementIdxAround) + # elementIdxMat.append(elementIdxThroughWall) + # + # # Annulus + # # Assemble endPoints for annulus + # endPoints_x = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + # endPoints_d1 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + # endPoints_d2 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + # endNode_Id = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + # endDerivativesMap = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + # endProportions = [] + # + # for n3 in range(elementsCountThroughWall + 1): + # n1 = 0 + # for nAround in range(elementsCountAroundEso): + # if nAround == 0: + # idx = idxMat[elementsAlongFundusApexToCardia][n3][elementsAroundHalfDuod] + # elif 0 < nAround < elementsAroundHalfEso: + # idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][elementsAroundHalfDuod - 1] + # n1 += 1 + # elif nAround == elementsAroundHalfEso: + # n1 -= 1 + # idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][elementsAroundHalfDuod] + # else: + # idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][ + # elementsAroundHalfDuod + (1 if (n1 == elementsAroundHalfEso - 2 or n1 == 0) else 0)] + # n1 -= 1 + # + # endPoints_x[n3][nAround] = xList[idx - stomachStartNode] + # endPoints_d1[n3][nAround] = d1List[idx - stomachStartNode] + # endPoints_d2[n3][nAround] = d2List[idx - stomachStartNode] + # endNode_Id[n3][nAround] = idx + # + # if n3 == elementsCountThroughWall: # outer layer + # endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) + # endProportions.append(trackSurfaceStomach.getProportion(endPosition)) + # + # for n3 in range(elementsCountThroughWall + 1): + # for nAround in range(elementsCountAroundEso): + # if nAround == 0: + # endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, -1, 0), None) + # elif nAround == 1: + # endDerivativesMap[n3][nAround] = ((-1, 1, 0), (-1, -1, 0), None) + # elif 1 < nAround < elementsAroundHalfEso - 1: + # endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) + # elif nAround == elementsAroundHalfEso - 1: + # endDerivativesMap[n3][nAround] = ((1, 1, 0), (-1, 1, 0), None) + # elif nAround == elementsAroundHalfEso: + # endDerivativesMap[n3][nAround] = (None, None, None) + # elif nAround == elementsAroundHalfEso + 1: + # endDerivativesMap[n3][nAround] = ((1, -1, 0), (1, 1, 0), None) + # elif elementsAroundHalfEso + 1 < nAround < elementsCountAroundEso - 1: + # endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) + # elif nAround == elementsCountAroundEso - 1: + # endDerivativesMap[n3][nAround] = ((-1, -1, 0), (1, -1, 0), None) + # + # startProportions = [] + # for n in range(elementsCountAroundEso): + # startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) + # + # cardiaGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, + # get_stomach_term("cardia of stomach")) + # cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) + # if cardiaGroup not in allAnnotationGroups: + # allAnnotationGroups.append(cardiaGroup) + # + # lastDuodenumElementIdentifier = elementIdentifier + # + # stomachWallAnnotationGroups = [] + # if elementsCountThroughWall == 4: + # stomachWallAnnotationGroups = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], + # [longitudinalMuscleGroup]] + # + # # Remove mucosa layer from annulus + # if elementsCountThroughWall == 4 and limitingRidge: + # o1_x = o1_x[1:] + # o1_d1 = o1_d1[1:] + # o1_d2 = o1_d2[1:] + # o1_NodeId = o1_NodeId[1:] + # endPoints_x = endPoints_x[1:] + # endPoints_d1 = endPoints_d1[1:] + # endPoints_d2 = endPoints_d2[1:] + # endNode_Id = endNode_Id[1:] + # endDerivativesMap = endDerivativesMap[1:] + # stomachWallAnnotationGroups = stomachWallAnnotationGroups[1:] + # + # nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( + # nodes, mesh, nodeIdentifier, elementIdentifier, + # o1_x, o1_d1, o1_d2, None, o1_NodeId, None, + # endPoints_x, endPoints_d1, endPoints_d2, None, endNode_Id, endDerivativesMap, + # elementsCountRadial=elementsCountAcrossCardia, meshGroups=[stomachMeshGroup, cardiaMeshGroup], + # wallAnnotationGroups=stomachWallAnnotationGroups, + # tracksurface=trackSurfaceStomach, + # startProportions=startProportions, endProportions=endProportions, + # rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, + # coordinates=coordinates) + # + # elementIdxThroughWall = [] + # n = lastDuodenumElementIdentifier - 1 + # for n3 in range(elementsCountThroughWall): + # elementIdxAround = [] + # for n1 in range(elementsCountAroundEso): + # n += 1 + # elementIdxAround.append(n) + # elementIdxThroughWall.append(elementIdxAround) + # elementIdxMat.append(elementIdxThroughWall) + # + # # delete mucosa layer in fundus when there is a limiting ridge + # mesh_destroy_elements_and_nodes_by_identifiers(mesh, fundusMucosaElementIdentifiers) + # + # # Create annotation groups for dorsal and ventral parts of the stomach + # dorsalGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("dorsal stomach")) + # ventralGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("ventral stomach")) + # dorsalMeshGroup = dorsalGroup.getMeshGroup(mesh) + # ventralMeshGroup = ventralGroup.getMeshGroup(mesh) + # + # for e2 in range(len(elementIdxMat)): + # for e3 in range(len(elementIdxMat[e2])): + # for e1 in range(len(elementIdxMat[e2][e3])): + # elementIdx = elementIdxMat[e2][e3][e1] + # element = mesh.findElementByIdentifier(elementIdx) + # if e1 < 0.5 * len(elementIdxMat[e2][e3]): + # ventralMeshGroup.addElement(element) + # else: + # dorsalMeshGroup.addElement(element) + # if dorsalGroup not in allAnnotationGroups: + # allAnnotationGroups.append(dorsalGroup) + # if ventralGroup not in allAnnotationGroups: + # allAnnotationGroups.append(ventralGroup) + # + # nodesOnLCMargin = [] + # for n2 in range(elementsAlongEsophagus + 1): + # for n3 in range(elementsThroughEsophagusWall + 1): + # nodeIdxOnLCMargin = 1 + elementsAroundHalfEso + \ + # n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ + # n3 * elementsCountAroundEso + # nodesOnLCMargin.append(nodeIdxOnLCMargin) + # allNodesOnLC = nodesOnLCMargin + nodeIdxLC + # + # nearLCGroup = AnnotationGroup(region, ("elements adjacent to lesser curvature", "None")) + # + # elementIter = mesh.createElementiterator() + # element = elementIter.next() + # while element.isValid(): + # eft = element.getElementfieldtemplate(coordinates, -1) + # nodeIdentifiers = get_element_node_identifiers(element, eft) + # for n in range(len(nodeIdentifiers)): + # if nodeIdentifiers[n] in allNodesOnLC: + # nearLCGroup.getMeshGroup(mesh).addElement(element) + # break + # element = elementIter.next() + # allAnnotationGroups.append(nearLCGroup) + # + # # Create split coordinate field + # if splitCoordinates: + # nodesOnSplitMargin = [] + # + # for n2 in range(elementsAlongEsophagus + 1): + # for n3 in range(elementsThroughEsophagusWall + 1): + # nodeIdxOnGCMargin = 1 + n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ + # n3 * elementsCountAroundEso + # nodesOnSplitMargin.append(nodeIdxOnGCMargin) + # nodeIdxOnLCMargin = 1 + elementsAroundHalfEso + \ + # n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ + # n3 * elementsCountAroundEso + # nodesOnSplitMargin.append(nodeIdxOnLCMargin) + # + # nodesOnSplitMargin += nodeIdxGC + nodeIdxLC + # + # splitCoordinates = findOrCreateFieldCoordinates(fm, name="split coordinates") + # splitNodetemplate1 = nodes.createNodetemplate() + # splitNodetemplate1.defineField(splitCoordinates) + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_VALUE, 1) + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + # if useCrossDerivatives: + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) + # if useCubicHermiteThroughWall: + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + # if useCrossDerivatives: + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) + # + # splitNodetemplate2 = nodes.createNodetemplate() + # splitNodetemplate2.defineField(splitCoordinates) + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_VALUE, 2) + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS1, 2) + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS2, 2) + # if useCrossDerivatives: + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 2) + # if useCubicHermiteThroughWall: + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS3, 2) + # if useCrossDerivatives: + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 2) + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 2) + # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 2) + # + # nodeIter = nodes.createNodeiterator() + # node = nodeIter.next() + # while node.isValid(): + # # if not markerPoints.containsNode(node): + # cache.setNode(node) + # identifier = node.getIdentifier() + # marginNode = identifier in nodesOnSplitMargin + # x = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, 3)[1] + # d1 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, 3)[1] + # d2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, 3)[1] + # if useCrossDerivatives: + # d1d2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, 3)[1] + # if useCubicHermiteThroughWall: + # d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, 3)[1] + # if useCrossDerivatives: + # d1d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, 3)[1] + # d2d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, 3)[1] + # d1d2d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, 3)[1] + # + # node.merge(splitNodetemplate2 if marginNode else splitNodetemplate1) + # versionCount = 2 if marginNode else 1 + # for vn in range(versionCount): + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, vn + 1, x) + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, vn + 1, d1) + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, vn + 1, d2) + # if useCrossDerivatives: + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, vn + 1, d1d2) + # if useCubicHermiteThroughWall: + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, vn + 1, d3) + # if useCrossDerivatives: + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, vn + 1, d1d3) + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, vn + 1, d2d3) + # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, vn + 1, d1d2d3) + # node = nodeIter.next() + # + # elementIter = mesh.createElementiterator() + # element = elementIter.next() + # splitElementtemplate1 = mesh.createElementtemplate() + # splitElementtemplate2 = mesh.createElementtemplate() + # + # count = 0 + # elementsInOstium = elementsCountAroundEso * elementsAlongEsophagus * elementsThroughEsophagusWall + # closedLoopElementId = nextElementIdentifier - elementsCountAroundEso * elementsCountAcrossCardia - \ + # elementsCountAroundDuod * elementsCountThroughWall * (elementsAlongCardiaToDuod + 1) + # + # allValueLabels = [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, + # Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3, + # Node.VALUE_LABEL_D2_DS2DS3, Node.VALUE_LABEL_D3_DS1DS2DS3] + # + # while element.isValid(): + # eft = element.getElementfieldtemplate(coordinates, -1) + # nodeIdentifiers = get_element_node_identifiers(element, eft) + # elementId = element.getIdentifier() + # marginDorsal = False + # for n in range(len(nodeIdentifiers)): + # marginElement = nodeIdentifiers[n] in nodesOnSplitMargin + # if marginElement: + # count += 1 + # if count < 3 and (elementId <= elementsInOstium or elementId > closedLoopElementId): + # marginDorsal = True + # elif count >= 3 and (elementId <= elementsInOstium or elementId > closedLoopElementId): + # if count == 4: + # count = 0 + # elif elementsInOstium < elementId < elementsInOstium + len(xOuter[0]) + 1: + # marginDorsal = True + # count = 0 + # elif elementsInOstium + len(xOuter[0]) < elementId < elementsInOstium + len(xOuter[0]) * 2 + 1: + # count = 0 + # elif count < 2 and elementId > elementsInOstium + 2 * (len(xOuter[0])): + # marginDorsal = True + # elif count >= 2 and elementId > elementsInOstium + 2 * (len(xOuter[0])): + # if count == 2: + # count = 0 + # break + # + # if marginDorsal: + # # Find nodes on margin to remap with version 2 + # lnRemapV2 = [] + # for n in range(len(nodeIdentifiers)): + # if nodeIdentifiers[n] in nodesOnSplitMargin: + # lnRemapV2.append(n + 1) + # eft2 = eft + # remapEftNodeValueLabelsVersion(eft2, lnRemapV2, allValueLabels, 2) + # + # splitElementtemplate2.defineField(splitCoordinates, -1, eft2) + # element.merge(splitElementtemplate2) + # element.setNodesByIdentifier(eft2, nodeIdentifiers) + # if eft2.getNumberOfLocalScaleFactors() > 0: + # element.setScaleFactor(eft2, 1, -1.0) + # else: + # splitElementtemplate1.defineField(splitCoordinates, -1, eft) + # element.merge(splitElementtemplate1) + # element.setNodesByIdentifier(eft, nodeIdentifiers) + # if eft.getNumberOfLocalScaleFactors() == 1: + # element.setScaleFactors(eft, [-1.0]) + # + # element = elementIter.next() + # + # allAnnotationGroups.append(nearLCGroup) + + nextNodeIdentifier = nodeIdentifier + nextElementIdentifier = elementIdentifier return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier From 564b0280ea0c0aaec914458a96401c361358d769 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 21 Jul 2023 13:14:42 +1200 Subject: [PATCH 10/30] Update central path unit scale and align axis origin to fundus-body intersection --- .../meshtypes/meshtype_3d_stomach1.py | 228 +++++++++--------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index a4a15aca..f4d6fa51 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -56,19 +56,19 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[1.41,0.44,0.00], [-0.01,-0.03,0.00], [0.04,-0.01,0.00], [0.13,-0.05,0.00], [0.00,0.00,0.04], [0.00,0.00,0.13]]), - (2, [[1.40,0.40,0.00], [-0.02,-0.05,0.00], [0.16,-0.06,0.00], [0.11,-0.05,0.00], [0.00,0.00,0.17], [0.00,0.00,0.13]]), - (3, [[1.37,0.34,0.00], [-0.03,-0.08,0.00], [0.25,-0.11,0.00], [0.09,-0.04,0.00], [0.00,0.00,0.29], [0.00,0.00,0.11]]), - (4, [[1.33,0.25,0.00], [-0.04,-0.10,0.00], [0.33,-0.15,0.00], [0.05,-0.04,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), - (5, [[1.28,0.14,0.00], [-0.06,-0.13,0.00], [0.36,-0.18,0.00], [0.01,-0.04,0.00], [0.00,0.00,0.42], [0.00,0.00,0.03]]), - (6, [[1.20,0.00,0.00], [-0.11,-0.17,0.00], [0.34,-0.22,0.00], [-0.04,-0.04,0.00], [0.00,0.00,0.43], [0.00,0.00,0.01]]), - (7, [[1.06,-0.19,0.00], [-0.16,-0.17,0.00], [0.27,-0.27,0.00], [-0.10,-0.05,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.01]]), - (8, [[0.88,-0.33,0.00], [-0.21,-0.10,0.00], [0.15,-0.31,0.00], [-0.13,-0.00,0.00], [0.00,0.00,0.41], [0.00,0.00,-0.05]]), - (9, [[0.66,-0.38,0.00], [-0.25,-0.01,0.00], [0.02,-0.27,0.00], [-0.11,0.05,0.00], [0.00,0.00,0.34], [0.00,0.00,-0.09]]), - (10, [[0.39,-0.35,0.00], [-0.22,0.08,0.00], [-0.08,-0.20,0.00], [-0.06,0.08,0.00], [0.00,0.00,0.23], [0.00,0.00,-0.07]]), - (11, [[0.24,-0.24,0.00], [-0.12,0.13,0.00], [-0.12,-0.11,0.00], [-0.00,0.08,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.06]]), - (12, [[0.16,-0.10,0.00], [-0.07,0.16,0.00], [-0.09,-0.04,0.00], [0.00,0.05,0.00], [0.00,0.00,0.11], [0.00,0.00,-0.03]]), - (13, [[0.11,0.08,0.00], [-0.03,0.20,0.00], [-0.12,-0.02,0.00], [-0.06,-0.01,0.00], [0.00,0.00,0.13], [0.00,0.00,0.07]]) + (1, [[0.49,0.06,0.00], [-0.03,-0.01,0.00], [0.01,-0.04,0.00], [0.03,-0.14,0.00], [0.00,0.00,0.04], [0.00,0.00,0.13]]), + (2, [[0.45,0.04,0.00], [-0.05,-0.01,0.00], [0.03,-0.17,0.00], [0.02,-0.12,0.00], [0.00,0.00,0.17], [0.00,0.00,0.13]]), + (3, [[0.38,0.04,0.00], [-0.08,-0.02,0.00], [0.04,-0.27,0.00], [0.01,-0.10,0.00], [0.00,0.00,0.29], [0.00,0.00,0.11]]), + (4, [[0.28,0.02,0.00], [-0.11,-0.02,0.00], [0.05,-0.36,0.00], [-0.01,-0.06,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), + (5, [[0.16,0.01,0.00], [-0.14,-0.02,0.00], [0.04,-0.40,0.00], [-0.03,-0.03,0.00], [0.00,0.00,0.42], [0.00,0.00,0.03]]), + (6, [[0.00,0.00,0.00], [-0.20,0.00,0.00], [-0.01,-0.40,0.00], [-0.06,0.01,0.00], [0.00,0.00,0.43], [0.00,0.00,0.01]]), + (7, [[-0.23,0.02,0.00], [-0.23,0.05,0.00], [-0.09,-0.37,0.00], [-0.10,0.06,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.01]]), + (8, [[-0.45,0.10,0.00], [-0.20,0.13,0.00], [-0.18,-0.29,0.00], [-0.07,0.11,0.00], [0.00,0.00,0.41], [0.00,0.00,-0.05]]), + (9, [[-0.61,0.26,0.00], [-0.14,0.21,0.00], [-0.22,-0.16,0.00], [-0.02,0.12,0.00], [0.00,0.00,0.34], [0.00,0.00,-0.09]]), + (10, [[-0.73,0.50,0.00], [-0.05,0.23,0.00], [-0.21,-0.04,0.00], [0.04,0.09,0.00], [0.00,0.00,0.23], [0.00,0.00,-0.07]]), + (11, [[-0.71,0.69,0.00], [0.05,0.17,0.00], [-0.16,0.04,0.00], [0.07,0.04,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.06]]), + (12, [[-0.64,0.83,0.00], [0.10,0.14,0.00], [-0.08,0.06,0.00], [0.04,0.03,0.00], [0.00,0.00,0.11], [0.00,0.00,-0.03]]), + (13, [[-0.51,0.97,0.00], [0.15,0.13,0.00], [-0.08,0.09,0.00], [-0.04,0.05,0.00], [0.00,0.00,0.13], [0.00,0.00,0.07]]) ]), 'userAnnotationGroups': [ @@ -118,18 +118,18 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[61.590,-101.050,1152.900], [0.442,-2.863,-3.864], [11.300,-0.230,1.460], [15.701,-3.029,2.832], [-0.850,-7.440,5.420], [-5.756,-22.456,14.946]]), - (2, [[61.990,-104.310,1148.310], [0.358,-3.656,-5.314], [24.170,-2.490,3.340], [10.039,-1.491,0.928], [-4.920,-25.060,16.910], [-2.384,-12.784,8.034]]), - (3, [[62.280,-108.340,1142.260], [0.251,-4.603,-7.040], [30.560,-2.990,3.040], [5.720,-0.448,-0.071], [-5.130,-31.610,20.490], [-0.206,-5.098,2.599]]), - (4, [[62.470,-113.500,1134.220], [0.315,-6.148,-9.733], [35.400,-3.370,3.270], [4.541,-0.488,0.325], [-5.330,-34.800,21.800], [-0.383,-3.012,1.219]]), - (5, [[62.940,-120.610,1122.780], [0.448,-8.598,-13.993], [39.520,-4.010,3.730], [3.189,-0.587,-0.295], [-5.970,-37.560,22.890], [-0.099,-1.218,0.549]]), - (6, [[63.320,-130.670,1106.220], [-0.184,-10.489,-16.967], [41.370,-4.520,2.350], [0.495,-2.468,-4.032], [-5.290,-36.560,22.660], [0.257,0.762,0.246]]), - (7, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.801], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), - (8, [[53.670,-152.880,1069.820], [-15.955,-9.817,-16.265], [30.765,-14.468,-15.598], [-14.187,-3.408,-7.577], [-3.580,-35.330,24.820], [2.031,4.346,-1.238]]), - (9, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.623], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), - (10, [[10.360,-162.050,1054.830], [-21.091,1.023,-0.270], [-0.460,-14.000,-17.230], [-8.753,2.830,4.765], [-1.070,-18.150,14.780], [-1.004,7.491,-3.259]]), - (11, [[-8.740,-158.280,1057.630], [-14.760,6.591,2.223], [-6.110,-10.230,-10.220], [-2.404,4.122,5.111], [-3.260,-12.000,13.950], [-1.432,6.623,-3.360]]), - (12, [[-18.830,-150.690,1059.200], [-11.483,11.369,1.057], [-6.410,-5.880,-6.340], [-0.423,3.102,2.580], [-4.200,-5.070,8.950], [-1.380,4.802,-2.401]]), + (1, [[61.590,-101.050,1152.900], [0.442,-2.863,-3.864], [11.300,-0.230,1.460], [15.701,-3.029,2.832], [-0.850,-7.440,5.420], [-5.756,-22.456,14.946]]), + (2, [[61.990,-104.310,1148.310], [0.358,-3.656,-5.314], [24.170,-2.490,3.340], [10.039,-1.491,0.928], [-4.920,-25.060,16.910], [-2.384,-12.784,8.034]]), + (3, [[62.280,-108.340,1142.260], [0.251,-4.603,-7.040], [30.560,-2.990,3.040], [5.720,-0.448,-0.071], [-5.130,-31.610,20.490], [-0.206,-5.098,2.599]]), + (4, [[62.470,-113.500,1134.220], [0.315,-6.148,-9.733], [35.400,-3.370,3.270], [4.541,-0.488,0.325], [-5.330,-34.800,21.800], [-0.383,-3.012,1.219]]), + (5, [[62.940,-120.610,1122.780], [0.448,-8.598,-13.993], [39.520,-4.010,3.730], [3.189,-0.587,-0.295], [-5.970,-37.560,22.890], [-0.099,-1.218,0.549]]), + (6, [[63.320,-130.670,1106.220], [-0.184,-10.489,-16.967], [41.370,-4.520,2.350], [0.495,-2.468,-4.032], [-5.290,-36.560,22.660], [0.257,0.762,0.246]]), + (7, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.801], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), + (8, [[53.670,-152.880,1069.820], [-15.955,-9.817,-16.265], [30.765,-14.468,-15.598], [-14.187,-3.408,-7.577], [-3.580,-35.330,24.820], [2.031,4.346,-1.238]]), + (9, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.623], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), + (10, [[10.360,-162.050,1054.830], [-21.091,1.023,-0.270], [-0.460,-14.000,-17.230], [-8.753,2.830,4.765], [-1.070,-18.150,14.780], [-1.004,7.491,-3.259]]), + (11, [[-8.740,-158.280,1057.630], [-14.760,6.591,2.223], [-6.110,-10.230,-10.220], [-2.404,4.122,5.111], [-3.260,-12.000,13.950], [-1.432,6.623,-3.360]]), + (12, [[-18.830,-150.690,1059.200], [-11.483,11.369,1.057], [-6.410,-5.880,-6.340], [-0.423,3.102,2.580], [-4.200,-5.070,8.950], [-1.380,4.802,-2.401]]), (13, [[-30.740,-135.240,1059.320], [-12.232,19.364,-0.810], [-7.020,-4.680,-5.740], [-0.797,-0.702,-1.380], [-6.250,-3.510,10.510], [-2.720,-1.682,5.521]]) ]), @@ -180,18 +180,18 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[1.71,0.60,-0.00], [0.03,-0.06,0.00], [0.07,0.01,-0.00], [0.13,0.01,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), - (2, [[1.73,0.52,0.00], [0.01,-0.10,0.00], [0.19,-0.01,0.00], [0.11,-0.03,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), - (3, [[1.72,0.40,0.00], [-0.03,-0.14,0.00], [0.25,-0.07,0.00], [0.05,-0.09,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), - (4, [[1.67,0.24,0.00], [-0.08,-0.15,0.00], [0.26,-0.19,0.01], [-0.03,-0.13,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), - (5, [[1.56,0.10,0.00], [-0.14,-0.12,0.00], [0.22,-0.31,0.00], [-0.08,-0.10,-0.01], [0.00,0.00,0.38], [0.00,0.00,0.02]]), - (6, [[1.39,0.02,0.00], [-0.23,-0.06,0.00], [0.09,-0.38,0.00], [-0.15,-0.04,-0.00], [0.00,0.00,0.39], [0.00,0.00,0.00]]), - (7, [[1.12,0.01,0.00], [-0.28,0.07,0.00], [-0.09,-0.39,0.00], [-0.18,0.06,0.00], [0.00,0.00,0.38], [0.00,0.00,-0.01]]), - (8, [[0.86,0.15,0.00], [-0.19,0.20,0.00], [-0.28,-0.26,0.00], [-0.09,0.17,0.01], [0.00,0.00,0.36], [0.01,0.00,-0.03]]), - (9, [[0.76,0.37,0.00], [-0.04,0.20,0.00], [-0.29,-0.08,0.01], [0.05,0.13,-0.00], [0.01,0.00,0.32], [-0.00,0.00,-0.08]]), - (10, [[0.77,0.54,0.00], [0.02,0.16,0.00], [-0.19,-0.00,0.00], [0.09,0.03,-0.00], [0.00,-0.00,0.21], [-0.00,0.00,-0.09]]), - (11, [[0.80,0.68,0.00], [0.01,0.14,0.00], [-0.10,0.01,0.00], [0.04,-0.03,0.00], [0.00,-0.00,0.13], [0.00,0.00,-0.04]]), - (12, [[0.79,0.81,0.00], [-0.03,0.12,0.00], [-0.11,-0.03,0.00], [-0.06,-0.05,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) + (1, [[0.42,0.72,0.00], [0.04,-0.05,0.00], [0.07,0.03,0.00], [0.12,0.04,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), + (2, [[0.46,0.65,0.00], [0.04,-0.09,0.00], [0.19,0.04,0.00], [0.11,-0.00,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), + (3, [[0.48,0.53,0.00], [0.01,-0.14,0.00], [0.26,-0.00,0.00], [0.07,-0.07,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), + (4, [[0.47,0.36,0.00], [-0.04,-0.17,0.00], [0.30,-0.12,0.01], [0.00,-0.13,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), + (5, [[0.40,0.20,0.00], [-0.10,-0.15,0.00], [0.29,-0.24,0.00], [-0.05,-0.12,-0.01], [0.00,0.00,0.38], [0.00,0.00,0.02]]), + (6, [[0.26,0.08,0.00], [-0.21,-0.12,0.00], [0.19,-0.34,0.00], [-0.13,-0.08,0.00], [0.00,0.00,0.39], [0.00,0.00,0.00]]), + (7, [[0.00,0.00,0.00], [-0.29,-0.00,0.00], [0.01,-0.40,0.00], [-0.19,0.01,0.00], [0.00,0.00,0.38], [0.00,0.00,-0.01]]), + (8, [[-0.29,0.07,0.00], [-0.24,0.14,0.00], [-0.20,-0.32,0.00], [-0.13,0.14,0.01], [0.00,0.00,0.36], [0.01,0.00,-0.03]]), + (9, [[-0.44,0.25,0.00], [-0.09,0.18,0.00], [-0.26,-0.15,0.01], [0.01,0.14,0.00], [0.01,0.00,0.32], [0.00,0.00,-0.08]]), + (10, [[-0.48,0.42,0.00], [-0.02,0.16,0.00], [-0.18,-0.05,0.00], [0.08,0.05,0.00], [0.00,0.00,0.21], [0.00,0.00,-0.09]]), + (11, [[-0.48,0.56,0.00], [-0.03,0.14,0.00], [-0.10,-0.02,0.00], [0.05,-0.02,0.00], [0.00,0.00,0.13], [0.00,0.00,-0.04]]), + (12, [[-0.53,0.69,0.00], [-0.06,0.11,0.00], [-0.10,-0.06,0.00], [-0.05,-0.06,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) ]), 'userAnnotationGroups': [ @@ -241,17 +241,17 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[1.40,0.39,0.00], [-0.00,-0.01,-0.00], [0.05,-0.02,0.00], [0.07,-0.05,0.00], [0.00,0.00,0.08], [0.00,0.00,0.06]]), - (2, [[1.39,0.37,0.00], [-0.02,-0.05,0.00], [0.13,-0.07,0.00], [0.09,-0.05,0.00], [0.00,0.00,0.15], [0.00,0.00,0.08]]), - (3, [[1.35,0.29,0.00], [-0.05,-0.10,0.00], [0.25,-0.13,0.00], [0.11,-0.06,0.00], [0.00,0.00,0.28], [0.00,0.00,0.12]]), - (4, [[1.29,0.17,0.00], [-0.07,-0.15,0.00], [0.35,-0.18,0.00], [0.06,-0.05,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), - (5, [[1.20,0.00,0.00], [-0.10,-0.18,0.00], [0.36,-0.23,0.00], [0.01,-0.03,0.00], [0.00,0.00,0.40], [0.00,0.00,0.01]]), - (6, [[1.09,-0.19,0.00], [-0.14,-0.21,0.00], [0.36,-0.23,0.00], [-0.05,-0.03,0.00], [0.00,0.00,0.40], [0.00,0.00,-0.01]]), - (7, [[0.92,-0.42,0.00], [-0.23,-0.17,0.00], [0.24,-0.31,0.00], [-0.18,-0.04,0.00], [0.00,0.00,0.37], [0.00,0.00,-0.05]]), - (8, [[0.66,-0.51,0.00], [-0.29,0.03,0.00], [0.01,-0.32,-0.00], [-0.21,0.05,0.00], [0.00,0.00,0.31], [0.00,0.00,-0.09]]), - (9, [[0.41,-0.37,0.00], [-0.17,0.23,0.00], [-0.17,-0.21,0.00], [-0.03,0.13,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.11]]), - (10, [[0.35,-0.11,0.00], [-0.10,0.21,0.00], [-0.07,-0.06,0.00], [0.05,0.06,0.00], [0.00,0.00,0.09], [0.00,0.00,-0.04]]), - (11, [[0.23,0.05,0.00], [-0.13,0.10,0.00], [-0.05,-0.07,0.00], [-0.01,-0.08,0.00], [0.00,0.00,0.09], [0.00,0.00,0.04]]) + (1, [[0.44,0.01,0.00], [-0.01,-0.00,0.00], [0.01,-0.05,0.00], [-0.01,-0.09,0.00], [0.00,0.00,0.08], [0.00,0.00,0.06]]), + (2, [[0.42,0.01,0.00], [-0.05,-0.01,0.00], [-0.00,-0.15,0.00], [-0.00,-0.10,0.00], [0.00,0.00,0.15], [0.00,0.00,0.08]]), + (3, [[0.33,0.00,0.00], [-0.11,-0.00,0.00], [0.00,-0.28,0.00], [-0.00,-0.13,0.00], [0.00,0.00,0.28], [0.00,0.00,0.12]]), + (4, [[0.19,0.00,0.00], [-0.17,-0.01,0.00], [0.01,-0.39,0.00], [-0.02,-0.08,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), + (5, [[0.00,0.00,0.00], [-0.21,0.00,0.00], [-0.03,-0.43,0.00], [-0.02,-0.02,0.00], [0.00,0.00,0.40], [0.00,0.00,0.01]]), + (6, [[-0.22,0.01,0.00], [-0.25,0.03,0.00], [-0.03,-0.43,0.00], [-0.05,0.03,0.00], [0.00,0.00,0.40], [0.00,0.00,-0.01]]), + (7, [[-0.50,0.05,0.00], [-0.26,0.12,0.00], [-0.16,-0.36,0.00], [-0.12,0.14,0.00], [0.00,0.00,0.37], [0.00,0.00,-0.05]]), + (8, [[-0.70,0.24,0.00], [-0.11,0.27,0.00], [-0.28,-0.16,0.00], [-0.05,0.21,0.00], [0.00,0.00,0.31], [0.00,0.00,-0.09]]), + (9, [[-0.70,0.52,0.00], [0.12,0.26,0.00], [-0.27,0.05,0.00], [0.10,0.09,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.11]]), + (10, [[-0.50,0.70,0.00], [0.14,0.19,0.00], [-0.09,0.03,0.00], [0.08,-0.02,0.00], [0.00,0.00,0.09], [0.00,0.00,-0.04]]), + (11, [[-0.41,0.88,0.00], [0.03,0.16,0.00], [-0.09,0.01,0.00], [-0.08,-0.03,0.00], [0.00,0.00,0.09], [0.00,0.00,0.04]]) ]), 'userAnnotationGroups': [ @@ -301,19 +301,19 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[1.670,0.640,0.000], [0.004,-0.035,0.000], [0.060,0.000,0.000], [0.117,0.020,0.000], [-0.000,0.000,0.080], [0.000,0.000,0.077]]), - (2, [[1.670,0.570,0.000], [-0.004,-0.105,0.000], [0.180,0.000,0.000], [0.123,-0.020,0.000], [-0.000,0.000,0.160], [0.000,0.000,0.083]]), - (3, [[1.660,0.430,0.000], [-0.033,-0.152,0.000], [0.310,-0.060,0.000], [0.080,-0.087,0.000], [0.000,0.000,0.250], [0.000,0.000,0.072]]), - (4, [[1.600,0.270,0.000], [-0.077,-0.146,0.000], [0.330,-0.180,0.000], [-0.024,-0.117,0.001], [0.000,0.000,0.300], [0.000,0.000,0.040]]), - (5, [[1.510,0.140,0.000], [-0.116,-0.118,0.000], [0.266,-0.295,0.001], [-0.086,-0.103,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), - (6, [[1.370,0.040,0.000], [-0.159,-0.072,0.000], [0.157,-0.384,-0.000], [-0.123,-0.063,-0.001], [0.000,0.000,0.360], [0.000,0.000,0.015]]), - (7, [[1.200,0.000,0.000], [-0.200,-0.005,0.000], [0.020,-0.420,0.000], [-0.156,-0.003,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), - (8, [[0.980,0.040,0.000], [-0.212,0.087,0.000], [-0.160,-0.380,0.000], [-0.155,0.074,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), - (9, [[0.790,0.170,0.000], [-0.152,0.177,0.000], [-0.290,-0.270,0.000], [-0.060,0.120,0.005], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), - (10, [[0.690,0.380,0.000], [-0.047,0.208,0.000], [-0.280,-0.140,0.010], [0.076,0.108,-0.001], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), - (11, [[0.690,0.570,-0.000], [-0.019,0.156,0.000], [-0.150,-0.050,0.000], [0.075,0.042,-0.004], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), - (12, [[0.660,0.690,0.000], [-0.035,0.115,0.000], [-0.110,-0.040,0.000], [0.009,-0.000,0.000], [0.000,0.000,0.120], [0.000,0.000,0.015]]), - (13, [[0.620,0.800,0.000], [-0.045,0.105,0.000], [-0.130,-0.050,0.000], [-0.049,-0.020,0.000], [0.000,0.000,0.150], [0.000,0.000,0.045]]) + (1, [[0.492,0.623,0.000], [0.003,-0.035,0.000], [0.060,-0.002,0.000], [0.118,0.016,0.000], [0.000,0.000,0.080], [0.000,0.000,0.077]]), + (2, [[0.490,0.553,0.000], [-0.008,-0.105,0.000], [0.180,-0.006,0.000], [0.122,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.083]]), + (3, [[0.475,0.414,0.000], [-0.038,-0.151,0.000], [0.308,-0.071,0.000], [0.077,-0.090,0.000], [0.000,0.000,0.250], [0.000,0.000,0.072]]), + (4, [[0.409,0.256,0.000], [-0.082,-0.143,0.000], [0.324,-0.191,0.000], [-0.028,-0.116,0.001], [0.000,0.000,0.300], [0.000,0.000,0.040]]), + (5, [[0.315,0.129,0.000], [-0.120,-0.114,0.000], [0.256,-0.304,0.001], [-0.090,-0.100,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), + (6, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.059,-0.001], [0.000,0.000,0.360], [0.000,0.000,0.015]]), + (7, [[0.000,0.000,0.000], [-0.200,0.002,0.000], [0.005,-0.420,0.000], [-0.156,0.002,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), + (8, [[-0.218,0.048,0.000], [-0.209,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), + (9, [[-0.404,0.184,0.000], [-0.146,0.182,0.000], [-0.299,-0.260,0.000], [-0.056,0.122,0.005], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), + (10, [[-0.496,0.398,0.000], [-0.040,0.210,0.000], [-0.285,-0.130,0.010], [0.080,0.105,-0.001], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), + (11, [[-0.490,0.587,0.000], [-0.014,0.157,0.000], [-0.152,-0.045,0.000], [0.076,0.039,-0.004], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), + (12, [[-0.516,0.708,0.000], [-0.031,0.116,0.000], [-0.111,-0.036,0.000], [0.009,-0.000,0.000], [0.000,0.000,0.120], [0.000,0.000,0.015]]), + (13, [[-0.552,0.820,0.000], [-0.041,0.107,0.000], [-0.132,-0.045,0.000], [-0.050,-0.018,0.000], [0.000,0.000,0.150], [0.000,0.000,0.045]]) ]), 'userAnnotationGroups': [ @@ -363,22 +363,22 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[2.00,0.00,0.00], [-0.02,0.00,0.00], [0.00,-0.05,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.05], [0.00,0.00,0.10]]), - (2, [[1.98,0.00,0.00], [-0.05,0.00,0.00], [0.00,-0.15,0.00], [0.00,-0.11,0.00], [0.00,0.00,0.15], [0.00,0.00,0.11]]), - (3, [[1.90,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.29,0.00], [0.00,-0.13,0.00], [0.00,0.00,0.29], [0.00,0.00,0.13]]), - (4, [[1.79,0.00,0.00], [-0.13,0.00,0.00], [0.00,-0.40,0.00], [0.00,-0.10,0.00], [0.00,0.00,0.40], [0.00,0.00,0.10]]), - (5, [[1.65,0.00,0.00], [-0.16,0.00,0.00], [0.00,-0.48,0.00], [0.00,-0.05,0.00], [0.00,0.00,0.48], [0.00,0.00,0.05]]), - (6, [[1.48,0.00,0.00], [-0.17,0.00,0.00], [0.00,-0.50,0.00], [0.00,-0.01,0.00], [0.00,0.00,0.50], [0.00,0.00,0.01]]), - (7, [[1.30,0.00,0.00], [-0.19,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), - (8, [[1.10,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), - (9, [[0.90,0.00,0.00], [-0.20,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,0.00]]), - (10, [[0.70,0.00,0.00], [-0.18,0.00,0.00], [0.00,-0.50,0.00], [0.00,0.00,0.00], [0.00,0.00,0.50], [0.00,0.00,-0.00]]), - (11, [[0.55,0.00,0.00], [-0.15,0.00,0.00], [0.00,-0.44,0.00], [0.00,0.10,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.10]]), - (12, [[0.40,0.00,0.00], [-0.12,0.00,0.00], [0.00,-0.31,0.00], [0.00,0.12,0.00], [0.00,0.00,0.31], [0.00,0.00,-0.12]]), - (13, [[0.30,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]), - (14, [[0.20,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00,0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]), - (15, [[0.10,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00, 0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]), - (16, [[0.00,0.00,0.00], [-0.10,0.00,0.00], [0.00,-0.20,0.00], [0.00, 0.00,0.00], [0.00,0.00,0.20], [0.00,0.00,0.00]]) + (1, [[0.700,0.000,0.000], [-0.020,0.000,0.000], [0.000,-0.050,0.000], [0.000,-0.100,0.000], [0.000,0.000,0.050], [0.000,0.000,0.100]]), + (2, [[0.680,0.000,0.000], [-0.050,0.000,0.000], [0.000,-0.150,0.000], [0.000,-0.110,0.000], [0.000,0.000,0.150], [0.000,0.000,0.110]]), + (3, [[0.600,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.290,0.000], [0.000,-0.130,0.000], [0.000,0.000,0.290], [0.000,0.000,0.130]]), + (4, [[0.490,0.000,0.000], [-0.130,0.000,0.000], [0.000,-0.400,0.000], [0.000,-0.100,0.000], [0.000,0.000,0.400], [0.000,0.000,0.100]]), + (5, [[0.350,0.000,0.000], [-0.160,0.000,0.000], [0.000,-0.480,0.000], [0.000,-0.050,0.000], [0.000,0.000,0.480], [0.000,0.000,0.050]]), + (6, [[0.180,0.000,0.000], [-0.170,0.000,0.000], [0.000,-0.500,0.000], [0.000,-0.010,0.000], [0.000,0.000,0.500], [0.000,0.000,0.010]]), + (7, [[0.000,0.000,0.000], [-0.190,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), + (8, [[-0.200,0.000,0.000], [-0.200,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), + (9, [[-0.400,0.000,0.000], [-0.200,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), + (10, [[-0.600,0.000,0.000], [-0.180,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), + (11, [[-0.750,0.000,0.000], [-0.150,0.000,0.000], [0.000,-0.440,0.000], [0.000,0.100,0.000], [0.000,0.000,0.440], [0.000,0.000,-0.100]]), + (12, [[-0.900,0.000,0.000], [-0.120,0.000,0.000], [0.000,-0.310,0.000], [0.000,0.120,0.000], [0.000,0.000,0.310], [0.000,0.000,-0.120]]), + (13, [[-1.000,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), + (14, [[-1.100,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), + (15, [[-1.200,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), + (16, [[-1.300,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]) ]), 'userAnnotationGroups': [ @@ -1731,43 +1731,43 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # tmpRegion.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_tracksurface.exf") # del tmpRegion - # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction - GEJSettings['Number of elements around ostium'] = elementsCountAroundEso - GEJPosition = trackSurfaceStomach.findNearestPosition(xGEJ) - xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GEJPosition, derivatives=True) - axis1 = d1Centre - - esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) - esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) - abdominalEsoGroup = AnnotationGroup(region, get_esophagus_term("abdominal part of esophagus")) - abdominalEsoMeshGroup = abdominalEsoGroup.getMeshGroup(mesh) - esophagogastricJunctionGroup = AnnotationGroup(region, get_stomach_term("esophagogastric junction")) - esophagogastricJunctionMeshGroup = esophagogastricJunctionGroup.getMeshGroup(mesh) - stomachMeshGroup = stomachGroup.getMeshGroup(mesh) - allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup, abdominalEsoGroup] - - ostiumWallAnnotationGroups = [] - if elementsCountThroughWall == 4: - esophagusMucosaGroup = AnnotationGroup(region, get_esophagus_term("esophagus mucosa")) - esophagusSubmucosaGroup = AnnotationGroup(region, get_esophagus_term("submucosa of esophagus")) - esophagusCircularGroup = AnnotationGroup(region, get_esophagus_term("esophagus smooth muscle circular layer")) - esophagusLongitudinalGroup = AnnotationGroup(region, - get_esophagus_term("esophagus smooth muscle longitudinal layer")) - - ostiumWallAnnotationGroups = [[esophagusMucosaGroup, mucosaGroup], - [esophagusSubmucosaGroup, submucosaGroup], - [esophagusCircularGroup, circularMuscleGroup], - [esophagusLongitudinalGroup, longitudinalMuscleGroup]] - - allAnnotationGroups += [esophagusMucosaGroup, esophagusSubmucosaGroup, - esophagusCircularGroup, esophagusLongitudinalGroup] - - nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, - nodeIdentifier, elementIdentifier, - vesselMeshGroups=[[stomachMeshGroup, esophagusMeshGroup, abdominalEsoMeshGroup]], - ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup], - wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=coordinates) + # # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction + # GEJSettings['Number of elements around ostium'] = elementsCountAroundEso + # GEJPosition = trackSurfaceStomach.findNearestPosition(xGEJ) + # xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GEJPosition, derivatives=True) + # axis1 = d1Centre + # + # esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) + # esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) + # abdominalEsoGroup = AnnotationGroup(region, get_esophagus_term("abdominal part of esophagus")) + # abdominalEsoMeshGroup = abdominalEsoGroup.getMeshGroup(mesh) + # esophagogastricJunctionGroup = AnnotationGroup(region, get_stomach_term("esophagogastric junction")) + # esophagogastricJunctionMeshGroup = esophagogastricJunctionGroup.getMeshGroup(mesh) + # stomachMeshGroup = stomachGroup.getMeshGroup(mesh) + # allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup, abdominalEsoGroup] + # + # ostiumWallAnnotationGroups = [] + # if elementsCountThroughWall == 4: + # esophagusMucosaGroup = AnnotationGroup(region, get_esophagus_term("esophagus mucosa")) + # esophagusSubmucosaGroup = AnnotationGroup(region, get_esophagus_term("submucosa of esophagus")) + # esophagusCircularGroup = AnnotationGroup(region, get_esophagus_term("esophagus smooth muscle circular layer")) + # esophagusLongitudinalGroup = AnnotationGroup(region, + # get_esophagus_term("esophagus smooth muscle longitudinal layer")) + # + # ostiumWallAnnotationGroups = [[esophagusMucosaGroup, mucosaGroup], + # [esophagusSubmucosaGroup, submucosaGroup], + # [esophagusCircularGroup, circularMuscleGroup], + # [esophagusLongitudinalGroup, longitudinalMuscleGroup]] + # + # allAnnotationGroups += [esophagusMucosaGroup, esophagusSubmucosaGroup, + # esophagusCircularGroup, esophagusLongitudinalGroup] + # + # nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + # generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, + # nodeIdentifier, elementIdentifier, + # vesselMeshGroups=[[stomachMeshGroup, esophagusMeshGroup, abdominalEsoMeshGroup]], + # ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup], + # wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=coordinates) # stomachStartNode = nextNodeIdentifier # nodeIdentifier = nextNodeIdentifier From f9860ef3f697b49bbfd0b313b19b9c819065ea38 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 21 Jul 2023 15:45:33 +1200 Subject: [PATCH 11/30] Update human 1 central path --- .../meshtypes/meshtype_3d_stomach1.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index f4d6fa51..2db88c33 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -56,19 +56,19 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.49,0.06,0.00], [-0.03,-0.01,0.00], [0.01,-0.04,0.00], [0.03,-0.14,0.00], [0.00,0.00,0.04], [0.00,0.00,0.13]]), - (2, [[0.45,0.04,0.00], [-0.05,-0.01,0.00], [0.03,-0.17,0.00], [0.02,-0.12,0.00], [0.00,0.00,0.17], [0.00,0.00,0.13]]), + (1, [[0.49,0.06,0.00], [-0.03,-0.00,-0.00], [0.01,-0.04,0.00], [0.02,-0.14,0.00], [0.00,0.00,0.04], [0.00,0.00,0.13]]), + (2, [[0.45,0.05,-0.00], [-0.06,-0.01,-0.00], [0.03,-0.17,0.00], [0.02,-0.12,0.00], [0.00,0.00,0.17], [0.00,0.00,0.13]]), (3, [[0.38,0.04,0.00], [-0.08,-0.02,0.00], [0.04,-0.27,0.00], [0.01,-0.10,0.00], [0.00,0.00,0.29], [0.00,0.00,0.11]]), - (4, [[0.28,0.02,0.00], [-0.11,-0.02,0.00], [0.05,-0.36,0.00], [-0.01,-0.06,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), - (5, [[0.16,0.01,0.00], [-0.14,-0.02,0.00], [0.04,-0.40,0.00], [-0.03,-0.03,0.00], [0.00,0.00,0.42], [0.00,0.00,0.03]]), + (4, [[0.28,0.02,0.00], [-0.11,-0.02,0.00], [0.05,-0.36,0.00], [0.00,-0.07,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), + (5, [[0.16,0.01,0.00], [-0.14,-0.01,0.00], [0.04,-0.40,0.00], [-0.03,-0.02,0.00], [0.00,0.00,0.42], [0.00,0.00,0.03]]), (6, [[0.00,0.00,0.00], [-0.20,0.00,0.00], [-0.01,-0.40,0.00], [-0.06,0.01,0.00], [0.00,0.00,0.43], [0.00,0.00,0.01]]), - (7, [[-0.23,0.02,0.00], [-0.23,0.05,0.00], [-0.09,-0.37,0.00], [-0.10,0.06,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.01]]), - (8, [[-0.45,0.10,0.00], [-0.20,0.13,0.00], [-0.18,-0.29,0.00], [-0.07,0.11,0.00], [0.00,0.00,0.41], [0.00,0.00,-0.05]]), - (9, [[-0.61,0.26,0.00], [-0.14,0.21,0.00], [-0.22,-0.16,0.00], [-0.02,0.12,0.00], [0.00,0.00,0.34], [0.00,0.00,-0.09]]), - (10, [[-0.73,0.50,0.00], [-0.05,0.23,0.00], [-0.21,-0.04,0.00], [0.04,0.09,0.00], [0.00,0.00,0.23], [0.00,0.00,-0.07]]), - (11, [[-0.71,0.69,0.00], [0.05,0.17,0.00], [-0.16,0.04,0.00], [0.07,0.04,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.06]]), - (12, [[-0.64,0.83,0.00], [0.10,0.14,0.00], [-0.08,0.06,0.00], [0.04,0.03,0.00], [0.00,0.00,0.11], [0.00,0.00,-0.03]]), - (13, [[-0.51,0.97,0.00], [0.15,0.13,0.00], [-0.08,0.09,0.00], [-0.04,0.05,0.00], [0.00,0.00,0.13], [0.00,0.00,0.07]]) + (7, [[-0.23,0.02,0.00], [-0.23,0.05,0.00], [-0.09,-0.37,0.00], [-0.08,0.05,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.01]]), + (8, [[-0.45,0.10,0.00], [-0.20,0.12,0.00], [-0.18,-0.29,0.00], [-0.06,0.11,0.00], [0.00,0.00,0.41], [0.00,0.00,-0.05]]), + (9, [[-0.61,0.26,0.00], [-0.15,0.20,0.00], [-0.22,-0.16,0.00], [-0.02,0.13,0.00], [0.00,0.00,0.34], [0.00,0.00,-0.09]]), + (10, [[-0.73,0.50,0.00], [-0.04,0.23,0.00], [-0.21,-0.04,0.00], [0.04,0.09,0.00], [0.00,0.00,0.23], [0.00,0.00,-0.07]]), + (11, [[-0.71,0.69,0.00], [0.05,0.17,0.00], [-0.14,0.03,0.00], [0.06,0.05,-0.00], [0.00,0.00,0.18], [0.00,0.00,-0.06]]), + (12, [[-0.64,0.83,0.00], [0.10,0.14,0.00], [-0.08,0.06,0.00], [0.03,0.03,-0.00], [0.00,0.00,0.11], [0.00,0.00,-0.03]]), + (13, [[-0.51,0.97,0.00], [0.16,0.14,0.00], [-0.08,0.09,0.00], [-0.03,0.03,0.00], [0.00,0.00,0.13], [0.00,0.00,0.07]]) ]), 'userAnnotationGroups': [ From 855c7bc46223fd0b43c6167af1a1b8ce74336f3c Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 31 Jul 2023 15:21:00 +1200 Subject: [PATCH 12/30] Update generateMesh for track surface --- .../meshtypes/meshtype_3d_stomach1.py | 78 +++++++++---------- src/scaffoldmaker/utils/tracksurface.py | 13 ++-- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 2db88c33..1b2425c4 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1687,45 +1687,45 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # Visualise track surface # tmpRegion = region.createRegion() - # trackSurfaceStomach.generateMesh(tmpRegion) - - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - startNodeIdentifier = nodeIdentifier = max(get_maximum_node_identifier(nodes), 0) + 1 - nodetemplate = nodes.createNodetemplate() - nodetemplate.defineField(coordinates) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - - mesh = fm.findMeshByDimension(2) - elementIdentifier = max(get_maximum_element_identifier(mesh), 0) + 1 - elementtemplate = mesh.createElementtemplate() - elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE) - bicubicHermiteBasis = fm.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) - eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) - # remove cross derivative terms - for n in range(4): - eft.setFunctionNumberOfTerms(n * 4 + 4, 0) - elementtemplate.defineField(coordinates, -1, eft) - - fieldcache = fm.createFieldcache() - with ChangeManager(fm): - for n1 in range(len(trackSurfaceStomach.nx)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - fieldcache.setNode(node) - coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, trackSurfaceStomach.nx[n1]) - coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, trackSurfaceStomach.nd1[n1]) - coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, trackSurfaceStomach.nd2[n1]) - nodeIdentifier += 1 - - del n1 - nodesCount1 = trackSurfaceStomach.elementsCount1 + 1 - for e2 in range(trackSurfaceStomach.elementsCount2): - for e1 in range(trackSurfaceStomach.elementsCount1): - nid1 = startNodeIdentifier + e2 * nodesCount1 + e1 - nids = [nid1, nid1 + 1, nid1 + nodesCount1, nid1 + nodesCount1 + 1] - element = mesh.createElement(elementIdentifier, elementtemplate) - element.setNodesByIdentifier(eft, nids) - elementIdentifier += 1 + nodeIdentifier, elementIdentifier = trackSurfaceStomach.generateMesh(region) #tmpRegion) + + # nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + # startNodeIdentifier = nodeIdentifier = max(get_maximum_node_identifier(nodes), 0) + 1 + # nodetemplate = nodes.createNodetemplate() + # nodetemplate.defineField(coordinates) + # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + # + # mesh = fm.findMeshByDimension(2) + # elementIdentifier = max(get_maximum_element_identifier(mesh), 0) + 1 + # elementtemplate = mesh.createElementtemplate() + # elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE) + # bicubicHermiteBasis = fm.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + # eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) + # # remove cross derivative terms + # for n in range(4): + # eft.setFunctionNumberOfTerms(n * 4 + 4, 0) + # elementtemplate.defineField(coordinates, -1, eft) + # + # fieldcache = fm.createFieldcache() + # with ChangeManager(fm): + # for n1 in range(len(trackSurfaceStomach.nx)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # fieldcache.setNode(node) + # coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, trackSurfaceStomach.nx[n1]) + # coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, trackSurfaceStomach.nd1[n1]) + # coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, trackSurfaceStomach.nd2[n1]) + # nodeIdentifier += 1 + # + # del n1 + # nodesCount1 = trackSurfaceStomach.elementsCount1 + 1 + # for e2 in range(trackSurfaceStomach.elementsCount2): + # for e1 in range(trackSurfaceStomach.elementsCount1): + # nid1 = startNodeIdentifier + e2 * nodesCount1 + e1 + # nids = [nid1, nid1 + 1, nid1 + nodesCount1, nid1 + nodesCount1 + 1] + # element = mesh.createElement(elementIdentifier, elementtemplate) + # element.setNodesByIdentifier(eft, nids) + # elementIdentifier += 1 # tmpRegion.getFieldmodule().defineAllFaces() # tmpRegion.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_tracksurface.exf") diff --git a/src/scaffoldmaker/utils/tracksurface.py b/src/scaffoldmaker/utils/tracksurface.py index cce85c1b..20be933e 100644 --- a/src/scaffoldmaker/utils/tracksurface.py +++ b/src/scaffoldmaker/utils/tracksurface.py @@ -498,7 +498,7 @@ def generateMesh(self, region): """ Generate nodes and surface elements in region. :param region: - :return: + :return: next node identifier, next 2D element identifier """ fieldmodule = region.getFieldmodule() coordinates = find_or_create_field_coordinates(fieldmodule) @@ -514,11 +514,12 @@ def generateMesh(self, region): elementIdentifier = max(get_maximum_element_identifier(mesh), 0) + 1 elementtemplate = mesh.createElementtemplate() elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE) - bicubicHermiteBasis = fieldmodule.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + # bicubicHermiteBasis = fieldmodule.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + bicubicHermiteBasis = fieldmodule.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE_SERENDIPITY) eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) - # remote cross derivative terms - for n in range(4): - eft.setFunctionNumberOfTerms(n * 4 + 4, 0) + # # remove cross derivative terms for regular Hermite + # for n in range(4): + # eft.setFunctionNumberOfTerms(n * 4 + 4, 0) elementtemplate.defineField(coordinates, -1, eft) fieldcache = fieldmodule.createFieldcache() @@ -541,6 +542,8 @@ def generateMesh(self, region): # print(elementIdentifier, element.isValid(), nids) elementIdentifier += 1 + return nodeIdentifier, elementIdentifier + def calculate_surface_delta_xi(d1, d2, direction): ''' Calculate dxi1, dxi2 in 3-D vector direction. From 887de79d27455a5a17614db1ff306065c05d4ccf Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 31 Jul 2023 16:04:07 +1200 Subject: [PATCH 13/30] Make d1 at apex zero for track surface --- .../meshtypes/meshtype_3d_stomach1.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 1b2425c4..ca295924 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1526,14 +1526,14 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio cd12Group = centralPath.cd12Groups[i + 1] cd13Group = centralPath.cd13Groups[i + 1] - for n2 in range(len(cxGroup)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxGroup[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd2Group[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd1Group[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, cd3Group[n2]) - nodeIdentifier += 1 + # for n2 in range(len(cxGroup)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxGroup[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd2Group[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd1Group[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, cd3Group[n2]) + # nodeIdentifier += 1 if materialCoordinates and i == len(elementCountGroupList) - 1: for n in range(len(cxGroup)): @@ -1679,7 +1679,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n2 in range(len(xEllipseAroundAll)): for n1 in range(len(xEllipseAroundAll[n2])): xTrackSurface.append(xEllipseAroundAll[n2][n1]) - d1TrackSurface.append(d1EllipseAroundAll[n2][n1]) + d1TrackSurface.append(d1EllipseAroundAll[n2][n1] if n2 else zero) d2TrackSurface.append(d2EllipseAroundAll[n2][n1]) trackSurfaceStomach = TrackSurface(elementsCountAroundDuod, len(xEllipseAroundAll) - 1, From dcc3e4bd3eb50549cf77ee86545d4abc9c3d815d Mon Sep 17 00:00:00 2001 From: mlin865 Date: Tue, 8 Aug 2023 18:03:25 +1200 Subject: [PATCH 14/30] Distribute elements along each region equally using track surface --- .../meshtypes/meshtype_3d_stomach1.py | 1448 ++++++++++------- 1 file changed, 850 insertions(+), 598 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index ca295924..7898bf7c 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -180,18 +180,18 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.42,0.72,0.00], [0.04,-0.05,0.00], [0.07,0.03,0.00], [0.12,0.04,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), - (2, [[0.46,0.65,0.00], [0.04,-0.09,0.00], [0.19,0.04,0.00], [0.11,-0.00,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), - (3, [[0.48,0.53,0.00], [0.01,-0.14,0.00], [0.26,-0.00,0.00], [0.07,-0.07,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), - (4, [[0.47,0.36,0.00], [-0.04,-0.17,0.00], [0.30,-0.12,0.01], [0.00,-0.13,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), - (5, [[0.40,0.20,0.00], [-0.10,-0.15,0.00], [0.29,-0.24,0.00], [-0.05,-0.12,-0.01], [0.00,0.00,0.38], [0.00,0.00,0.02]]), - (6, [[0.26,0.08,0.00], [-0.21,-0.12,0.00], [0.19,-0.34,0.00], [-0.13,-0.08,0.00], [0.00,0.00,0.39], [0.00,0.00,0.00]]), - (7, [[0.00,0.00,0.00], [-0.29,-0.00,0.00], [0.01,-0.40,0.00], [-0.19,0.01,0.00], [0.00,0.00,0.38], [0.00,0.00,-0.01]]), - (8, [[-0.29,0.07,0.00], [-0.24,0.14,0.00], [-0.20,-0.32,0.00], [-0.13,0.14,0.01], [0.00,0.00,0.36], [0.01,0.00,-0.03]]), - (9, [[-0.44,0.25,0.00], [-0.09,0.18,0.00], [-0.26,-0.15,0.01], [0.01,0.14,0.00], [0.01,0.00,0.32], [0.00,0.00,-0.08]]), - (10, [[-0.48,0.42,0.00], [-0.02,0.16,0.00], [-0.18,-0.05,0.00], [0.08,0.05,0.00], [0.00,0.00,0.21], [0.00,0.00,-0.09]]), - (11, [[-0.48,0.56,0.00], [-0.03,0.14,0.00], [-0.10,-0.02,0.00], [0.05,-0.02,0.00], [0.00,0.00,0.13], [0.00,0.00,-0.04]]), - (12, [[-0.53,0.69,0.00], [-0.06,0.11,0.00], [-0.10,-0.06,0.00], [-0.05,-0.06,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) + (1, [[0.42,0.72,0.00], [0.04,-0.04,0.00], [0.07,0.03,0.00], [0.14,0.03,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), + (2, [[0.46,0.65,0.00], [0.03,-0.10,0.00], [0.19,0.04,0.00], [0.10,-0.01,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), + (3, [[0.48,0.53,0.00], [0.01,-0.15,0.00], [0.26,-0.00,0.00], [0.06,-0.07,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), + (4, [[0.47,0.36,0.00], [-0.04,-0.17,0.00], [0.30,-0.12,0.00], [0.02,-0.12,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), + (5, [[0.40,0.20,0.00], [-0.11,-0.15,0.00], [0.29,-0.24,0.00], [-0.05,-0.11,0.00], [0.00,0.00,0.38], [0.00,0.00,0.02]]), + (6, [[0.26,0.08,0.00], [-0.20,-0.11,0.00], [0.19,-0.34,0.00], [-0.13,-0.08,0.00], [0.00,0.00,0.39], [0.00,0.00,0.00]]), + (7, [[0.00,0.00,0.00], [-0.29,-0.01,0.00], [0.01,-0.40,0.00], [-0.19,0.01,0.00], [0.00,0.00,0.38], [0.00,0.00,-0.01]]), + (8, [[-0.29,0.07,0.00], [-0.24,0.13,0.00], [-0.20,-0.32,0.00], [-0.11,0.10,0.00], [0.00,0.00,0.36], [0.01,0.00,-0.03]]), + (9, [[-0.46,0.24,-0.00], [-0.09,0.19,0.00], [-0.23,-0.21,0.00], [0.02,0.12,0.00], [0.01,0.00,0.32], [-0.00,0.00,-0.08]]), + (10, [[-0.48,0.42,0.00], [-0.01,0.16,0.00], [-0.17,-0.08,0.00], [0.07,0.09,0.00], [0.00,0.00,0.21], [-0.00,0.00,-0.09]]), + (11, [[-0.48,0.56,0.00], [-0.03,0.14,0.00], [-0.10,-0.02,0.00], [0.03,0.01,0.00], [0.00,0.00,0.13], [0.00,0.00,-0.04]]), + (12, [[-0.53,0.69,0.00], [-0.07,0.12,0.00], [-0.10,-0.06,0.00], [-0.03,-0.09,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) ]), 'userAnnotationGroups': [ @@ -304,14 +304,14 @@ class MeshType_3d_stomach1(Scaffold_base): (1, [[0.492,0.623,0.000], [0.003,-0.035,0.000], [0.060,-0.002,0.000], [0.118,0.016,0.000], [0.000,0.000,0.080], [0.000,0.000,0.077]]), (2, [[0.490,0.553,0.000], [-0.008,-0.105,0.000], [0.180,-0.006,0.000], [0.122,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.083]]), (3, [[0.475,0.414,0.000], [-0.038,-0.151,0.000], [0.308,-0.071,0.000], [0.077,-0.090,0.000], [0.000,0.000,0.250], [0.000,0.000,0.072]]), - (4, [[0.409,0.256,0.000], [-0.082,-0.143,0.000], [0.324,-0.191,0.000], [-0.028,-0.116,0.001], [0.000,0.000,0.300], [0.000,0.000,0.040]]), - (5, [[0.315,0.129,0.000], [-0.120,-0.114,0.000], [0.256,-0.304,0.001], [-0.090,-0.100,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), - (6, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.059,-0.001], [0.000,0.000,0.360], [0.000,0.000,0.015]]), + (4, [[0.409,0.256,0.000], [-0.082,-0.143,0.000], [0.324,-0.191,0.000], [-0.028,-0.116,0.000], [0.000,0.000,0.300], [0.000,0.000,0.040]]), + (5, [[0.315,0.129,0.000], [-0.120,-0.114,0.000], [0.256,-0.304,0.000], [-0.090,-0.100,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), + (6, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.059,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), (7, [[0.000,0.000,0.000], [-0.200,0.002,0.000], [0.005,-0.420,0.000], [-0.156,0.002,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), (8, [[-0.218,0.048,0.000], [-0.209,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), - (9, [[-0.404,0.184,0.000], [-0.146,0.182,0.000], [-0.299,-0.260,0.000], [-0.056,0.122,0.005], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), - (10, [[-0.496,0.398,0.000], [-0.040,0.210,0.000], [-0.285,-0.130,0.010], [0.080,0.105,-0.001], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), - (11, [[-0.490,0.587,0.000], [-0.014,0.157,0.000], [-0.152,-0.045,0.000], [0.076,0.039,-0.004], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), + (9, [[-0.404,0.184,0.000], [-0.146,0.182,0.000], [-0.299,-0.260,0.000], [-0.056,0.122,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), + (10, [[-0.511,0.392,0.000], [-0.040,0.210,0.000], [-0.259,-0.148,0.000], [0.080,0.105,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), + (11, [[-0.490,0.587,0.000], [-0.014,0.157,0.000], [-0.152,-0.045,0.000], [0.076,0.039,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), (12, [[-0.516,0.708,0.000], [-0.031,0.116,0.000], [-0.111,-0.036,0.000], [0.009,-0.000,0.000], [0.000,0.000,0.120], [0.000,0.000,0.015]]), (13, [[-0.552,0.820,0.000], [-0.041,0.107,0.000], [-0.132,-0.045,0.000], [-0.050,-0.018,0.000], [0.000,0.000,0.150], [0.000,0.000,0.045]]) ]), @@ -1386,8 +1386,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio :return allAnnotationGroups, elementsCountGroupList """ elementsCountAroundDuod = options['Number of elements around duodenum'] - elementsAlongFundusApexToCardia = options['Number of elements between fundus apex and cardia'] - elementsAlongCardiaToDuod = options['Number of elements between cardia and duodenum'] + # elementsAlongFundusApexToCardia = options['Number of elements between fundus apex and cardia'] + # elementsAlongCardiaToDuod = options['Number of elements between cardia and duodenum'] targetLength = options['Target element unit length'] elementsCountThroughWall = options['Number of elements through wall'] mucosaRelThickness = options['Mucosa relative thickness'] @@ -1609,6 +1609,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio curvature = [1.0 for n in range(elementsCountAroundDuod)] d2Curvature.append(curvature) + count = 1 + sectionIdx = [0] for s in range(len(cxSections)): for n2 in range(1, len(cxSections[s])): px, pd1 = sampleEllipsePoints(cxSections[s][n2], cd2Sections[s][n2], cd3Sections[s][n2], @@ -1632,6 +1634,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d1EllipseAroundAll.append(pd1) d2EllipseAroundAll.append(d2Around) d2Curvature.append(d2CurvatureAround) + if n2 == len(cxSections[s]) - 1: + sectionIdx.append(count) + count += 1 if s == 0 and n2 == len(cxSections[s]) - 1: xGEJ = px[elementsAroundHalfDuod] @@ -1687,91 +1692,95 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # Visualise track surface # tmpRegion = region.createRegion() - nodeIdentifier, elementIdentifier = trackSurfaceStomach.generateMesh(region) #tmpRegion) - - # nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - # startNodeIdentifier = nodeIdentifier = max(get_maximum_node_identifier(nodes), 0) + 1 - # nodetemplate = nodes.createNodetemplate() - # nodetemplate.defineField(coordinates) - # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - # - # mesh = fm.findMeshByDimension(2) - # elementIdentifier = max(get_maximum_element_identifier(mesh), 0) + 1 - # elementtemplate = mesh.createElementtemplate() - # elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE) - # bicubicHermiteBasis = fm.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) - # eft = mesh.createElementfieldtemplate(bicubicHermiteBasis) - # # remove cross derivative terms - # for n in range(4): - # eft.setFunctionNumberOfTerms(n * 4 + 4, 0) - # elementtemplate.defineField(coordinates, -1, eft) - # - # fieldcache = fm.createFieldcache() - # with ChangeManager(fm): - # for n1 in range(len(trackSurfaceStomach.nx)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # fieldcache.setNode(node) - # coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, trackSurfaceStomach.nx[n1]) - # coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, trackSurfaceStomach.nd1[n1]) - # coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, trackSurfaceStomach.nd2[n1]) - # nodeIdentifier += 1 - # - # del n1 - # nodesCount1 = trackSurfaceStomach.elementsCount1 + 1 - # for e2 in range(trackSurfaceStomach.elementsCount2): - # for e1 in range(trackSurfaceStomach.elementsCount1): - # nid1 = startNodeIdentifier + e2 * nodesCount1 + e1 - # nids = [nid1, nid1 + 1, nid1 + nodesCount1, nid1 + nodesCount1 + 1] - # element = mesh.createElement(elementIdentifier, elementtemplate) - # element.setNodesByIdentifier(eft, nids) - # elementIdentifier += 1 - - # tmpRegion.getFieldmodule().defineAllFaces() - # tmpRegion.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_tracksurface.exf") - # del tmpRegion - - # # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction - # GEJSettings['Number of elements around ostium'] = elementsCountAroundEso - # GEJPosition = trackSurfaceStomach.findNearestPosition(xGEJ) - # xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GEJPosition, derivatives=True) - # axis1 = d1Centre - # - # esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) - # esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) - # abdominalEsoGroup = AnnotationGroup(region, get_esophagus_term("abdominal part of esophagus")) - # abdominalEsoMeshGroup = abdominalEsoGroup.getMeshGroup(mesh) - # esophagogastricJunctionGroup = AnnotationGroup(region, get_stomach_term("esophagogastric junction")) - # esophagogastricJunctionMeshGroup = esophagogastricJunctionGroup.getMeshGroup(mesh) - # stomachMeshGroup = stomachGroup.getMeshGroup(mesh) - # allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup, abdominalEsoGroup] - # - # ostiumWallAnnotationGroups = [] - # if elementsCountThroughWall == 4: - # esophagusMucosaGroup = AnnotationGroup(region, get_esophagus_term("esophagus mucosa")) - # esophagusSubmucosaGroup = AnnotationGroup(region, get_esophagus_term("submucosa of esophagus")) - # esophagusCircularGroup = AnnotationGroup(region, get_esophagus_term("esophagus smooth muscle circular layer")) - # esophagusLongitudinalGroup = AnnotationGroup(region, - # get_esophagus_term("esophagus smooth muscle longitudinal layer")) - # - # ostiumWallAnnotationGroups = [[esophagusMucosaGroup, mucosaGroup], - # [esophagusSubmucosaGroup, submucosaGroup], - # [esophagusCircularGroup, circularMuscleGroup], - # [esophagusLongitudinalGroup, longitudinalMuscleGroup]] - # - # allAnnotationGroups += [esophagusMucosaGroup, esophagusSubmucosaGroup, - # esophagusCircularGroup, esophagusLongitudinalGroup] - # - # nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - # generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, - # nodeIdentifier, elementIdentifier, - # vesselMeshGroups=[[stomachMeshGroup, esophagusMeshGroup, abdominalEsoMeshGroup]], - # ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup], - # wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=coordinates) - - # stomachStartNode = nextNodeIdentifier - # nodeIdentifier = nextNodeIdentifier - # elementIdentifier = nextElementIdentifier + # nodeIdentifier, elementIdentifier = trackSurfaceStomach.generateMesh(region) + + # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction + GEJSettings['Number of elements around ostium'] = elementsCountAroundEso + GEJPosition = trackSurfaceStomach.findNearestPosition(xGEJ) + xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GEJPosition, derivatives=True) + axis1 = d1Centre + + esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) + esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) + abdominalEsoGroup = AnnotationGroup(region, get_esophagus_term("abdominal part of esophagus")) + abdominalEsoMeshGroup = abdominalEsoGroup.getMeshGroup(mesh) + esophagogastricJunctionGroup = AnnotationGroup(region, get_stomach_term("esophagogastric junction")) + esophagogastricJunctionMeshGroup = esophagogastricJunctionGroup.getMeshGroup(mesh) + stomachMeshGroup = stomachGroup.getMeshGroup(mesh) + allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup, abdominalEsoGroup] + + ostiumWallAnnotationGroups = [] + if elementsCountThroughWall == 4: + esophagusMucosaGroup = AnnotationGroup(region, get_esophagus_term("esophagus mucosa")) + esophagusSubmucosaGroup = AnnotationGroup(region, get_esophagus_term("submucosa of esophagus")) + esophagusCircularGroup = AnnotationGroup(region, get_esophagus_term("esophagus smooth muscle circular layer")) + esophagusLongitudinalGroup = AnnotationGroup(region, + get_esophagus_term("esophagus smooth muscle longitudinal layer")) + + ostiumWallAnnotationGroups = [[esophagusMucosaGroup, mucosaGroup], + [esophagusSubmucosaGroup, submucosaGroup], + [esophagusCircularGroup, circularMuscleGroup], + [esophagusLongitudinalGroup, longitudinalMuscleGroup]] + + allAnnotationGroups += [esophagusMucosaGroup, esophagusSubmucosaGroup, + esophagusCircularGroup, esophagusLongitudinalGroup] + + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, + nodeIdentifier, elementIdentifier, + vesselMeshGroups=[[stomachMeshGroup, esophagusMeshGroup, abdominalEsoMeshGroup]], + ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup], + wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=coordinates) + + stomachStartNode = nextNodeIdentifier + nodeIdentifier = nextNodeIdentifier + elementIdentifier = nextElementIdentifier + + # if materialCoordinates: + # GEJSettings['Unit scale'] = unitScale + # GEJSettings['Ostium diameter'] = ostiumDiameter + # GEJSettings['Ostium length'] = ostiumLength + # GEJSettings['Ostium wall thickness'] = ostiumWallThickness + # GEJSettings['Ostium wall relative thicknesses'] = ostiumWallRelThicknesses + # GEJSettings['Vessel inner diameter'] = vesselInnerDiameter + # GEJSettings['Vessel wall thickness'] = vesselWallThickness + # GEJSettings['Vessel wall relative thicknesses'] = vesselWallRelThicknesses + # GEJSettings['Vessel angle 1 degrees'] = vesselAngle1 + # GEJSettings['Vessel angle 2 degrees'] = vesselAngle2 + + # Create location of annulus + xAnnulusOuter = [[] for x in range(elementsCountAroundEso)] + xAnnulusOuterPosition = [[] for x in range(elementsCountAroundEso)] + d2AnnulusNorm = [] + d2AnnulusOuter = [] + for n1 in range(elementsCountAroundEso): + normD2 = vector.normalise(o1_d2[-1][n1]) + d2AnnulusNorm.append(normD2) + d2AnnulusOuter.append(vector.setMagnitude(o1_d2[-1][n1], sf)) + x = [o1_x[-1][n1][c] + sf * normD2[c] for c in range(3)] + nearestPosition = trackSurfaceStomach.findNearestPosition(x) + xAnnulusOuterPosition[n1] = nearestPosition + xAnnulusOuter[n1] = trackSurfaceStomach.evaluateCoordinates(nearestPosition) + + d1AnnulusOuter = [] + for n in range(elementsCountAroundEso): + d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundEso]) + d1AnnulusOuter.append(d) + d1AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) + d3Annulus = [] + for n in range(elementsCountAroundEso): + d3 = vector.normalise(vector.crossproduct3(vector.normalise(d1AnnulusOuter[n]), d2AnnulusNorm[n])) + d3Annulus.append(d3) + # annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + + # for m in range(len(xAnnulusOuter)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusOuter[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AnnulusOuter[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AnnulusOuter[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 # Calculate arclength at quarter line between lesser and greater curvature for each region xQuarterEllipseAll = [] @@ -1789,48 +1798,446 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xList.append(xQuarterEllipseAll[n]) d2List.append(d2QuarterEllipseAll[n]) quarterLengthSection = interp.getCubicHermiteCurvesLength(xList, d2List) - ratioArcLengthSections.append(quarterLengthSection/totalQuarterLength) + ratioArcLengthSections.append(quarterLengthSection / totalQuarterLength) elementsAlongSections = [math.ceil(c / targetLength) for c in ratioArcLengthSections] + totalElementsAlong = sum(elementsAlongSections) print(elementsAlongSections) - # if materialCoordinates: - # GEJSettings['Unit scale'] = unitScale - # GEJSettings['Ostium diameter'] = ostiumDiameter - # GEJSettings['Ostium length'] = ostiumLength - # GEJSettings['Ostium wall thickness'] = ostiumWallThickness - # GEJSettings['Ostium wall relative thicknesses'] = ostiumWallRelThicknesses - # GEJSettings['Vessel inner diameter'] = vesselInnerDiameter - # GEJSettings['Vessel wall thickness'] = vesselWallThickness - # GEJSettings['Vessel wall relative thicknesses'] = vesselWallRelThicknesses - # GEJSettings['Vessel angle 1 degrees'] = vesselAngle1 - # GEJSettings['Vessel angle 2 degrees'] = vesselAngle2 - # - # # Create location of annulus - # xAnnulusOuter = [[] for x in range(elementsCountAroundEso)] - # xAnnulusOuterPosition = [[] for x in range(elementsCountAroundEso)] - # d1AnnulusNorm = [] - # d1AnnulusOuter = [] - # for n1 in range(elementsCountAroundEso): - # normD2 = vector.normalise(o1_d2[-1][n1]) - # d1AnnulusNorm.append(normD2) - # d1AnnulusOuter.append(vector.setMagnitude(o1_d2[-1][n1], sf)) - # x = [o1_x[-1][n1][c] + sf * normD2[c] for c in range(3)] - # nearestPosition = trackSurfaceStomach.findNearestPosition(x) - # xAnnulusOuterPosition[n1] = nearestPosition - # xAnnulusOuter[n1] = trackSurfaceStomach.evaluateCoordinates(nearestPosition) - # - # d2AnnulusOuter = [] - # for n in range(elementsCountAroundEso): - # d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundEso]) - # d2AnnulusOuter.append(d) - # d2AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) - # d3Annulus = [] - # for n in range(elementsCountAroundEso): - # d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) - # d3Annulus.append(d3) - # annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + xSampledAlong = [[] for n1 in range(elementsCountAroundDuod)] + d1SampledAlong = [[] for n1 in range(elementsCountAroundDuod)] + d2SampledAlong = [[] for n1 in range(elementsCountAroundDuod)] + d3SampledAlong = [[] for n1 in range(elementsCountAroundDuod)] + + for i in range(len(sectionIdx) - 1): + s = sectionIdx[i] + sNext = sectionIdx[i + 1] + for n1 in range(len(xEllipseAroundAll[s])): + #for each pt around, we take the point on the sectionIdx as Pt A and the point on sectionIdx + 1 as Pt B, + # do a tracksurface sampling to divide the elements into equal sized elements while keeping the start and + # end derivatives direction at both pts + elementsOut = elementsAlongSections[i] + if i == 1 and n1 == elementsAroundHalfDuod - 1: + aPosition = xAnnulusOuterPosition[elementsAroundHalfEso - 1] + elementsOut = elementsAlongSections[i] - 1 + elif i == 1 and n1 == elementsAroundHalfDuod: + aPosition = xAnnulusOuterPosition[elementsAroundHalfEso] + elementsOut = elementsAlongSections[i] - 1 + elif i == 1 and n1 == elementsAroundHalfDuod + 1: + aPosition = xAnnulusOuterPosition[elementsAroundHalfEso + 1] + elementsOut = elementsAlongSections[i] - 1 + else: + startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0/elementsCountAroundDuod * n1, + 1.0/len(xEllipseAroundAll) * s) + aPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[s][n1], startGuessPosition) + aProportion = trackSurfaceStomach.getProportion(aPosition) + + if i == 0 and n1 == elementsAroundHalfDuod - 1: + bPosition = xAnnulusOuterPosition[1] + elementsOut = elementsAlongSections[i] - 1 + elif i == 0 and n1 == elementsAroundHalfDuod: + bPosition = xAnnulusOuterPosition[0] + elementsOut = elementsAlongSections[i] - 1 + elif i == 0 and n1 == elementsAroundHalfDuod + 1: + bPosition = xAnnulusOuterPosition[-1] + elementsOut = elementsAlongSections[i] - 1 + + else: + startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * n1, + 1.0 / len(xEllipseAroundAll) * sNext) + bPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[sNext][n1], startGuessPosition) + bProportion = trackSurfaceStomach.getProportion(bPosition) + + nx, nd1, nd2, nd3, proportions = trackSurfaceStomach.createHermiteCurvePoints( + aProportion[0], aProportion[1], bProportion[0], bProportion[1], elementsOut, + curveMode=TrackSurface.HermiteCurveMode.UNIFORM_SIZE) + + nx, nd1, nd2, nd3 = \ + trackSurfaceStomach.resampleHermiteCurvePointsSmooth(nx, nd1, nd2, nd3, proportions)[:-1] + + # Rotate nd2 + for m in range(len(nx)): + rotFrame = matrix.getRotationMatrixFromAxisAngle(nd3[m], math.pi) + nd2[m] = [rotFrame[j][0] * nd2[m][0] + rotFrame[j][1] * nd2[m][1] + + rotFrame[j][2] * nd2[m][2] for j in range(3)] + + # Deal with annulus + if i == 0: + if n1 == elementsAroundHalfDuod: + nx.append(zero) + nd1.append(zero) + nd2.append(zero) + nd3.append(zero) + elif n1 == elementsAroundHalfDuod - 1: + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundQuarterEso], math.pi) + d2 = d2AnnulusOuter[elementsAroundQuarterEso] + d2 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + nx.append(xAnnulusOuter[elementsAroundQuarterEso]) + nd1.append(d1AnnulusOuter[elementsAroundQuarterEso]) + nd2.append(d2) + nd3.append(d3Annulus[elementsAroundQuarterEso]) + + elif n1 == elementsAroundHalfDuod + 1: + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[-elementsAroundQuarterEso], math.pi) + d1 = d1AnnulusOuter[-elementsAroundQuarterEso] + d1 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] + nx.append(xAnnulusOuter[-elementsAroundQuarterEso]) + nd1.append(d1) + nd2.append(d2AnnulusOuter[-elementsAroundQuarterEso]) + nd3.append(d3Annulus[-elementsAroundQuarterEso]) + + if i == 1 and elementsAroundHalfDuod - 1 <= n1 <= elementsAroundHalfDuod + 1: + xSampledAlong[n1] += nx + d1SampledAlong[n1] += nd2 + d2SampledAlong[n1] += nd1 + d3SampledAlong[n1] += nd3 + + else: + xSampledAlong[n1] += nx[1:] if i else nx + d1SampledAlong[n1] += nd2[1:] if i else nd2 + d2SampledAlong[n1] += nd1[1:] if i else nd1 + d3SampledAlong[n1] += nd3[1:] if i else nd3 + + # for n1 in range(len(xSampledAlong)): + # for n2 in range(len(xSampledAlong[n1])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAlong[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAlong[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAlong[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3SampledAlong[n1][n2]) + # nodeIdentifier += 1 + + # Rearrange to around first + xSampledAroundAlong = [] + d1SampledAroundAlong = [] + d2SampledAroundAlong = [] + d3SampledAroundAlong = [] + + for n2 in range(totalElementsAlong + 1): + xSampledAround = [] + d1SampledAround = [] + d2SampledAround = [] + d3SampledAround = [] + for n1 in range(elementsCountAroundDuod): + xSampledAround.append(xSampledAlong[n1][n2]) + d1SampledAround.append(d1SampledAlong[n1][n2]) + d2SampledAround.append(d2SampledAlong[n1][n2]) + d3SampledAround.append(d3SampledAlong[n1][n2]) + xSampledAroundAlong.append(xSampledAround) + d1SampledAroundAlong.append(d1SampledAround) + d2SampledAroundAlong.append(d2SampledAround) + d3SampledAroundAlong.append(d3SampledAround) + + bodyStartIdx = elementsAlongSections[0] + + # Smooth d1 around + d1SmoothedAroundAlong = [d1EllipseAroundAll[0]] + for n2 in range(1, len(xSampledAroundAlong)): + if n2 == bodyStartIdx: + d1SmoothedLeft = \ + interp.smoothCubicHermiteDerivativesLine(xSampledAroundAlong[n2][0:elementsAroundHalfDuod], + d1SampledAroundAlong[n2][0:elementsAroundHalfDuod]) + d1SmoothedRight = \ + interp.smoothCubicHermiteDerivativesLine(xSampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + + [xSampledAroundAlong[n2][0]], + d1SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + + [d1SampledAroundAlong[n2][0]]) + d1Smoothed = d1SmoothedLeft + [[1.0, 0.0, 0.0]] + d1SmoothedRight[:-1] + + else: + d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xSampledAroundAlong[n2], d1SampledAroundAlong[n2]) + d1SmoothedAroundAlong.append(d1Smoothed) + + d1SampledAroundAlong = d1SmoothedAroundAlong + + # for n2 in range(len(xSampledAroundAlong)): + # for n1 in range(len(xSampledAroundAlong[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3SampledAroundAlong[n2][n1]) + # nodeIdentifier += 1 + + # Smooth d2 along + for n1 in range(elementsCountAroundDuod): + nx = [] + nd2 = [] + if n1 == elementsAroundHalfDuod: + for n2 in range(bodyStartIdx): + nx.append(xSampledAroundAlong[n2][n1]) + nd2.append(d2SampledAroundAlong[n2][n1]) + d2SmoothedAlongGC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + d2SmoothedAlongGC[-1] = vector.setMagnitude(d2SmoothedAlongGC[-1], + 0.5*(vector.magnitude(d2AnnulusOuter[0]) + + vector.magnitude(d2SmoothedAlongGC[-1]))) + + nx = [] + nd2 = [] + for n2 in range(bodyStartIdx + 1, len(xSampledAroundAlong)): + nx.append(xSampledAroundAlong[n2][n1]) + nd2.append(d2SampledAroundAlong[n2][n1]) + d2SmoothedAlongLC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + d2SmoothedAlongLC[0] = vector.setMagnitude(d2SmoothedAlongLC[0], + 0.5*(vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso]) + + (vector.magnitude(d2SmoothedAlongLC[0])))) + + d2Smoothed = d2SmoothedAlongGC + [[0.0, 1.0, 0.0]] + d2SmoothedAlongLC + + else: + for n2 in range(len(xSampledAroundAlong)): + nx.append(xSampledAroundAlong[n2][n1]) + nd2.append(d2SampledAroundAlong[n2][n1]) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + + if n1 == elementsAroundHalfDuod - 1: + d2Smoothed[bodyStartIdx - 1] = \ + vector.setMagnitude(d1AnnulusOuter[1], + 0.5 * (vector.magnitude(d2Smoothed[bodyStartIdx - 1]) + + vector.magnitude(d1AnnulusOuter[1]))) + d2Smoothed[bodyStartIdx] = \ + vector.setMagnitude(d2Smoothed[bodyStartIdx], + vector.magnitude(d1AnnulusOuter[elementsAroundQuarterEso])) + d2Smoothed[bodyStartIdx + 1] = \ + vector.setMagnitude(d1AnnulusOuter[elementsAroundQuarterEso + 1], + 0.5 * (vector.magnitude(d2Smoothed[bodyStartIdx + 1]) + + vector.magnitude(d2AnnulusOuter[elementsAroundQuarterEso + 1]))) + + if n1 == elementsAroundHalfDuod + 1: + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[-1], math.pi) + d1 = d1AnnulusOuter[-1] + d2 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] + d2Smoothed[bodyStartIdx - 1] = \ + vector.setMagnitude(d2, 0.5*(vector.magnitude(d2Smoothed[bodyStartIdx - 1]) + + vector.magnitude(d1AnnulusOuter[-1]))) + d2Smoothed[bodyStartIdx] = \ + vector.setMagnitude(d2Smoothed[bodyStartIdx], + vector.magnitude(d1AnnulusOuter[-elementsAroundQuarterEso])) + + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[-elementsAroundQuarterEso - 1], math.pi) + d1 = d1AnnulusOuter[-elementsAroundQuarterEso - 1] + d2 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] + d2Smoothed[bodyStartIdx + 1] = \ + vector.setMagnitude(d2, 0.5 * (vector.magnitude(d2Smoothed[bodyStartIdx + 1]) + + vector.magnitude(d2AnnulusOuter[-elementsAroundQuarterEso - 1]))) + + for n2 in range(len(d2Smoothed)): + d2SampledAroundAlong[n2][n1] = d2Smoothed[n2] + + # calculate d3 + for n2 in range(len(xSampledAroundAlong)): + for n1 in range(len(xSampledAroundAlong[n2])): + d3SampledAroundAlong[n2][n1] = vector.normalise(vector.crossproduct3(vector.normalise(d1SampledAroundAlong[n2][n1]), + vector.normalise(d2SampledAroundAlong[n2][n1]))) + + # Calculate curvature around + d1CurvatureAroundAlong = [[0.0 for n in range(elementsCountAroundDuod)]] # check later + for n2 in range(1, len(xSampledAroundAlong)): + if n2 == bodyStartIdx: + d1CurvatureLeft = findCurvatureAlongLine(xSampledAroundAlong[n2][0:elementsAroundHalfDuod], + d1SampledAroundAlong[n2][0:elementsAroundHalfDuod], + d3SampledAroundAlong[n2][0:elementsAroundHalfDuod]) + d1CurvatureRight = \ + findCurvatureAlongLine(xSampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [xSampledAroundAlong[n2][0]], + d1SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [d1SampledAroundAlong[n2][0]], + d3SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [d3SampledAroundAlong[n2][0]]) + d1Curvature = d1CurvatureLeft + [0.0] + d1CurvatureRight[:-1] + else: + d1Curvature = findCurvatureAroundLoop(xSampledAroundAlong[n2], d1SampledAroundAlong[n2], d3SampledAroundAlong[n2]) + d1CurvatureAroundAlong.append(d1Curvature) + + # Replace derivatives around annulus + # bodyStartIdx - 1 + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[1], math.pi) + d2 = d2AnnulusOuter[1] + d1 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod - 1] = \ + vector.setMagnitude(d1, 0.5 * + (vector.magnitude(d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod - 1]) + + vector.magnitude(d2AnnulusOuter[1]))) + + d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod] = \ + vector.setMagnitude(d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod], + vector.magnitude(d1AnnulusOuter[0])) + + d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod + 1] = \ + vector.setMagnitude(d2AnnulusOuter[-1], 0.5 * + (vector.magnitude(d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod + 1]) + + vector.magnitude(d2AnnulusOuter[-1]))) + + # bodyStartIdx + 1 + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundQuarterEso + 1], math.pi) + d2 = d2AnnulusOuter[elementsAroundQuarterEso + 1] + d1 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod - 1] = \ + vector.setMagnitude(d1, 0.5 * + (vector.magnitude(d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod - 1]) + + vector.magnitude(d2AnnulusOuter[elementsAroundQuarterEso + 1]))) + + d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod] = \ + vector.setMagnitude(d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod], + vector.magnitude(d1AnnulusOuter[elementsAroundHalfEso])) + + d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod + 1] = \ + vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso + 1], 0.5 * + (vector.magnitude(d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod + 1]) + + vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso + 1]))) + + # Calculate curvature along + d2CurvatureAroundAlong = [[[] for n1 in range(len(xSampledAroundAlong[n2]))] + for n2 in range(len(xSampledAroundAlong))] + + for n1 in range(elementsCountAroundDuod): + nx = [] + nd2 = [] + nd3 = [] + if n1 == elementsAroundHalfDuod: + for n2 in range(bodyStartIdx): + nx.append(xSampledAroundAlong[n2][n1]) + nd2.append(d2SampledAroundAlong[n2][n1]) + nd3.append(d3SampledAroundAlong[n2][n1]) + d2CurvatureAlongGC = findCurvatureAlongLine(nx, nd2, nd3) + + nx = [] + nd2 = [] + nd3 = [] + # print(d2SampledAroundAlong[bodyStartIdx + 1][n1]) + for n2 in range(bodyStartIdx + 1, len(xSampledAroundAlong)): + nx.append(xSampledAroundAlong[n2][n1]) + nd2.append(d2SampledAroundAlong[n2][n1]) + nd3.append(d3SampledAroundAlong[n2][n1]) + # print(n2, n1) + d2CurvatureAlongLC = findCurvatureAlongLine(nx, nd2, nd3) + d2CurvatureAlong = d2CurvatureAlongGC + [0.0] + d2CurvatureAlongLC + + else: + for n2 in range(len(xSampledAroundAlong)): + nx.append(xSampledAroundAlong[n2][n1]) + nd2.append(d2SampledAroundAlong[n2][n1]) + nd3.append(d3SampledAroundAlong[n2][n1]) + d2CurvatureAlong = findCurvatureAlongLine(nx, nd2, nd3) + + for n2 in range(len(d2CurvatureAlong)): + d2CurvatureAroundAlong[n2][n1] = d2CurvatureAlong[n2] + + del xSampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] + del d1SampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] + del d2SampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] + del d3SampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] + + # Remove multiple nodes at apex + del xSampledAroundAlong[0][1:], d1SampledAroundAlong[0][1:], d2SampledAroundAlong[0][1:], \ + d3SampledAroundAlong[0][1:], d1CurvatureAroundAlong[0][1:], d2CurvatureAroundAlong[0][1:] + + # Set magnitude for d1 at apex + arcLength = interp.computeCubicHermiteArcLength(xSampledAroundAlong[0][0], d1SampledAroundAlong[0][0], + xSampledAroundAlong[1][elementsAroundQuarterDuod], + d2SampledAroundAlong[1][elementsAroundQuarterDuod], + rescaleDerivatives=True) + d1SampledAroundAlong[0][0] = vector.setMagnitude(d1SampledAroundAlong[0][0], arcLength) + d2SampledAroundAlong[0][0] = vector.setMagnitude(d2SampledAroundAlong[0][0], arcLength) + + # Replace d1Curvature with d2Curvature + d1CurvatureAroundAlong[0][0] = d2CurvatureAroundAlong[0][0] + + # for n2 in range(len(xSampledAroundAlong)): + # for n1 in range(len(xSampledAroundAlong[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3SampledAroundAlong[n2][n1]) + # nodeIdentifier += 1 + + # Create inner nodes + xList = [] + d1List = [] + d2List = [] + d3List = [] + nodeIdx = stomachStartNode + idxMat = [] + + if elementsCountThroughWall > 1: + thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, + longitudinalRelThickness, longitudinalRelThickness] + thicknessProportions = [thicknessProportion / sum(thicknessProportionsUI[:-1]) + for thicknessProportion in thicknessProportionsUI] + + xi3List = [] + xi3 = 0.0 + for i in range(len(thicknessProportions) - 1): + xi3 += thicknessProportions[i] + xi3List.append(xi3) + + for n2 in range(len(xSampledAroundAlong)): + idxThroughWall = [] + for n3 in range(elementsCountThroughWall + 1): + xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 + idxAround = [] + for n1 in range(len(xSampledAroundAlong[n2])): + # Coordinates + norm = vector.normalise(d3SampledAroundAlong[n2][n1]) + xOut = xSampledAroundAlong[n2][n1] + xIn = [xOut[i] - norm[i] * wallThickness for i in range(3)] + dWall = [wallThickness * c for c in norm] + x = interp.interpolateCubicHermite(xIn, dWall, xOut, dWall, xi3) + xList.append(x) + + # d1 + factor = 1.0 + wallThickness * (1.0 - xi3) * d1CurvatureAroundAlong[n2][n1] + d1 = [factor * c for c in d1SampledAroundAlong[n2][n1]] + d1List.append(d1) + + # d2 + factor = 1.0 + wallThickness * (1.0 - xi3) * d2CurvatureAroundAlong[n2][n1] + d2 = [factor * c for c in d2SampledAroundAlong[n2][n1]] + d2List.append(d2) + + # d3 + d3 = [c * wallThickness * (thicknessProportions[n3 + 1] if elementsCountThroughWall > 1 else 1.0) + for c in norm] + d3List.append(d3) + + idxAround.append(nodeIdx) + nodeIdx += 1 + idxThroughWall.append(idxAround) + idxMat.append(idxThroughWall) + + nodeIdxGC = [] + for n2 in range(len(idxMat)): + for n3 in range(len(idxMat[n2])): + if n2 == 0: + nodeIdxGC += idxMat[n2][n3] + else: + nodeIdxGC.append(idxMat[n2][n3][0]) + + # for n2 in range(1, bodyStartIdx + 1): + # for n3 in range(len(idxMat[n2])): + # nodeIdxGC.append(idxMat[n2][n3][int(0.5 * len(xSampledAroundAlong[n2]))]) # + # nodeIdxLC = [] + # for n2 in range(elementsAlongCardiaToDuod + 1): + # for n3 in range(len(idxMat[n2])): + # nodeIdxLC.append( + # idxMat[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 + n2][n3][elementsAroundHalfDuod]) + + for n2 in range(len(xList)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xList[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1List[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2List[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n2]) + 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 += 1 + # # Adjust annulus derivatives # # Make d2 on second half of eso point towards duodenum # for n1 in range(elementsAroundHalfEso - 1): @@ -2451,461 +2858,297 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # # Replace d1Curvature at apex with d2Curvature # for n1 in range(elementsCountAroundDuod): # d1Curvature[0][n1] = d2Curvature[0][n1] - # - # # Create inner nodes - # xList = [] - # d1List = [] - # d2List = [] - # d3List = [] - # nodeIdx = stomachStartNode - # idxMat = [] - # - # if elementsCountThroughWall > 1: - # thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, - # longitudinalRelThickness, longitudinalRelThickness] - # thicknessProportions = [thicknessProportion / sum(thicknessProportionsUI[:-1]) - # for thicknessProportion in thicknessProportionsUI] - # - # xi3List = [] - # xi3 = 0.0 - # for i in range(len(thicknessProportions) - 1): - # xi3 += thicknessProportions[i] - # xi3List.append(xi3) - # - # for n2 in range(len(xOuter)): - # idxThroughWall = [] - # for n3 in range(elementsCountThroughWall + 1): - # xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 - # idxAround = [] - # for n1 in range(1 if n2 == 0 else len(xOuter[n2])): - # # Coordinates - # norm = d3UnitOuter[n2][n1] - # xOut = xOuter[n2][n1] - # xIn = [xOut[i] - norm[i] * wallThickness for i in range(3)] - # dWall = [wallThickness * c for c in norm] - # x = interp.interpolateCubicHermite(xIn, dWall, xOut, dWall, xi3) - # xList.append(x) - # - # # d1 - # factor = 1.0 + wallThickness * (1.0 - xi3) * d1Curvature[n2][n1] - # d1 = [factor * c for c in d1Outer[n2][n1]] - # d1List.append(d1) - # - # # d2 - # factor = 1.0 + wallThickness * (1.0 - xi3) * d2Curvature[n2][n1] - # d2 = [factor * c for c in d2Outer[n2][n1]] - # d2List.append(d2) - # - # # d3 - # d3 = [c * wallThickness * (thicknessProportions[n3 + 1] if elementsCountThroughWall > 1 else 1.0) - # for c in norm] - # d3List.append(d3) - # - # idxAround.append(nodeIdx) - # nodeIdx += 1 - # idxThroughWall.append(idxAround) - # idxMat.append(idxThroughWall) - # - # nodeIdxGC = [] - # for n2 in range(len(idxMat)): - # for n3 in range(len(idxMat[n2])): - # if n2 == 0: - # nodeIdxGC += idxMat[n2][n3] - # else: - # nodeIdxGC.append(idxMat[n2][n3][0]) - # - # for n2 in range(1, elementsAlongFundusApexToCardia + 1): - # for n3 in range(len(idxMat[n2])): - # nodeIdxGC.append(idxMat[n2][n3][int(0.5 * len(xOuter[n2]))]) - # - # nodeIdxLC = [] - # for n2 in range(elementsAlongCardiaToDuod + 1): - # for n3 in range(len(idxMat[n2])): - # nodeIdxLC.append( - # idxMat[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 + n2][n3][elementsAroundHalfDuod]) - # - # for n2 in range(len(xList)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xList[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1List[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2List[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n2]) - # 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 += 1 - # - # annotationGroupsAlong = [] - # for i in range(len(elementCountGroupList)): - # elementsCount = elementCountGroupList[i] - # for n in range(elementsCount): - # annotationGroupsAlong.append(annotationGroupAlong[i]) - # - # # Create elements - # fundusMucosaElementIdentifiers = [] - # elementIdxMat = [] - # n = 0 - # for n2 in range(elementsAlongEsophagus): - # elementIdxThroughWall = [] - # for n3 in range(elementsThroughEsophagusWall): - # elementIdxAround = [] - # for n1 in range(elementsCountAroundEso): - # n += 1 - # elementIdxAround.append(n) - # elementIdxThroughWall.append(elementIdxAround) - # elementIdxMat.append(elementIdxThroughWall) - # - # if useCubicHermiteThroughWall: - # eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives) - # else: - # eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) - # eftStandard = eftfactory.createEftBasic() - # - # elementtemplateStandard = mesh.createElementtemplate() - # elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) - # elementtemplateStandard.defineField(coordinates, -1, eftStandard) - # - # elementtemplateX = mesh.createElementtemplate() - # elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) - # - # fundusElements = elementCountGroupList[0] - # radiansPerElementAroundDuod = math.pi * 2.0 / elementsCountAroundDuod - # - # for e2 in range(len(xOuter) - 1): - # elementIdxThroughWall = [] - # if e2 == 0: # pole - # for e3 in range(elementsCountThroughWall): - # elementIdxAround = [] - # for e1 in range(elementsCountAroundDuod): - # va = e1 - # vb = (e1 + 1) % elementsCountAroundDuod - # eft1 = eftfactory.createEftShellPoleBottom(va*100, vb*100) - # elementtemplateX.defineField(coordinates, -1, eft1) - # element = mesh.createElement(elementIdentifier, elementtemplateX) - # bni1 = e3 + stomachStartNode - # bni2 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + e1 - # bni3 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + \ - # (e1 + 1) % elementsCountAroundDuod - # nodeIdentifiers = [bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAroundDuod, - # bni3 + elementsCountAroundDuod] - # - # element.setNodesByIdentifier(eft1, nodeIdentifiers) - # # set general linear map coefficients - # radiansAround = e1 * radiansPerElementAroundDuod - # radiansAroundNext = ((e1 + 1) % elementsCountAroundDuod) * radiansPerElementAroundDuod - # scalefactors = [ - # -1.0, - # math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, - # math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod, - # math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, - # math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod - # ] - # element.setScaleFactors(eft1, scalefactors) - # if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: - # fundusMucosaElementIdentifiers.append(elementIdentifier) - # elementIdxAround.append(elementIdentifier) - # elementIdentifier += 1 - # annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - # if annotationGroups: - # allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - # for annotationGroup in annotationGroups: - # meshGroup = annotationGroup.getMeshGroup(mesh) - # meshGroup.addElement(element) - # elementIdxThroughWall.append(elementIdxAround) - # elementIdxMat.append(elementIdxThroughWall) - # - # elif 0 < e2 < elementsAlongFundusApexToCardia or \ - # e2 > elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: - # for e3 in range(elementsCountThroughWall): - # elementIdxAround = [] - # for e1 in range(len(xOuter[e2])): - # eft1 = eftStandard - # scaleFactors = [] - # elementtemplate1 = elementtemplateStandard - # bni111 = idxMat[e2][e3][e1] - # bni211 = idxMat[e2][e3][(e1 + 1) % len(idxMat[e2][e3])] - # bni121 = idxMat[e2 + 1][e3][e1] - # bni221 = idxMat[e2 + 1][e3][(e1 + 1) % len(idxMat[e2 + 1][e3])] - # bni112 = idxMat[e2][e3 + 1][e1] - # bni212 = idxMat[e2][e3 + 1][(e1 + 1) % len(idxMat[e2][e3])] - # bni122 = idxMat[e2 + 1][e3 + 1][e1] - # bni222 = idxMat[e2 + 1][e3 + 1][(e1 + 1) % len(idxMat[e2 + 1][e3])] - # nodeIdentifiers = [bni111, bni211, bni121, bni221, - # bni112, bni212, bni122, bni222] - # - # if e2 == elementsAlongFundusApexToCardia - 1: - # if e1 == int(0.5 * len(xOuter[e2]) - 2): - # eft1 = eftfactory.createEftNoCrossDerivatives() - # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # elif e1 == int(0.5 * len(xOuter[e2]) - 1): - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # elif e1 == int(0.5 * len(xOuter[e2])): - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # elif e1 == int(0.5 * len(xOuter[e2]) + 1): - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # if e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - # if e1 == int(0.5 * len(xOuter[e2]) - 2): - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # elif e1 == int(0.5 * len(xOuter[e2]) - 1): - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # elif e1 == int(0.5 * len(xOuter[e2])): - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # elif e1 == int(0.5 * len(xOuter[e2]) + 1): - # eft1 = eftfactory.createEftNoCrossDerivatives() - # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # element = mesh.createElement(elementIdentifier, elementtemplate1) - # element.setNodesByIdentifier(eft1, nodeIdentifiers) - # if scaleFactors: - # element.setScaleFactors(eft1, scaleFactors) - # if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: - # fundusMucosaElementIdentifiers.append(elementIdentifier) - # elementIdxAround.append(elementIdentifier) - # elementIdentifier += 1 - # annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - # if annotationGroups: - # allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - # for annotationGroup in annotationGroups: - # meshGroup = annotationGroup.getMeshGroup(mesh) - # meshGroup.addElement(element) - # elementIdxThroughWall.append(elementIdxAround) - # elementIdxMat.append(elementIdxThroughWall) - # - # elif elementsAlongFundusApexToCardia <= e2 <= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: - # for e3 in range(elementsCountThroughWall): - # elementIdxAround = [] - # for e1 in range(elementsCountAroundDuod - 2): - # eft1 = eftStandard - # scaleFactors = [] - # elementtemplate1 = elementtemplateStandard - # if e1 > elementsAroundHalfDuod - 2: - # if elementsAlongFundusApexToCardia == e2: # first ring in eso - # e1IdxBni1 = e1 + 2 - # e1IdxBni3 = e1 + 1 - # elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3: - # # last ring in esophagus - # e1IdxBni1 = e1 + 1 - # e1IdxBni3 = e1 + 2 - # elif elementsAlongFundusApexToCardia < e2 < elementsAlongFundusApexToCardia + \ - # elementsAroundHalfEso - 3: # incomplete rings interior of eso - # e1IdxBni1 = e1 + 1 - # e1IdxBni3 = e1 + 1 - # else: - # e1IdxBni1 = e1 - # e1IdxBni3 = e1 - # bni1 = idxMat[e2][e3][e1IdxBni1] - # bni2 = idxMat[e2][e3][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] - # bni3 = idxMat[e2 + 1][e3][e1IdxBni3] - # bni4 = idxMat[e2 + 1][e3][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] - # bni5 = idxMat[e2][e3 + 1][e1IdxBni1] - # bni6 = idxMat[e2][e3 + 1][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] - # bni7 = idxMat[e2 + 1][e3 + 1][e1IdxBni3] - # bni8 = idxMat[e2 + 1][e3 + 1][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] - # nodeIdentifiers = [bni1, bni2, bni3, bni4, bni5, bni6, bni7, bni8] - # - # if e2 == elementsAlongFundusApexToCardia and e1 == elementsAroundHalfDuod - 2: - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3 and \ - # e1 == elementsAroundHalfDuod - 2: - # eft1 = eftfactory.createEftNoCrossDerivatives() - # remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # elif e2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 3 and \ - # e1 == elementsAroundHalfDuod - 1: - # scaleFactors = [-1.0] - # eft1 = eftfactory.createEftNoCrossDerivatives() - # setEftScaleFactorIds(eft1, [1], []) - # remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # elif e2 == elementsAlongFundusApexToCardia and e1 == elementsAroundHalfDuod - 1: - # eft1 = eftfactory.createEftNoCrossDerivatives() - # remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - # [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - # elementtemplateX.defineField(coordinates, -1, eft1) - # elementtemplate1 = elementtemplateX - # - # element = mesh.createElement(elementIdentifier, elementtemplate1) - # element.setNodesByIdentifier(eft1, nodeIdentifiers) - # if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: - # fundusMucosaElementIdentifiers.append(elementIdentifier) - # elementIdxAround.append(elementIdentifier) - # if scaleFactors: - # element.setScaleFactors(eft1, scaleFactors) - # elementIdentifier += 1 - # annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - # if annotationGroups: - # allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - # for annotationGroup in annotationGroups: - # meshGroup = annotationGroup.getMeshGroup(mesh) - # meshGroup.addElement(element) - # elementIdxThroughWall.append(elementIdxAround) - # elementIdxMat.append(elementIdxThroughWall) - # - # # Annulus - # # Assemble endPoints for annulus - # endPoints_x = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - # endPoints_d1 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - # endPoints_d2 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - # endNode_Id = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - # endDerivativesMap = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] - # endProportions = [] - # - # for n3 in range(elementsCountThroughWall + 1): - # n1 = 0 - # for nAround in range(elementsCountAroundEso): - # if nAround == 0: - # idx = idxMat[elementsAlongFundusApexToCardia][n3][elementsAroundHalfDuod] - # elif 0 < nAround < elementsAroundHalfEso: - # idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][elementsAroundHalfDuod - 1] - # n1 += 1 - # elif nAround == elementsAroundHalfEso: - # n1 -= 1 - # idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][elementsAroundHalfDuod] - # else: - # idx = idxMat[elementsAlongFundusApexToCardia + n1][n3][ - # elementsAroundHalfDuod + (1 if (n1 == elementsAroundHalfEso - 2 or n1 == 0) else 0)] - # n1 -= 1 - # - # endPoints_x[n3][nAround] = xList[idx - stomachStartNode] - # endPoints_d1[n3][nAround] = d1List[idx - stomachStartNode] - # endPoints_d2[n3][nAround] = d2List[idx - stomachStartNode] - # endNode_Id[n3][nAround] = idx - # - # if n3 == elementsCountThroughWall: # outer layer - # endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) - # endProportions.append(trackSurfaceStomach.getProportion(endPosition)) - # - # for n3 in range(elementsCountThroughWall + 1): - # for nAround in range(elementsCountAroundEso): - # if nAround == 0: - # endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, -1, 0), None) - # elif nAround == 1: - # endDerivativesMap[n3][nAround] = ((-1, 1, 0), (-1, -1, 0), None) - # elif 1 < nAround < elementsAroundHalfEso - 1: - # endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) - # elif nAround == elementsAroundHalfEso - 1: - # endDerivativesMap[n3][nAround] = ((1, 1, 0), (-1, 1, 0), None) - # elif nAround == elementsAroundHalfEso: - # endDerivativesMap[n3][nAround] = (None, None, None) - # elif nAround == elementsAroundHalfEso + 1: - # endDerivativesMap[n3][nAround] = ((1, -1, 0), (1, 1, 0), None) - # elif elementsAroundHalfEso + 1 < nAround < elementsCountAroundEso - 1: - # endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) - # elif nAround == elementsCountAroundEso - 1: - # endDerivativesMap[n3][nAround] = ((-1, -1, 0), (1, -1, 0), None) - # - # startProportions = [] - # for n in range(elementsCountAroundEso): - # startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) - # - # cardiaGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, - # get_stomach_term("cardia of stomach")) - # cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) - # if cardiaGroup not in allAnnotationGroups: - # allAnnotationGroups.append(cardiaGroup) - # - # lastDuodenumElementIdentifier = elementIdentifier - # - # stomachWallAnnotationGroups = [] - # if elementsCountThroughWall == 4: - # stomachWallAnnotationGroups = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], - # [longitudinalMuscleGroup]] - # - # # Remove mucosa layer from annulus - # if elementsCountThroughWall == 4 and limitingRidge: - # o1_x = o1_x[1:] - # o1_d1 = o1_d1[1:] - # o1_d2 = o1_d2[1:] - # o1_NodeId = o1_NodeId[1:] - # endPoints_x = endPoints_x[1:] - # endPoints_d1 = endPoints_d1[1:] - # endPoints_d2 = endPoints_d2[1:] - # endNode_Id = endNode_Id[1:] - # endDerivativesMap = endDerivativesMap[1:] - # stomachWallAnnotationGroups = stomachWallAnnotationGroups[1:] - # - # nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( - # nodes, mesh, nodeIdentifier, elementIdentifier, - # o1_x, o1_d1, o1_d2, None, o1_NodeId, None, - # endPoints_x, endPoints_d1, endPoints_d2, None, endNode_Id, endDerivativesMap, - # elementsCountRadial=elementsCountAcrossCardia, meshGroups=[stomachMeshGroup, cardiaMeshGroup], - # wallAnnotationGroups=stomachWallAnnotationGroups, - # tracksurface=trackSurfaceStomach, - # startProportions=startProportions, endProportions=endProportions, - # rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, - # coordinates=coordinates) - # + + annotationGroupsAlong = [] + for i in range(len(elementsAlongSections)): + elementsCount = elementsAlongSections[i] + for n in range(elementsCount): + annotationGroupsAlong.append(annotationGroupAlong[i]) + + # Create elements + fundusMucosaElementIdentifiers = [] + elementIdxMat = [] + n = 0 + for n2 in range(elementsAlongEsophagus): + elementIdxThroughWall = [] + for n3 in range(elementsThroughEsophagusWall): + elementIdxAround = [] + for n1 in range(elementsCountAroundEso): + n += 1 + elementIdxAround.append(n) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + + if useCubicHermiteThroughWall: + eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives) + else: + eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) + eftStandard = eftfactory.createEftBasic() + + elementtemplateStandard = mesh.createElementtemplate() + elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) + elementtemplateStandard.defineField(coordinates, -1, eftStandard) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + fundusElements = elementCountGroupList[0] + radiansPerElementAroundDuod = math.pi * 2.0 / elementsCountAroundDuod + + for e2 in range(len(xSampledAroundAlong) - 1): + elementIdxThroughWall = [] + if e2 == 0: # pole + for e3 in range(elementsCountThroughWall): + elementIdxAround = [] + for e1 in range(elementsCountAroundDuod): + va = e1 + vb = (e1 + 1) % elementsCountAroundDuod + eft1 = eftfactory.createEftShellPoleBottom(va*100, vb*100) + elementtemplateX.defineField(coordinates, -1, eft1) + element = mesh.createElement(elementIdentifier, elementtemplateX) + bni1 = e3 + stomachStartNode + bni2 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + e1 + bni3 = (elementsCountThroughWall + 1) + stomachStartNode + elementsCountAroundDuod * e3 + \ + (e1 + 1) % elementsCountAroundDuod + nodeIdentifiers = [bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAroundDuod, + bni3 + elementsCountAroundDuod] + + element.setNodesByIdentifier(eft1, nodeIdentifiers) + # set general linear map coefficients + radiansAround = e1 * radiansPerElementAroundDuod + radiansAroundNext = ((e1 + 1) % elementsCountAroundDuod) * radiansPerElementAroundDuod + scalefactors = [ + -1.0, + math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, + math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod, + math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAroundDuod, + math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAroundDuod + ] + element.setScaleFactors(eft1, scalefactors) + if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: + fundusMucosaElementIdentifiers.append(elementIdentifier) + elementIdxAround.append(elementIdentifier) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + + # elif 0 < e2 < bodyStartIdx - 1 or e2 > bodyStartIdx: + else: + e1Range = elementsCountAroundDuod - 2 if (e2 == bodyStartIdx - 1 or e2 == bodyStartIdx) \ + else len(xSampledAroundAlong[e2]) + for e3 in range(elementsCountThroughWall): + elementIdxAround = [] + for e1 in range(e1Range): + if e1 > elementsAroundHalfDuod - 2: + e1IdxBni1 = e1 + (2 if e2 == bodyStartIdx - 1 else 1 if e2 == bodyStartIdx else 0) + e1IdxBni3 = e1 + (1 if e2 == bodyStartIdx - 1 else 2 if e2 == bodyStartIdx else 0) + else: + e1IdxBni1 = e1 + e1IdxBni3 = e1 + # elif elementsAlongFundusApexToCardia < e2 < elementsAlongFundusApexToCardia + \ + # elementsAroundHalfEso - 3: # incomplete rings interior of eso + # print('3') + # e1IdxBni1 = e1 + 1 + # e1IdxBni3 = e1 + 1 + + eft1 = eftStandard + scaleFactors = [] + elementtemplate1 = elementtemplateStandard + bni111 = idxMat[e2][e3][e1IdxBni1] + bni211 = idxMat[e2][e3][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] + bni121 = idxMat[e2 + 1][e3][e1IdxBni3] + bni221 = idxMat[e2 + 1][e3][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] + bni112 = idxMat[e2][e3 + 1][e1IdxBni1] + bni212 = idxMat[e2][e3 + 1][(e1IdxBni1 + 1) % len(idxMat[e2][e3])] + bni122 = idxMat[e2 + 1][e3 + 1][e1IdxBni3] + bni222 = idxMat[e2 + 1][e3 + 1][(e1IdxBni3 + 1) % len(idxMat[e2 + 1][e3])] + nodeIdentifiers = [bni111, bni211, bni121, bni221, + bni112, bni212, bni122, bni222] + + if e2 == bodyStartIdx - 2: + if e1 == elementsAroundHalfDuod - 2: + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod - 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod + 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + if e2 == bodyStartIdx + 1: + if e1 == elementsAroundHalfDuod - 2: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod - 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod + 1: + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + element.setScaleFactors(eft1, scaleFactors) + if e2 < fundusElements and limitingRidge and elementsCountThroughWall > 1 and e3 == 0: + fundusMucosaElementIdentifiers.append(elementIdentifier) + elementIdxAround.append(elementIdentifier) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + + # Annulus + # Assemble endPoints for annulus + endPoints_x = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + endPoints_d1 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + endPoints_d2 = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + endNode_Id = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + endDerivativesMap = [[None] * elementsCountAroundEso for n3 in range(elementsCountThroughWall + 1)] + endProportions = [] + + for n3 in range(elementsCountThroughWall + 1): + n1 = 0 + for nAround in range(elementsCountAroundEso): + if nAround == 0: + idx = idxMat[bodyStartIdx - 1][n3][elementsAroundHalfDuod] + elif 0 < nAround < elementsAroundQuarterEso or nAround > elementsAroundQuarterEso + elementsAroundHalfEso: + idx = idxMat[bodyStartIdx - 1][n3][elementsAroundHalfDuod + (-1 if 0 < nAround < elementsAroundQuarterEso else 1)] + elif nAround == elementsAroundQuarterEso or nAround == elementsAroundQuarterEso + elementsAroundHalfEso: + idx = idxMat[bodyStartIdx][n3][elementsAroundHalfDuod - (1 if nAround == elementsAroundQuarterEso else 0)] + elif elementsAroundQuarterEso < nAround < elementsAroundHalfEso + 2: + idx = idxMat[bodyStartIdx + 1][n3][elementsAroundHalfDuod - 1 + n1] + n1 += 1 + + endPoints_x[n3][nAround] = xList[idx - stomachStartNode] + endPoints_d1[n3][nAround] = d1List[idx - stomachStartNode] + endPoints_d2[n3][nAround] = d2List[idx - stomachStartNode] + endNode_Id[n3][nAround] = idx + + if n3 == elementsCountThroughWall: # outer layer + endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) + endProportions.append(trackSurfaceStomach.getProportion(endPosition)) + + for n3 in range(elementsCountThroughWall + 1): + for nAround in range(elementsCountAroundEso): + if nAround == 0: + endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, -1, 0), None) + elif 1 <= nAround < elementsAroundHalfEso: + endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) + elif nAround == elementsAroundHalfEso: + endDerivativesMap[n3][nAround] = (None, None, None) + else: + endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) + + startProportions = [] + for n in range(elementsCountAroundEso): + startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) + + cardiaGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, + get_stomach_term("cardia of stomach")) + cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) + if cardiaGroup not in allAnnotationGroups: + allAnnotationGroups.append(cardiaGroup) + + lastDuodenumElementIdentifier = elementIdentifier + + stomachWallAnnotationGroups = [] + if elementsCountThroughWall == 4: + stomachWallAnnotationGroups = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], + [longitudinalMuscleGroup]] + + # Remove mucosa layer from annulus + if elementsCountThroughWall == 4 and limitingRidge: + o1_x = o1_x[1:] + o1_d1 = o1_d1[1:] + o1_d2 = o1_d2[1:] + o1_NodeId = o1_NodeId[1:] + endPoints_x = endPoints_x[1:] + endPoints_d1 = endPoints_d1[1:] + endPoints_d2 = endPoints_d2[1:] + endNode_Id = endNode_Id[1:] + endDerivativesMap = endDerivativesMap[1:] + stomachWallAnnotationGroups = stomachWallAnnotationGroups[1:] + + nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( + nodes, mesh, nodeIdentifier, elementIdentifier, + o1_x, o1_d1, o1_d2, None, o1_NodeId, None, + endPoints_x, endPoints_d1, endPoints_d2, None, endNode_Id, endDerivativesMap, + elementsCountRadial=elementsCountAcrossCardia, meshGroups=[stomachMeshGroup, cardiaMeshGroup], + wallAnnotationGroups=stomachWallAnnotationGroups, + tracksurface=trackSurfaceStomach, + startProportions=startProportions, endProportions=endProportions, + rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, + coordinates=coordinates) + # elementIdxThroughWall = [] # n = lastDuodenumElementIdentifier - 1 # for n3 in range(elementsCountThroughWall): @@ -2961,7 +3204,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # break # element = elementIter.next() # allAnnotationGroups.append(nearLCGroup) - # + # # Create split coordinate field # if splitCoordinates: # nodesOnSplitMargin = [] @@ -3110,6 +3353,15 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nextNodeIdentifier = nodeIdentifier nextElementIdentifier = elementIdentifier + # for n2 in range(len(cxGroup)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxGroup[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd2Group[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd1Group[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, cd3Group[n2]) + # nodeIdentifier += 1 + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier From ececfe2ac153923e130e2dce78af1cff004db726 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 9 Aug 2023 12:00:29 +1200 Subject: [PATCH 15/30] Remove use of elements between fundus apex to cardia and cardia to duodenum --- .../meshtypes/meshtype_3d_stomach1.py | 61 ++----------------- 1 file changed, 6 insertions(+), 55 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 7898bf7c..077e7af3 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -648,8 +648,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options = { 'Central path': copy.deepcopy(centralPathOption), 'Number of elements around duodenum': 16, - 'Number of elements between fundus apex and cardia': 3, - 'Number of elements between cardia and duodenum': 6, 'Target element unit length': 0.1, 'Number of elements through wall': 4, 'Wall thickness': 0.0525, @@ -665,13 +663,10 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Human 2' in parameterSetName: - options['Number of elements between cardia and duodenum'] = 8 options['Number of elements through wall'] = 1 # 4 later options['Wall thickness'] = 0.0525 * 101 elif 'Mouse 1' in parameterSetName: options['Number of elements around duodenum'] = 16 - options['Number of elements between fundus apex and cardia'] = 5 - options['Number of elements between cardia and duodenum'] = 5 options['Wall thickness'] = 0.05145 options['Mucosa relative thickness'] = 0.75 options['Submucosa relative thickness'] = 0.05 @@ -680,8 +675,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Limiting ridge'] = True elif 'Pig 1' in parameterSetName: options['Number of elements around duodenum'] = 16 - options['Number of elements between fundus apex and cardia'] = 3 - options['Number of elements between cardia and duodenum'] = 6 options['Wall thickness'] = 0.059 options['Mucosa relative thickness'] = 0.47 options['Submucosa relative thickness'] = 0.1 @@ -690,8 +683,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Limiting ridge'] = False elif 'Rat 1' in parameterSetName: options['Number of elements around duodenum'] = 16 - options['Number of elements between fundus apex and cardia'] = 5 - options['Number of elements between cardia and duodenum'] = 6 options['Wall thickness'] = 0.0215 options['Mucosa relative thickness'] = 0.65 options['Submucosa relative thickness'] = 0.12 @@ -700,8 +691,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Limiting ridge'] = True elif 'Material' in parameterSetName: options['Number of elements around duodenum'] = 16 - options['Number of elements between fundus apex and cardia'] = 5 - options['Number of elements between cardia and duodenum'] = 5 options['Wall thickness'] = 0.05 options['Mucosa relative thickness'] = 0.25 options['Submucosa relative thickness'] = 0.25 @@ -717,8 +706,6 @@ def getOrderedOptionNames(): return [ 'Central path', 'Number of elements around duodenum', - 'Number of elements between fundus apex and cardia', - 'Number of elements between cardia and duodenum', 'Target element unit length', 'Number of elements through wall', 'Wall thickness', @@ -784,10 +771,6 @@ def checkOptions(cls, options): options['Number of elements around duodenum'] = 12 if options['Number of elements around duodenum'] % 4 > 0: options['Number of elements around duodenum'] = options['Number of elements around duodenum'] // 4 * 4 - if options['Number of elements between fundus apex and cardia'] < 2: - options['Number of elements between fundus apex and cardia'] = 2 - if options['Number of elements between cardia and duodenum'] < 4: - options['Number of elements between cardia and duodenum'] = 4 if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 for key in [ @@ -834,8 +817,6 @@ def generateBaseMesh(cls, region, options): materialCentralPath = cls.centralPathDefaultScaffoldPackages['Material'] limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] - elementsAlongFundusApexToCardia = options['Number of elements between fundus apex and cardia'] - elementsAlongCardiaToDuod = options['Number of elements between cardia and duodenum'] elementsCountAroundEso = 8 elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) allAnnotationGroups = [] @@ -851,36 +832,9 @@ def generateBaseMesh(cls, region, options): # geometricCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path.exf") arcLengthOfGroupsAlong = geometricCentralPath.arcLengthOfGroupsAlong - # Pre-calculate element numbers in each group - elementsAlongFromBody = elementsAlongCardiaToDuod + elementsAroundQuarterEso - 1 - arcLengthOfGroupsAlongFromBody = arcLengthOfGroupsAlong[0] - arcLengthOfGroupsAlong[1] - estElementLengthFromBody = arcLengthOfGroupsAlongFromBody / elementsAlongFromBody - - modGroups = [0.0] - elementsAlongCPFundus = elementsAlongFundusApexToCardia + elementsAroundQuarterEso - 1 - elementCountGroupList = [elementsAlongCPFundus] - elementsTally = 0 - for i in range(2, len(stomachTermsAlong)): - numberOfElementsGroup = int(arcLengthOfGroupsAlong[i] // estElementLengthFromBody) - if numberOfElementsGroup < 1: - numberOfElementsGroup = 1 - - mod = arcLengthOfGroupsAlong[i] - estElementLengthFromBody * numberOfElementsGroup - modGroups.append(mod) - - elementsTally += numberOfElementsGroup - elementCountGroupList.append(numberOfElementsGroup) - - excessElements = elementsAlongFromBody - elementsTally - for i in range(excessElements): - maxIdx = max(range(len(modGroups)), key=modGroups.__getitem__) - elementCountGroupList[maxIdx] += 1 - modGroups[maxIdx] = arcLengthOfGroupsAlong[maxIdx] - estElementLengthFromBody * \ - elementCountGroupList[maxIdx] - allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier = \ createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, - allAnnotationGroups, elementCountGroupList, centralPath=geometricCentralPath, + allAnnotationGroups, centralPath=geometricCentralPath, options=options, nodeIdentifier=1, elementIdentifier=1, splitCoordinates=False, materialCoordinates=False) @@ -897,7 +851,7 @@ def generateBaseMesh(cls, region, options): # # allAnnotationGroupsMaterial, nextNodeIdentifier, nextElementIdentifier = \ # createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, - # allAnnotationGroupsMaterial, elementCountGroupList, + # allAnnotationGroupsMaterial, # centralPath=materialCentralPath, options=options, nodeIdentifier=1, # elementIdentifier=1, splitCoordinates=False, materialCoordinates=True) # @@ -1367,7 +1321,7 @@ def findCurvatureAlongLine(nx, nd, radialVectors): def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, - elementCountGroupList, centralPath, options, nodeIdentifier, elementIdentifier, + centralPath, options, nodeIdentifier, elementIdentifier, splitCoordinates, materialCoordinates=False): """ Generates a stomach scaffold in the region using a central path and parameter options. @@ -1376,7 +1330,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio :param coordinates: Coordinate field to define nodes and elements. :param stomachTermsAlong: Annotation terms along length of stomach. :param allAnnotationGroups: List of annotation groups. - :param elementCountGroupList: List contains number of elements in each annotation group along the stomach. :param centralPath: Central path through the axis of the stomach scaffold. :param options: Parameter options for stomach scaffold. :param nodeIdentifier: First node identifier. @@ -1386,8 +1339,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio :return allAnnotationGroups, elementsCountGroupList """ elementsCountAroundDuod = options['Number of elements around duodenum'] - # elementsAlongFundusApexToCardia = options['Number of elements between fundus apex and cardia'] - # elementsAlongCardiaToDuod = options['Number of elements between cardia and duodenum'] targetLength = options['Target element unit length'] elementsCountThroughWall = options['Number of elements through wall'] mucosaRelThickness = options['Mucosa relative thickness'] @@ -1518,7 +1469,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio targetLengthTS = 0.025 - for i in (list(range(1, len(elementCountGroupList))) + [0]): # start from body, go back to fundus + for i in (list(range(1, len(stomachTermsAlong) - 1)) + [0]): # start from body, go back to fundus cxGroup = centralPath.cxGroups[i + 1] cd1Group = centralPath.cd1Groups[i + 1] cd2Group = centralPath.cd2Groups[i + 1] @@ -1535,7 +1486,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, cd3Group[n2]) # nodeIdentifier += 1 - if materialCoordinates and i == len(elementCountGroupList) - 1: + if materialCoordinates and i == len(stomachTermsAlong) - 1: for n in range(len(cxGroup)): cd12Group[n] = zero cd13Group[n] = zero @@ -2892,7 +2843,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementtemplateX = mesh.createElementtemplate() elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) - fundusElements = elementCountGroupList[0] + fundusElements = elementsAlongSections[0] radiansPerElementAroundDuod = math.pi * 2.0 / elementsCountAroundDuod for e2 in range(len(xSampledAroundAlong) - 1): From c67e1d382e3ea844211e0151220ed4d91630f609 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 10 Aug 2023 15:08:25 +1200 Subject: [PATCH 16/30] Allow variable elements around esophagus --- .../meshtypes/meshtype_3d_stomach1.py | 932 ++++-------------- 1 file changed, 176 insertions(+), 756 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 077e7af3..276674d2 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -647,6 +647,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options = { 'Central path': copy.deepcopy(centralPathOption), + 'Number of elements around esophagus': 8, 'Number of elements around duodenum': 16, 'Target element unit length': 0.1, 'Number of elements through wall': 4, @@ -705,6 +706,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): def getOrderedOptionNames(): return [ 'Central path', + 'Number of elements around esophagus', 'Number of elements around duodenum', 'Target element unit length', 'Number of elements through wall', @@ -767,10 +769,14 @@ def checkOptions(cls, options): 'Gastro-esophageal junction'): options['Gastro-esophageal junction'] = cls.getOptionScaffoldPackage('Gastro-esophageal junction', MeshType_3d_ostium1) + if options['Number of elements around esophagus'] < 8: + options['Number of elements around esophagus'] = 8 if options['Number of elements around duodenum'] < 12: options['Number of elements around duodenum'] = 12 - if options['Number of elements around duodenum'] % 4 > 0: - options['Number of elements around duodenum'] = options['Number of elements around duodenum'] // 4 * 4 + for key in ['Number of elements around esophagus', + 'Number of elements around duodenum']: + if options[key] % 4 > 0: + options[key] = options[key] // 4 * 4 if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 for key in [ @@ -788,6 +794,7 @@ def updateSubScaffoldOptions(cls, options): """ ostiumOptions = options['Gastro-esophageal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() + ostiumSettings['Number of elements around ostium'] = options['Number of elements around esophagus'] wallThickness = options['Wall thickness'] / ostiumSettings['Unit scale'] ostiumSettings['Ostium wall thickness'] = wallThickness elementsCountThroughWall = options['Number of elements through wall'] @@ -817,7 +824,7 @@ def generateBaseMesh(cls, region, options): materialCentralPath = cls.centralPathDefaultScaffoldPackages['Material'] limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] - elementsCountAroundEso = 8 + elementsCountAroundEso = options['Number of elements around esophagus'] elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) allAnnotationGroups = [] @@ -1338,6 +1345,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio :param materialCoordinates: Create material coordinates if True. :return allAnnotationGroups, elementsCountGroupList """ + elementsCountAroundEso = options['Number of elements around esophagus'] elementsCountAroundDuod = options['Number of elements around duodenum'] targetLength = options['Target element unit length'] elementsCountThroughWall = options['Number of elements through wall'] @@ -1356,7 +1364,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio limitingRidge = options['Limiting ridge'] wallThickness = options['Wall thickness'] - elementsCountAroundEso = 8 elementsCountAcrossCardia = 1 cardiaDiameterFactor = 1.4 # scale to ostium diameter sf = (cardiaDiameterFactor - 1) * ostiumDiameter * 0.5 * GEJSettings['Unit scale'] @@ -1753,46 +1760,41 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementsAlongSections = [math.ceil(c / targetLength) for c in ratioArcLengthSections] totalElementsAlong = sum(elementsAlongSections) - print(elementsAlongSections) xSampledAlong = [[] for n1 in range(elementsCountAroundDuod)] d1SampledAlong = [[] for n1 in range(elementsCountAroundDuod)] d2SampledAlong = [[] for n1 in range(elementsCountAroundDuod)] d3SampledAlong = [[] for n1 in range(elementsCountAroundDuod)] + n1IdxAtBodyStartIdxPlusMinusOne = list(range(elementsAroundHalfDuod - 1, + elementsAroundHalfDuod + 2)) + annulusIdxAtBodyStartIdxMinusOne = list(range(1, -2, -1)) + annulusIdxAtBodyStartIdxPlusOne = list(range(elementsAroundHalfEso - 1, + elementsAroundHalfEso + 2)) + for i in range(len(sectionIdx) - 1): s = sectionIdx[i] sNext = sectionIdx[i + 1] + count = 0 for n1 in range(len(xEllipseAroundAll[s])): #for each pt around, we take the point on the sectionIdx as Pt A and the point on sectionIdx + 1 as Pt B, # do a tracksurface sampling to divide the elements into equal sized elements while keeping the start and # end derivatives direction at both pts elementsOut = elementsAlongSections[i] - if i == 1 and n1 == elementsAroundHalfDuod - 1: - aPosition = xAnnulusOuterPosition[elementsAroundHalfEso - 1] - elementsOut = elementsAlongSections[i] - 1 - elif i == 1 and n1 == elementsAroundHalfDuod: - aPosition = xAnnulusOuterPosition[elementsAroundHalfEso] - elementsOut = elementsAlongSections[i] - 1 - elif i == 1 and n1 == elementsAroundHalfDuod + 1: - aPosition = xAnnulusOuterPosition[elementsAroundHalfEso + 1] - elementsOut = elementsAlongSections[i] - 1 + if i == 1 and n1 in n1IdxAtBodyStartIdxPlusMinusOne: + aPosition = xAnnulusOuterPosition[annulusIdxAtBodyStartIdxPlusOne[count]] + count += 1 + elementsOut = elementsAlongSections[i] - (elementsAroundQuarterEso - 1) else: startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0/elementsCountAroundDuod * n1, 1.0/len(xEllipseAroundAll) * s) aPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[s][n1], startGuessPosition) aProportion = trackSurfaceStomach.getProportion(aPosition) - if i == 0 and n1 == elementsAroundHalfDuod - 1: - bPosition = xAnnulusOuterPosition[1] - elementsOut = elementsAlongSections[i] - 1 - elif i == 0 and n1 == elementsAroundHalfDuod: - bPosition = xAnnulusOuterPosition[0] - elementsOut = elementsAlongSections[i] - 1 - elif i == 0 and n1 == elementsAroundHalfDuod + 1: - bPosition = xAnnulusOuterPosition[-1] - elementsOut = elementsAlongSections[i] - 1 - + if i == 0 and n1 in n1IdxAtBodyStartIdxPlusMinusOne: + bPosition = xAnnulusOuterPosition[annulusIdxAtBodyStartIdxMinusOne[count]] + elementsOut = elementsAlongSections[i] - (elementsAroundQuarterEso - 1) + count += 1 else: startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * n1, 1.0 / len(xEllipseAroundAll) * sNext) @@ -1815,27 +1817,34 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # Deal with annulus if i == 0: if n1 == elementsAroundHalfDuod: - nx.append(zero) - nd1.append(zero) - nd2.append(zero) - nd3.append(zero) + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + nx.append(zero) + nd1.append(zero) + nd2.append(zero) + nd3.append(zero) elif n1 == elementsAroundHalfDuod - 1: - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundQuarterEso], math.pi) - d2 = d2AnnulusOuter[elementsAroundQuarterEso] - d2 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - nx.append(xAnnulusOuter[elementsAroundQuarterEso]) - nd1.append(d1AnnulusOuter[elementsAroundQuarterEso]) - nd2.append(d2) - nd3.append(d3Annulus[elementsAroundQuarterEso]) + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = m + 2 + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[annulusIdx], math.pi) + d2 = d2AnnulusOuter[annulusIdx] + d2 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] + for j in range(3)] + nx.append(xAnnulusOuter[annulusIdx]) + nd1.append(d1AnnulusOuter[annulusIdx]) + nd2.append(d2) + nd3.append(d3Annulus[annulusIdx]) elif n1 == elementsAroundHalfDuod + 1: - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[-elementsAroundQuarterEso], math.pi) - d1 = d1AnnulusOuter[-elementsAroundQuarterEso] - d1 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] - nx.append(xAnnulusOuter[-elementsAroundQuarterEso]) - nd1.append(d1) - nd2.append(d2AnnulusOuter[-elementsAroundQuarterEso]) - nd3.append(d3Annulus[-elementsAroundQuarterEso]) + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = -2 - m + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[annulusIdx], math.pi) + d1 = d1AnnulusOuter[annulusIdx] + d1 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] + for j in range(3)] + nx.append(xAnnulusOuter[annulusIdx]) + nd1.append(d1) + nd2.append(d2AnnulusOuter[annulusIdx]) + nd3.append(d3Annulus[annulusIdx]) if i == 1 and elementsAroundHalfDuod - 1 <= n1 <= elementsAroundHalfDuod + 1: xSampledAlong[n1] += nx @@ -1881,11 +1890,13 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d3SampledAroundAlong.append(d3SampledAround) bodyStartIdx = elementsAlongSections[0] + annulusFundusOpenRingIdx = bodyStartIdx - (elementsAroundQuarterEso - 2) + annulusBodyOpenRingIdx = bodyStartIdx + (elementsAroundQuarterEso - 2) # Smooth d1 around d1SmoothedAroundAlong = [d1EllipseAroundAll[0]] for n2 in range(1, len(xSampledAroundAlong)): - if n2 == bodyStartIdx: + if annulusFundusOpenRingIdx <= n2 <= annulusBodyOpenRingIdx: d1SmoothedLeft = \ interp.smoothCubicHermiteDerivativesLine(xSampledAroundAlong[n2][0:elementsAroundHalfDuod], d1SampledAroundAlong[n2][0:elementsAroundHalfDuod]) @@ -1902,22 +1913,12 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d1SampledAroundAlong = d1SmoothedAroundAlong - # for n2 in range(len(xSampledAroundAlong)): - # for n1 in range(len(xSampledAroundAlong[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3SampledAroundAlong[n2][n1]) - # nodeIdentifier += 1 - # Smooth d2 along for n1 in range(elementsCountAroundDuod): nx = [] nd2 = [] if n1 == elementsAroundHalfDuod: - for n2 in range(bodyStartIdx): + for n2 in range(annulusFundusOpenRingIdx): nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2SmoothedAlongGC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) @@ -1927,7 +1928,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx = [] nd2 = [] - for n2 in range(bodyStartIdx + 1, len(xSampledAroundAlong)): + for n2 in range(annulusBodyOpenRingIdx + 1, len(xSampledAroundAlong)): nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2SmoothedAlongLC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) @@ -1935,7 +1936,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio 0.5*(vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso]) + (vector.magnitude(d2SmoothedAlongLC[0])))) - d2Smoothed = d2SmoothedAlongGC + [[0.0, 1.0, 0.0]] + d2SmoothedAlongLC + d2Smoothed = d2SmoothedAlongGC + \ + [[0.0, 1.0, 0.0] for n in range(2 * (elementsAroundQuarterEso - 2) + 1)] + \ + d2SmoothedAlongLC else: for n2 in range(len(xSampledAroundAlong)): @@ -1944,59 +1947,76 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d2Smoothed = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) if n1 == elementsAroundHalfDuod - 1: - d2Smoothed[bodyStartIdx - 1] = \ - vector.setMagnitude(d1AnnulusOuter[1], - 0.5 * (vector.magnitude(d2Smoothed[bodyStartIdx - 1]) + - vector.magnitude(d1AnnulusOuter[1]))) + d2Smoothed[annulusFundusOpenRingIdx - 1] = \ + vector.setMagnitude( + d1AnnulusOuter[1], + 0.5 * (vector.magnitude(d2Smoothed[annulusFundusOpenRingIdx - 1]) + + vector.magnitude(d1AnnulusOuter[1]))) d2Smoothed[bodyStartIdx] = \ vector.setMagnitude(d2Smoothed[bodyStartIdx], vector.magnitude(d1AnnulusOuter[elementsAroundQuarterEso])) - d2Smoothed[bodyStartIdx + 1] = \ - vector.setMagnitude(d1AnnulusOuter[elementsAroundQuarterEso + 1], - 0.5 * (vector.magnitude(d2Smoothed[bodyStartIdx + 1]) + - vector.magnitude(d2AnnulusOuter[elementsAroundQuarterEso + 1]))) + d2Smoothed[annulusBodyOpenRingIdx + 1] = \ + vector.setMagnitude( + d1AnnulusOuter[elementsAroundHalfEso - 1], + 0.5 * (vector.magnitude(d2Smoothed[annulusBodyOpenRingIdx + 1]) + + vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso - 1]))) if n1 == elementsAroundHalfDuod + 1: rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[-1], math.pi) d1 = d1AnnulusOuter[-1] d2 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] - d2Smoothed[bodyStartIdx - 1] = \ - vector.setMagnitude(d2, 0.5*(vector.magnitude(d2Smoothed[bodyStartIdx - 1]) + - vector.magnitude(d1AnnulusOuter[-1]))) + d2Smoothed[annulusFundusOpenRingIdx - 1] = \ + vector.setMagnitude( + d2, 0.5*(vector.magnitude(d2Smoothed[annulusFundusOpenRingIdx - 1]) + + vector.magnitude(d1AnnulusOuter[-1]))) + d2Smoothed[bodyStartIdx] = \ vector.setMagnitude(d2Smoothed[bodyStartIdx], vector.magnitude(d1AnnulusOuter[-elementsAroundQuarterEso])) - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[-elementsAroundQuarterEso - 1], math.pi) - d1 = d1AnnulusOuter[-elementsAroundQuarterEso - 1] + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundHalfEso + 1], math.pi) + d1 = d1AnnulusOuter[elementsAroundHalfEso + 1] d2 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] - d2Smoothed[bodyStartIdx + 1] = \ - vector.setMagnitude(d2, 0.5 * (vector.magnitude(d2Smoothed[bodyStartIdx + 1]) + - vector.magnitude(d2AnnulusOuter[-elementsAroundQuarterEso - 1]))) + d2Smoothed[annulusBodyOpenRingIdx + 1] = \ + vector.setMagnitude(d2, 0.5 * (vector.magnitude(d2Smoothed[annulusBodyOpenRingIdx + 1]) + + vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso + 1]))) for n2 in range(len(d2Smoothed)): d2SampledAroundAlong[n2][n1] = d2Smoothed[n2] + # for n2 in range(len(xSampledAroundAlong)): + # for n1 in range(len(xSampledAroundAlong[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3SampledAroundAlong[n2][n1]) + # nodeIdentifier += 1 + # calculate d3 for n2 in range(len(xSampledAroundAlong)): for n1 in range(len(xSampledAroundAlong[n2])): - d3SampledAroundAlong[n2][n1] = vector.normalise(vector.crossproduct3(vector.normalise(d1SampledAroundAlong[n2][n1]), - vector.normalise(d2SampledAroundAlong[n2][n1]))) + d3SampledAroundAlong[n2][n1] = vector.normalise(vector.crossproduct3( + vector.normalise(d1SampledAroundAlong[n2][n1]), vector.normalise(d2SampledAroundAlong[n2][n1]))) # Calculate curvature around - d1CurvatureAroundAlong = [[0.0 for n in range(elementsCountAroundDuod)]] # check later + d1CurvatureAroundAlong = [[0.0 for n in range(elementsCountAroundDuod)]] for n2 in range(1, len(xSampledAroundAlong)): - if n2 == bodyStartIdx: + if annulusFundusOpenRingIdx <= n2 <= annulusBodyOpenRingIdx: d1CurvatureLeft = findCurvatureAlongLine(xSampledAroundAlong[n2][0:elementsAroundHalfDuod], - d1SampledAroundAlong[n2][0:elementsAroundHalfDuod], - d3SampledAroundAlong[n2][0:elementsAroundHalfDuod]) + d1SampledAroundAlong[n2][0:elementsAroundHalfDuod], + d3SampledAroundAlong[n2][0:elementsAroundHalfDuod]) d1CurvatureRight = \ - findCurvatureAlongLine(xSampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [xSampledAroundAlong[n2][0]], - d1SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [d1SampledAroundAlong[n2][0]], - d3SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [d3SampledAroundAlong[n2][0]]) + findCurvatureAlongLine( + xSampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [xSampledAroundAlong[n2][0]], + d1SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [d1SampledAroundAlong[n2][0]], + d3SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [d3SampledAroundAlong[n2][0]]) + d1Curvature = d1CurvatureLeft + [0.0] + d1CurvatureRight[:-1] else: - d1Curvature = findCurvatureAroundLoop(xSampledAroundAlong[n2], d1SampledAroundAlong[n2], d3SampledAroundAlong[n2]) + d1Curvature = findCurvatureAroundLoop(xSampledAroundAlong[n2], d1SampledAroundAlong[n2], + d3SampledAroundAlong[n2]) d1CurvatureAroundAlong.append(d1Curvature) # Replace derivatives around annulus @@ -2004,37 +2024,41 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[1], math.pi) d2 = d2AnnulusOuter[1] d1 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod - 1] = \ - vector.setMagnitude(d1, 0.5 * - (vector.magnitude(d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod - 1]) + - vector.magnitude(d2AnnulusOuter[1]))) - - d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod] = \ - vector.setMagnitude(d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod], + d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod - 1] = \ + vector.setMagnitude( + d1, + 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod - 1]) + + vector.magnitude(d2AnnulusOuter[1]))) + + d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod] = \ + vector.setMagnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod], vector.magnitude(d1AnnulusOuter[0])) - d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod + 1] = \ - vector.setMagnitude(d2AnnulusOuter[-1], 0.5 * - (vector.magnitude(d1SampledAroundAlong[bodyStartIdx - 1][elementsAroundHalfDuod + 1]) + - vector.magnitude(d2AnnulusOuter[-1]))) + d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod + 1] = \ + vector.setMagnitude( + d2AnnulusOuter[-1], + 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod + 1]) + + vector.magnitude(d2AnnulusOuter[-1]))) # bodyStartIdx + 1 - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundQuarterEso + 1], math.pi) - d2 = d2AnnulusOuter[elementsAroundQuarterEso + 1] + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundHalfEso - 1], math.pi) + d2 = d2AnnulusOuter[elementsAroundHalfEso - 1] d1 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod - 1] = \ - vector.setMagnitude(d1, 0.5 * - (vector.magnitude(d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod - 1]) + - vector.magnitude(d2AnnulusOuter[elementsAroundQuarterEso + 1]))) - - d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod] = \ - vector.setMagnitude(d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod], + d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod - 1] = \ + vector.setMagnitude( + d1, + 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod - 1]) + + vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso - 1]))) + + d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod] = \ + vector.setMagnitude(d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod], vector.magnitude(d1AnnulusOuter[elementsAroundHalfEso])) - d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod + 1] = \ - vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso + 1], 0.5 * - (vector.magnitude(d1SampledAroundAlong[bodyStartIdx + 1][elementsAroundHalfDuod + 1]) + - vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso + 1]))) + d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod + 1] = \ + vector.setMagnitude( + d2AnnulusOuter[elementsAroundHalfEso + 1], + 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod + 1]) + + vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso + 1]))) # Calculate curvature along d2CurvatureAroundAlong = [[[] for n1 in range(len(xSampledAroundAlong[n2]))] @@ -2045,7 +2069,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nd2 = [] nd3 = [] if n1 == elementsAroundHalfDuod: - for n2 in range(bodyStartIdx): + for n2 in range(annulusFundusOpenRingIdx): nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) nd3.append(d3SampledAroundAlong[n2][n1]) @@ -2054,14 +2078,14 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx = [] nd2 = [] nd3 = [] - # print(d2SampledAroundAlong[bodyStartIdx + 1][n1]) - for n2 in range(bodyStartIdx + 1, len(xSampledAroundAlong)): + for n2 in range(annulusBodyOpenRingIdx + 1, len(xSampledAroundAlong)): nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) nd3.append(d3SampledAroundAlong[n2][n1]) - # print(n2, n1) d2CurvatureAlongLC = findCurvatureAlongLine(nx, nd2, nd3) - d2CurvatureAlong = d2CurvatureAlongGC + [0.0] + d2CurvatureAlongLC + d2CurvatureAlong = d2CurvatureAlongGC + \ + [0.0 for n in range(2 * (elementsAroundQuarterEso - 2) + 1)] + \ + d2CurvatureAlongLC else: for n2 in range(len(xSampledAroundAlong)): @@ -2073,10 +2097,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n2 in range(len(d2CurvatureAlong)): d2CurvatureAroundAlong[n2][n1] = d2CurvatureAlong[n2] - del xSampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] - del d1SampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] - del d2SampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] - del d3SampledAroundAlong[bodyStartIdx][elementsAroundHalfDuod] + for i in range(annulusFundusOpenRingIdx, annulusBodyOpenRingIdx + 1): + del xSampledAroundAlong[i][elementsAroundHalfDuod] + del d1SampledAroundAlong[i][elementsAroundHalfDuod] + del d2SampledAroundAlong[i][elementsAroundHalfDuod] + del d3SampledAroundAlong[i][elementsAroundHalfDuod] # Remove multiple nodes at apex del xSampledAroundAlong[0][1:], d1SampledAroundAlong[0][1:], d2SampledAroundAlong[0][1:], \ @@ -2189,627 +2214,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nodeIdentifier += 1 - # # Adjust annulus derivatives - # # Make d2 on second half of eso point towards duodenum - # for n1 in range(elementsAroundHalfEso - 1): - # idx = n1 + elementsAroundHalfEso + 1 - # rotAxis = d3Annulus[idx] - # rotAngle = math.pi - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - # d2 = d2AnnulusOuter[idx] - # d2AnnulusOuter[idx] = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + - # rotFrame[j][2] * d2[2] for j in range(3)] - # - # # Make d1 on first half of eso point towards esophagus - # for n1 in range(1, elementsAroundHalfEso): - # rotAxis = d3Annulus[n1] - # rotAngle = math.pi - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - # d1 = d1AnnulusOuter[n1] - # d1AnnulusOuter[n1] = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + - # rotFrame[j][2] * d1[2] for j in range(3)] - # - # # Flip d1 and d2 on xAnnulusOuter[0] - # d1 = d1AnnulusOuter[0] # original d1 - # rotAxis = d3Annulus[0] - # rotAngle = math.pi - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - # d1Rot = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] - # - # d2 = d2AnnulusOuter[0] # original d2 - # rotAngle = math.pi - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - # d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - # - # d2AnnulusOuter[0] = d1Rot # d2 is now d1 - # d1AnnulusOuter[0] = d2Rot # d1 is now d2 - curvature = annulusD2Curvature[0] - # - # # Flip d1 and d2 on xAnnulusOuter[halfEso] - # d1 = d1AnnulusOuter[elementsAroundHalfEso] # original d1 - # d2 = d2AnnulusOuter[elementsAroundHalfEso] # original d2 - # d2AnnulusOuter[elementsAroundHalfEso] = d1 # d2 is now d1 - # d1AnnulusOuter[elementsAroundHalfEso] = d2 # d1 is now d2 - curvature = annulusD2Curvature[halfEso] - # - # # x along GC and LC row - needs to be in 2 parts - # # GC - # xAlongGCHalfDuod = [] - # endGCEsoP2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] - # - # for n2 in range(len(xEllipseAroundAll)): - # xPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) - # p2 = trackSurfaceStomach.getProportion(xPosition) - # if p2[1] < endGCEsoP2: - # # xAlongGCHalfDuod.append(xAroundAllTransformed[n2][elementsAroundHalfDuod if n2 else 0]) - # xAlongGCHalfDuod.append(xEllipseAroundAll[n2][elementsAroundHalfDuod if n2 else 0]) - # else: - # break - # - # xAlongGCHalfDuod.append(xAnnulusOuter[0]) - # - # rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * elementsAroundHalfDuod - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) - # d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + rotFrame[j][2] * d2Apex[2] for j in range(3)] - # - # d2AlongGCHalfDuod = [d2ApexRot] - # for n2 in range(1, len(xAlongGCHalfDuod) - 1): - # d = findDerivativeBetweenPoints(xAlongGCHalfDuod[n2], xAlongGCHalfDuod[n2 + 1]) - # d2AlongGCHalfDuod.append(d) - # d2AlongGCHalfDuod.append(d2AnnulusOuter[0]) - # - # xSampledAlongGCHalfDuod, d2SampledAlongGCHalfDuod = \ - # interp.sampleCubicHermiteCurvesSmooth(xAlongGCHalfDuod + [o1_x[-1][0]], d2AlongGCHalfDuod + [d2AnnulusOuter[0]], - # elementsAlongFundusApexToCardia + 1, - # derivativeMagnitudeEnd=vector.magnitude(d2AnnulusOuter[0]))[0:2] - # - # d2SampledAlongGCHalfDuod = \ - # interp.smoothCubicHermiteDerivativesLine(xSampledAlongGCHalfDuod, d2SampledAlongGCHalfDuod, - # fixEndDerivative=True) - # - # xAlongGCHalfDuod = xSampledAlongGCHalfDuod[:-1] - # d2AlongGCHalfDuod = d2SampledAlongGCHalfDuod[:-1] - # for n2 in range(len(xAlongGCHalfDuod)): - # xEllipseAroundAll[n2][elementsAroundHalfDuod] = xAlongGCHalfDuod[n2] - # - # # LC part - # elementsInBody = elementCountGroupList[1] - # xAnnulusOuterHalfEsoPosition = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[elementsAroundHalfEso]) - # startLCAnnulus = trackSurfaceStomach.getProportion(xAnnulusOuterHalfEsoPosition) - # - # xAlongLCHalfDuod = [xAnnulusOuter[elementsAroundHalfEso]] - # n2IdxEndBody = elementCountGroupList[0] + elementCountGroupList[1] - # - # if elementsInBody - elementsAroundQuarterEso + 1 > 1: - # xPositionEndBody = \ - # trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2IdxEndBody][elementsAroundHalfDuod]) - # xProportionEndBody = trackSurfaceStomach.getProportion(xPositionEndBody) - # - # nx, nd1, nd2, nd3, proportions = \ - # trackSurfaceStomach.createHermiteCurvePoints( - # startLCAnnulus[0], startLCAnnulus[1], xProportionEndBody[0], xProportionEndBody[1], - # elementsInBody - elementsAroundQuarterEso + 1, derivativeStart=d2AnnulusOuter[elementsAroundHalfEso]) - # - # nxNew, nd1New = \ - # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - # nx, nd1, nd2, nd3, proportions, - # derivativeMagnitudeStart=vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso]))[0:2] - # xAlongLCHalfDuod += nxNew[1:-1] - # - # for n2 in range(sum(elementCountGroupList) - sum(elementCountGroupList[:2]) + 1): - # xAlongLCHalfDuod.append(xEllipseAroundAll[n2IdxEndBody + n2][elementsAroundHalfDuod]) - # - # d2AlongLCHalfDuod = [d2AnnulusOuter[elementsAroundHalfEso]] - # for n2 in range(1, len(xAlongLCHalfDuod)): - # d = findDerivativeBetweenPoints(xAlongLCHalfDuod[n2 - 1], xAlongLCHalfDuod[n2]) - # d2AlongLCHalfDuod.append(d) - # d2AlongLCHalfDuod[-1] = cd1Sections[-1][-1] - # - # if materialCoordinates: - # # Break point along at body-antrum and pylorus-duod intersection and smooth separately to keep derivative at - # # body end - # d2AlongBody = \ - # interp.smoothCubicHermiteDerivativesLine( - # xAlongLCHalfDuod[:elementsInBody - elementsAroundQuarterEso + 2], - # d2AlongLCHalfDuod[:elementsInBody - elementsAroundQuarterEso + 2], - # fixStartDirection=True, fixEndDirection=True) - # - # for n in range(elementCountGroupList[-1] + 1): - # d2AlongLCHalfDuod[-(n + 1)] = cd1Sections[-1][-1] - # - # d2AlongBodyToPylorus = \ - # interp.smoothCubicHermiteDerivativesLine( - # xAlongLCHalfDuod[elementsInBody - elementsAroundQuarterEso + 1:-n], - # d2AlongLCHalfDuod[elementsInBody - elementsAroundQuarterEso + 1:-n], - # fixStartDirection=True, fixEndDirection=True) - # d2AlongDuod = \ - # interp.smoothCubicHermiteDerivativesLine( - # xAlongLCHalfDuod[-(n + 1):], d2AlongLCHalfDuod[-(n + 1):], fixStartDirection=True, fixEndDirection=True) - # d2AlongLCHalfDuod = d2AlongBody[:-1] + d2AlongBodyToPylorus[:-1] + d2AlongDuod - # else: - # d2AlongLCHalfDuod = \ - # interp.smoothCubicHermiteDerivativesLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, - # fixStartDerivative=True, fixEndDirection=True) - # - # for n2 in range(len(xAlongLCHalfDuod)): - # xEllipseAroundAll[n2 + elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2][elementsAroundHalfDuod] = \ - # xAlongLCHalfDuod[n2] - # - # xAlongCurvatures = xAlongGCHalfDuod + xAlongLCHalfDuod - # d2AlongCurvatures = d2AlongGCHalfDuod + d2AlongLCHalfDuod - # - # esoCount = 1 - # # Find arclengths to points on quarter, GC and 3-quarter fundus as trackSurface search for nearest position doesnt - # # work well near apex - # proportionsAlongQuarterMidThree = [] - # count = 0 - # for n1 in [elementsAroundQuarterDuod, elementsAroundHalfDuod, elementsAroundQuarterDuod + elementsAroundHalfDuod]: - # xAlong = [] - # arcLength = 0.0 - # proportions = [] - # for n2 in range(elementsAlongFundusApexToCardia): - # xAlong.append(xEllipseAroundAll[n2][n1]) - # - # rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * n1 - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) - # d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + - # rotFrame[j][2] * d2Apex[2] for j in range(3)] - # d2Along = [d2ApexRot] - # - # for n2 in range(len(xAlong) - 1): - # d2Along.append(findDerivativeBetweenPoints(xAlong[n2], xAlong[n2 + 1])) - # - # for n2 in range(len(xAlong) - 1): - # arcLength += interp.getCubicHermiteArcLength(xAlong[n2], d2Along[n2], xAlong[n2 + 1], d2Along[n2 + 1]) - # proportion = arcLength / arcLengthsAlongTS[count] - # proportions.append(proportion) - # proportionsAlongQuarterMidThree.append(proportions) - # count += 1 - # - # for n2 in range(1, len(xEllipseAroundAll) - 1): - # startAnnulus = n2 == elementsAlongFundusApexToCardia - # endAnnulus = n2 == elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 - # interiorAnnulus = \ - # elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 - # - # if startAnnulus or interiorAnnulus or endAnnulus: - # xEllipseAroundAll[n2][elementsAroundHalfDuod - 1] = xAnnulusOuter[esoCount] - # d1EllipseAroundAll[n2][elementsAroundHalfDuod - 1] = d1AnnulusOuter[esoCount] - # xEllipseAroundAll[n2][elementsAroundHalfDuod + 1] = xAnnulusOuter[-esoCount] - # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1] = d1AnnulusOuter[-esoCount] - # - # if startAnnulus or endAnnulus: - # xEllipseAroundAll[n2][elementsAroundHalfDuod] = \ - # xAnnulusOuter[0 if startAnnulus else elementsAroundHalfEso] - # - # xPositionA = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundQuarterDuod]) - # xProportionA = trackSurfaceStomach.getProportion(xPositionA) - # xPositionB = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[esoCount]) - # xProportionB = trackSurfaceStomach.getProportion(xPositionB) - # - # nx, nd1, nd2, nd3, proportions = \ - # trackSurfaceStomach.createHermiteCurvePoints( - # xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], elementsAroundQuarterDuod - 1, - # derivativeStart=d1EllipseAroundAll[n2][elementsAroundQuarterDuod]) - # - # nx, nd1 = \ - # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - # nx, nd1, nd2, nd3, proportions, - # derivativeMagnitudeStart=vector.magnitude(d1EllipseAroundAll[n2][elementsAroundQuarterDuod]))[0:2] - # - # xEllipseAroundAll[n2][elementsAroundQuarterDuod + 1:elementsAroundHalfDuod - 1] = nx[1:-1] - # d1EllipseAroundAll[n2][elementsAroundQuarterDuod + 1:elementsAroundHalfDuod - 1] = nd1[1:-1] - # - # # Smooth two halves separately and join together again with d1 at xOuterAnnulus[0] and - # # xOuterAnnulus[elementsAroundHalfEso] - # d1SmoothedFirstHalf = \ - # interp.smoothCubicHermiteDerivativesLine(xEllipseAroundAll[n2][:elementsAroundHalfDuod], - # d1EllipseAroundAll[n2][:elementsAroundHalfDuod], - # fixEndDerivative=True if interiorAnnulus else None) - # - # if interiorAnnulus: - # d1EllipseAroundAll[n2][:elementsAroundHalfDuod] = d1SmoothedFirstHalf - # else: - # d1SmoothedFirstHalf[-1] = vector.setMagnitude(d1SmoothedFirstHalf[-1], - # 0.5 * (vector.magnitude(d1SmoothedFirstHalf[-2]) + - # vector.magnitude(d1AnnulusOuter[1]))) - # - # xPositionA = trackSurfaceStomach.findNearestPosition(xAnnulusOuter[-esoCount]) - # xProportionA = trackSurfaceStomach.getProportion(xPositionA) - # xPositionB = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[n2][elementsAroundHalfDuod + - # elementsAroundQuarterDuod]) - # xProportionB = trackSurfaceStomach.getProportion(xPositionB) - # - # nx, nd1, nd2, nd3, proportions = \ - # trackSurfaceStomach.createHermiteCurvePoints( - # xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - # elementsAroundQuarterDuod - 1, - # derivativeEnd=d1EllipseAroundAll[n2][elementsAroundHalfDuod + elementsAroundQuarterDuod]) - # - # nx, nd1 = \ - # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - # nx, nd1, nd2, nd3, proportions, - # derivativeMagnitudeEnd=vector.magnitude(d1EllipseAroundAll[n2][elementsAroundHalfDuod + - # elementsAroundQuarterDuod]))[0:2] - # - # xEllipseAroundAll[n2][elementsAroundHalfDuod + 2:elementsAroundHalfDuod + elementsAroundQuarterDuod] = \ - # nx[1:-1] - # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 2:elementsAroundHalfDuod + elementsAroundQuarterDuod] = \ - # nd1[1:-1] - # - # esoCount += 1 - # if startAnnulus or endAnnulus: - # d1SmoothedSecondHalf = \ - # interp.smoothCubicHermiteDerivativesLine( - # xEllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + [xEllipseAroundAll[n2][0]], - # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + [d1SmoothedFirstHalf[0]], - # fixEndDerivative=True) - # d1SmoothedSecondHalf[0] = vector.setMagnitude(d1SmoothedSecondHalf[0], - # 0.5 * (vector.magnitude(d1SmoothedFirstHalf[1]) + - # vector.magnitude(d1AnnulusOuter[1]))) - # - # d1EllipseAroundAll[n2] = d1SmoothedFirstHalf + \ - # [d1AnnulusOuter[0 if startAnnulus else elementsAroundHalfEso]] + \ - # d1SmoothedSecondHalf[:-1] - # else: - # d1Smoothed = \ - # interp.smoothCubicHermiteDerivativesLine(xEllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + - # [xEllipseAroundAll[n2][0]], - # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] + - # [d1EllipseAroundAll[n2][0]], - # fixStartDerivative=True, fixEndDerivative=True) - # - # d1EllipseAroundAll[n2][elementsAroundHalfDuod + 1:] = d1Smoothed[:-1] - # - # del xEllipseAroundAll[n2][elementsAroundHalfDuod] - # del d1EllipseAroundAll[n2][elementsAroundHalfDuod] - # del d2EllipseAroundAll[n2][elementsAroundHalfDuod] - # - # elif 0 < n2 < elementsAlongFundusApexToCardia or \ - # elementsAlongFundusApexToCardia + elementsAroundHalfEso - 1 <= n2 < elementsAlongFundusApexToCardia + \ - # elementsAroundHalfEso + elementsInBody - elementsAroundQuarterEso - 1: - # if 0 < n2 < elementsAlongFundusApexToCardia: - # xToSample = [xEllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ - # [xAlongGCHalfDuod[n2]] + \ - # [xEllipseAroundAll[n2][elementsAroundQuarterDuod + elementsAroundHalfDuod]] - # xToSampleProportion0 = [0.25, 0.5, 0.75] - # xToSampleProportion1 = [proportionsAlongQuarterMidThree[0][n2 - 1], - # proportionsAlongQuarterMidThree[1][n2 - 1], - # proportionsAlongQuarterMidThree[2][n2 - 1]] - # else: - # n2Idx = n2 - (elementsAlongFundusApexToCardia + elementsAroundHalfEso - 1) + 1 - # xToSample = [xEllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ - # [xAlongLCHalfDuod[n2Idx]] + \ - # [xEllipseAroundAll[n2][elementsAroundQuarterDuod + elementsAroundHalfDuod]] - # - # d1ToSample = [d1EllipseAroundAll[n2][elementsAroundQuarterDuod]] + \ - # [d1EllipseAroundAll[n2][elementsAroundHalfDuod]] + \ - # [d1EllipseAroundAll[n2][elementsAroundHalfDuod + elementsAroundQuarterDuod]] - # - # if 0 < n2 < elementsAlongFundusApexToCardia: - # xProportionA = [xToSampleProportion0[0], xToSampleProportion1[0]] - # xProportionB = [xToSampleProportion0[1], xToSampleProportion1[1]] - # xProportionC = [xToSampleProportion0[2], xToSampleProportion1[2]] - # - # else: - # xPositionA = trackSurfaceStomach.findNearestPosition(xToSample[0]) - # xProportionA = trackSurfaceStomach.getProportion(xPositionA) - # xPositionB = trackSurfaceStomach.findNearestPosition(xToSample[1]) - # xProportionB = trackSurfaceStomach.getProportion(xPositionB) - # xPositionC = trackSurfaceStomach.findNearestPosition(xToSample[2]) - # xProportionC = trackSurfaceStomach.getProportion(xPositionC) - # - # nx, nd1, nd2, nd3, proportions = \ - # trackSurfaceStomach.createHermiteCurvePoints( - # xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - # elementsAroundQuarterDuod, derivativeStart=d1ToSample[0], derivativeEnd=d1ToSample[1]) - # if n2 == 1: - # sampledProportionsOneLeft = proportions - # nxLeft, nd1Left = \ - # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - # nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=vector.magnitude(d1ToSample[0]))[0:2] - # - # nx, nd1, nd2, nd3, proportions = \ - # trackSurfaceStomach.createHermiteCurvePoints( - # xProportionB[0], xProportionB[1], xProportionC[0], xProportionC[1], elementsAroundQuarterDuod, - # derivativeStart=d1ToSample[1], derivativeEnd=d1ToSample[2]) - # if n2 == 1: - # sampledProportionsOneRight = proportions - # nxRight, nd1Right = \ - # trackSurfaceStomach.resampleHermiteCurvePointsSmooth( - # nx, nd1, nd2, nd3, proportions, derivativeMagnitudeEnd=vector.magnitude(d1ToSample[2]))[0:2] - # - # xNew = nxLeft[1:] + nxRight[1:-1] - # d1New = nd1Left[1:] + nd1Right[1:-1] - # - # xEllipseAroundAll[n2][elementsAroundQuarterDuod + 1:-elementsAroundQuarterDuod] = xNew - # d1EllipseAroundAll[n2][elementsAroundQuarterDuod + 1:-elementsAroundQuarterDuod] = d1New - # - # d1EllipseAroundAll[n2] = interp.smoothCubicHermiteDerivativesLoop(xEllipseAroundAll[n2], - # d1EllipseAroundAll[n2]) - # - # # Calculate and smooth d2 - # xAlongAll = [] - # for n1 in range(elementsAroundHalfDuod - 1): - # xAlong = [] - # for n2 in range(len(xEllipseAroundAll)): - # xAlong.append(xEllipseAroundAll[n2][n1 if n2 else 0]) - # xAlongAll.append(xAlong) - # - # # Row with annulus - left - # xAlong = [] - # for n2 in range(len(xEllipseAroundAll)): - # xAlong.append(xEllipseAroundAll[n2][elementsAroundHalfDuod - 1 if n2 else 0]) - # xAlongAll.append(xAlong) - # - # xAlongAll.append(xAlongCurvatures) - # - # for n1 in range(elementsAroundHalfDuod - 1): - # xAlong = [] - # for n2 in range(len(xEllipseAroundAll)): - # if n2 == 0: - # ringIdx = 0 - # elif elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - # ringIdx = n1 + elementsAroundHalfDuod - # else: - # ringIdx = n1 + elementsAroundHalfDuod + 1 - # xAlong.append(xEllipseAroundAll[n2][ringIdx]) - # xAlongAll.append(xAlong) - # - # d2AlongAll = [] - # for n1 in range(elementsCountAroundDuod): - # rotAngle = -math.pi * 2.0 / elementsCountAroundDuod * n1 - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxisApex, rotAngle) - # d2ApexRot = [rotFrame[j][0] * d2Apex[0] + rotFrame[j][1] * d2Apex[1] + - # rotFrame[j][2] * d2Apex[2] for j in range(3)] - # - # if n1 == elementsAroundHalfDuod: # Process LC and GC - # # GC - # # Resample point downstream from apex - # nx = \ - # trackSurfaceStomach.createHermiteCurvePoints( - # sampledProportionsOneLeft[-2][0], sampledProportionsOneLeft[-2][1], - # sampledProportionsOneRight[1][0], sampledProportionsOneRight[1][1], 2, - # derivativeStart=d1EllipseAroundAll[1][elementsAroundHalfDuod - 1], - # derivativeEnd=d1EllipseAroundAll[1][elementsAroundHalfDuod + 1])[0] - # - # xEllipseAroundAll[1][elementsAroundHalfDuod] = nx[1] - # - # d1EllipseAroundAll[1] = interp.smoothCubicHermiteDerivativesLoop(xEllipseAroundAll[1], - # d1EllipseAroundAll[1]) - # - # xAlongGCHalfDuodNew = [] - # for n2 in range(elementsAlongFundusApexToCardia + 1): - # xAlongGCHalfDuodNew.append(xEllipseAroundAll[n2][elementsAroundHalfDuod]) - # - # d2AlongGCHalfDuodNew = [d2ApexRot] - # for n2 in range(1, len(xAlongGCHalfDuodNew) - 1): - # d = findDerivativeBetweenPoints(xAlongGCHalfDuodNew[n2], xAlongGCHalfDuodNew[n2 + 1]) - # d2AlongGCHalfDuodNew.append(d) - # d2AlongGCHalfDuodNew.append(d2AnnulusOuter[0]) - # - # d2AlongGCHalfDuodNew = \ - # interp.smoothCubicHermiteDerivativesLine(xAlongGCHalfDuodNew + [o1_x[-1][0]], - # d2AlongGCHalfDuodNew + [d2AnnulusOuter[0]], - # fixEndDerivative=True)[:-1] - # d2AlongCurvatures[:len(d2AlongGCHalfDuodNew)] = d2AlongGCHalfDuodNew - # d2AlongAll.append(d2AlongCurvatures) - # - # else: - # d2Along = [d2ApexRot] - # for n2 in range(1, len(xAlongAll[n1])): - # d = findDerivativeBetweenPoints(xAlongAll[n1][n2 - 1], xAlongAll[n1][n2]) - # d2Along.append(d) - # d2Along[-1] = cd1Sections[-1][-1] - # - # if materialCoordinates: - # # Break point along at body-antrum and pylorus-duod intersection and smooth separately to keep - # # derivative at body end - # d2AlongFundusBody = \ - # interp.smoothCubicHermiteDerivativesLine( - # xAlongAll[n1][:elementCountGroupList[0] + elementCountGroupList[1] + 1], - # d2Along[:elementCountGroupList[0] + elementCountGroupList[1] + 1], - # fixStartDirection=True, fixEndDirection=True) - # - # for n in range(elementCountGroupList[-1] + 1): - # d2Along[-(n + 1)] = cd1Sections[-1][-1] - # - # d2AlongBodyToPylorus = \ - # interp.smoothCubicHermiteDerivativesLine( - # xAlongAll[n1][elementCountGroupList[0] + elementCountGroupList[1]:-n], - # d2Along[elementCountGroupList[0] + elementCountGroupList[1]:-n], - # fixStartDirection=True, fixEndDirection=True) - # - # d2AlongDuod = \ - # interp.smoothCubicHermiteDerivativesLine( - # xAlongAll[n1][-(n + 1):], d2Along[-(n + 1):], fixStartDirection=True, fixEndDirection=True) - # - # d2Along = d2AlongFundusBody[:-1] + d2AlongBodyToPylorus[:-1] + d2AlongDuod - # else: - # d2Along = interp.smoothCubicHermiteDerivativesLine(xAlongAll[n1], d2Along, fixStartDirection=True, - # fixEndDirection=True) - # if n1 == elementsAroundHalfDuod - 1 or n1 == elementsAroundHalfDuod + 1: - # d2Along[elementsAlongFundusApexToCardia] = \ - # vector.setMagnitude(d2Along[elementsAlongFundusApexToCardia], - # 0.5 * (vector.magnitude(d2Along[elementsAlongFundusApexToCardia]) + - # vector.magnitude(d2AnnulusOuter[1]))) - # d2Along[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2] = \ - # vector.setMagnitude(d2Along[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2], - # 0.5 * (vector.magnitude(d2Along[elementsAlongFundusApexToCardia + - # elementsAroundHalfEso - 2]) + - # vector.magnitude(d2AnnulusOuter[1]))) - # d2AlongAll.append(d2Along) - # - # # Replace d2 for points sitting on annulus - # for n2 in range(2, elementsAroundHalfEso - 1): - # n2Idx = n2 + elementsAlongFundusApexToCardia - 1 - # d2AlongAll[elementsAroundHalfDuod - 1][n2Idx] = d2AnnulusOuter[n2] - # d2AlongAll[elementsAroundHalfDuod + 1][n2Idx] = d2AnnulusOuter[-n2] - # - # # Re-arrange back to around followed by along - # for n2 in range(len(xEllipseAroundAll)): - # incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ - # elementsAroundHalfEso - 2 - # for n1 in range(len(xEllipseAroundAll[n2]) + (1 if incompleteRingsWithinEso else 0)): - # if incompleteRingsWithinEso: - # if n1 == elementsAroundHalfDuod: - # pass - # else: - # d2EllipseAroundAll[n2][n1 - (1 if n1 > elementsAroundHalfDuod else 0)] = d2AlongAll[n1][n2] - # elif n2 >= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - # d2EllipseAroundAll[n2][n1] = \ - # d2AlongAll[n1][n2 - (elementsAroundHalfEso + 1 - 4 if n1 == elementsAroundHalfDuod else 0)] - # else: - # d2EllipseAroundAll[n2][n1] = d2AlongAll[n1][n2] - # - # xOuter = xEllipseAroundAll - # d1Outer = d1EllipseAroundAll - # d2Outer = d2EllipseAroundAll - # - # # Calculate d3 - # d3UnitOuter = [] - # for n2 in range(len(xOuter)): - # d3Around = [] - # for n1 in range(len(xOuter[n2])): - # if n2 == 0: - # d3Around.append(rotAxisApex) - # else: - # d3Around.append(vector.normalise( - # vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) - # d3UnitOuter.append(d3Around) - # - # # Calculate curvature around - # d1Curvature = [] - # d1Curvature.append([1.0 for n in range(len(xOuter[0]))]) # Will be replaced in later step - # esoCount = 1 - # for n2 in range(1, len(xOuter)): - # incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ - # elementsAroundHalfEso - 2 - # completeRingsOnCardia = (n2 == elementsAlongFundusApexToCardia or n2 == elementsAlongFundusApexToCardia + - # elementsAroundHalfEso - 2) - # if incompleteRingsWithinEso: - # d2 = o1_d2[-1][esoCount] - # rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(o1_d1[-1][esoCount]), - # vector.normalise(o1_d2[-1][esoCount]))) - # rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - # d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - # d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod] + [o1_x[-1][esoCount]], - # d1Outer[n2][:elementsAroundHalfDuod] + [d2Rot], - # d3UnitOuter[n2][:elementsAroundHalfDuod] + [rotAxis]) - # curvature = interp.getCubicHermiteCurvature(xAnnulusOuter[esoCount], d1AnnulusOuter[esoCount], - # o1_x[-1][esoCount], d2Rot, - # d3UnitOuter[n2][elementsAroundHalfDuod - 1], 0.0) - # d1CurvatureFirstHalf[-2] = curvature - # - # d3 = vector.normalise(vector.crossproduct3(vector.normalise(o1_d1[-1][-esoCount]), - # vector.normalise(o1_d2[-1][-esoCount]))) - # d1CurvatureSecondHalf = findCurvatureAlongLine([o1_x[-1][-esoCount]] + - # xOuter[n2][elementsAroundHalfDuod:] + [xOuter[n2][0]], - # [o1_d2[-1][-esoCount]] + - # d1Outer[n2][elementsAroundHalfDuod:] + [d1Outer[n2][0]], - # [d3] + d3UnitOuter[n2][elementsAroundHalfDuod:] + - # [d3UnitOuter[n2][0]])[:-1] - # - # curvature = interp.getCubicHermiteCurvature(o1_x[-1][-esoCount], o1_d2[-1][-esoCount], - # xAnnulusOuter[-esoCount], d1AnnulusOuter[-esoCount], - # d3UnitOuter[n2][elementsAroundHalfDuod], 1.0) - # d1CurvatureSecondHalf[1] = curvature - # d1Curvature.append(d1CurvatureFirstHalf[:-1] + d1CurvatureSecondHalf[1:]) - # esoCount += 1 - # - # elif completeRingsOnCardia: - # d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod], - # d1Outer[n2][:elementsAroundHalfDuod], - # d3UnitOuter[n2][:elementsAroundHalfDuod]) - # - # d1CurvatureSecondHalf = findCurvatureAlongLine(xOuter[n2][elementsAroundHalfDuod + 1:] + [xOuter[n2][0]], - # d1Outer[n2][elementsAroundHalfDuod + 1:] + [d1Outer[n2][0]], - # d3UnitOuter[n2][elementsAroundHalfDuod + 1:] + - # [d3UnitOuter[n2][0]])[:-1] - # - # midPtCurvature = annulusD2Curvature[0 if n2 == elementsAlongFundusApexToCardia else elementsAroundHalfEso] - # d1Curvature.append(d1CurvatureFirstHalf + [midPtCurvature] + d1CurvatureSecondHalf) - # esoCount += 1 - # else: - # d1Curvature.append(findD1CurvatureAround(xOuter[n2], d1Outer[n2], d3UnitOuter[n2])) - # - # # Populate d3Along for use to calculate curvature along - # d3UnitAlongAll = [] - # for n1 in range(elementsAroundHalfDuod - 1): - # d3Along = [] - # for n2 in range(len(d3UnitOuter)): - # d3Along.append(d3UnitOuter[n2][n1 if n2 else 0]) - # d3UnitAlongAll.append(d3Along) - # - # # Row wth annulus - left - # d3Along = [] - # for n2 in range(len(d3UnitOuter)): - # d3Along.append(d3UnitOuter[n2][elementsAroundHalfDuod - 1 if n2 else 0]) - # d3UnitAlongAll.append(d3Along) - # - # # GC and LC row - needs to be in 2 parts - # # GC part - # d3AlongGCHalfDuod = [] - # for n2 in range(elementsAlongFundusApexToCardia + 1): - # d3AlongGCHalfDuod.append(d3UnitOuter[n2][elementsAroundHalfDuod if n2 else 0]) - # - # # LC part - # d3AlongLCHalfDuod = [] - # for n2 in range(elementsAlongCardiaToDuod + 1): - # d3AlongLCHalfDuod.append(d3UnitOuter[n2 + elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2] - # [elementsAroundHalfDuod]) - # d3Along = d3AlongGCHalfDuod + d3AlongLCHalfDuod - # d3UnitAlongAll.append(d3Along) - # - # for n1 in range(elementsAroundHalfDuod - 1): - # d3Along = [] - # for n2 in range(len(d3UnitOuter)): - # if n2 == 0: - # ringIdx = 0 - # elif elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - # ringIdx = n1 + elementsAroundHalfDuod - # else: - # ringIdx = n1 + elementsAroundHalfDuod + 1 - # d3Along.append(d3UnitOuter[n2][ringIdx]) - # d3UnitAlongAll.append(d3Along) - # - # # Calculate curvature along - # d2CurvatureAlong = [] - # for n1 in range(len(xAlongAll)): - # if n1 == elementsAroundHalfDuod: # Process LC and GC - # # GC - # d2CurvatureAlongGCHalfDuod = findCurvatureAlongLine(xAlongGCHalfDuod, d2AlongGCHalfDuod, d3AlongGCHalfDuod) - # # LC - # d2CurvatureAlongLCHalfDuod = findCurvatureAlongLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, d3AlongLCHalfDuod) - # d2CurvaturesAlongCurvature = d2CurvatureAlongGCHalfDuod + d2CurvatureAlongLCHalfDuod - # d2CurvatureAlong.append(d2CurvaturesAlongCurvature) - # else: - # curvature = findCurvatureAlongLine(xAlongAll[n1], d2AlongAll[n1], d3UnitAlongAll[n1]) - # # replace with curvature from annulus - # if n1 == elementsAroundHalfDuod - 1 or n1 == elementsAroundHalfDuod + 1: - # for n2 in range(2, elementsAroundHalfEso - 1): - # n2Idx = n2 + elementsAlongFundusApexToCardia + 1 - # curvature[n2Idx] = annulusD2Curvature[(n2 + 1 if elementsAroundHalfDuod - 1 else -(n2 + 1))] - # d2CurvatureAlong.append(curvature) - # - # # Re-arrange back to around followed by along - # for n2 in range(len(xEllipseAroundAll)): - # incompleteRingsWithinEso = elementsAlongFundusApexToCardia < n2 < elementsAlongFundusApexToCardia + \ - # elementsAroundHalfEso - 2 - # for n1 in range(len(xEllipseAroundAll[n2]) + (1 if incompleteRingsWithinEso else 0)): - # if incompleteRingsWithinEso: - # if n1 == elementsAroundHalfDuod: - # pass - # else: - # d2Curvature[n2][n1 - (1 if n1 > elementsAroundHalfDuod else 0)] = d2CurvatureAlong[n1][n2] - # elif n2 >= elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2: - # d2Curvature[n2][n1] = \ - # d2CurvatureAlong[n1][n2 - (elementsAroundHalfEso + 1 - 4 if n1 == elementsAroundHalfDuod else 0)] - # else: - # d2Curvature[n2][n1] = d2CurvatureAlong[n1][n2] - # - # # Replace d1Curvature at apex with d2Curvature - # for n1 in range(elementsCountAroundDuod): - # d1Curvature[0][n1] = d2Curvature[0][n1] - annotationGroupsAlong = [] for i in range(len(elementsAlongSections)): elementsCount = elementsAlongSections[i] @@ -2889,24 +2293,24 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementIdxThroughWall.append(elementIdxAround) elementIdxMat.append(elementIdxThroughWall) - # elif 0 < e2 < bodyStartIdx - 1 or e2 > bodyStartIdx: else: - e1Range = elementsCountAroundDuod - 2 if (e2 == bodyStartIdx - 1 or e2 == bodyStartIdx) \ + e1Range = elementsCountAroundDuod - 2 if (annulusFundusOpenRingIdx - 1 <= e2 <= annulusBodyOpenRingIdx) \ else len(xSampledAroundAlong[e2]) for e3 in range(elementsCountThroughWall): elementIdxAround = [] for e1 in range(e1Range): + e1IdxBni1 = e1 + e1IdxBni3 = e1 if e1 > elementsAroundHalfDuod - 2: - e1IdxBni1 = e1 + (2 if e2 == bodyStartIdx - 1 else 1 if e2 == bodyStartIdx else 0) - e1IdxBni3 = e1 + (1 if e2 == bodyStartIdx - 1 else 2 if e2 == bodyStartIdx else 0) - else: - e1IdxBni1 = e1 - e1IdxBni3 = e1 - # elif elementsAlongFundusApexToCardia < e2 < elementsAlongFundusApexToCardia + \ - # elementsAroundHalfEso - 3: # incomplete rings interior of eso - # print('3') - # e1IdxBni1 = e1 + 1 - # e1IdxBni3 = e1 + 1 + if e2 == annulusFundusOpenRingIdx - 1: + e1IdxBni1 = e1 + 2 + e1IdxBni3 = e1 + 1 + elif annulusFundusOpenRingIdx - 1 < e2 < annulusBodyOpenRingIdx: + e1IdxBni1 = e1 + 1 + e1IdxBni3 = e1 + 1 + elif e2 == annulusBodyOpenRingIdx: + e1IdxBni1 = e1 + 1 + e1IdxBni3 = e1 + 2 eft1 = eftStandard scaleFactors = [] @@ -2922,7 +2326,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nodeIdentifiers = [bni111, bni211, bni121, bni221, bni112, bni212, bni122, bni222] - if e2 == bodyStartIdx - 2: + if e2 == annulusFundusOpenRingIdx - 2: if e1 == elementsAroundHalfDuod - 2: eft1 = eftfactory.createEftNoCrossDerivatives() remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, @@ -2961,7 +2365,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX - if e2 == bodyStartIdx + 1: + if e2 == annulusBodyOpenRingIdx + 1: if e1 == elementsAroundHalfDuod - 2: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() @@ -3028,16 +2432,32 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n3 in range(elementsCountThroughWall + 1): n1 = 0 + m = -1 for nAround in range(elementsCountAroundEso): if nAround == 0: - idx = idxMat[bodyStartIdx - 1][n3][elementsAroundHalfDuod] - elif 0 < nAround < elementsAroundQuarterEso or nAround > elementsAroundQuarterEso + elementsAroundHalfEso: - idx = idxMat[bodyStartIdx - 1][n3][elementsAroundHalfDuod + (-1 if 0 < nAround < elementsAroundQuarterEso else 1)] + idx = idxMat[annulusFundusOpenRingIdx - 1][n3][elementsAroundHalfDuod] + elif 0 < nAround < elementsAroundQuarterEso: + idx = idxMat[annulusFundusOpenRingIdx - 1 + n1][n3][elementsAroundHalfDuod - 1] + n1 += 1 elif nAround == elementsAroundQuarterEso or nAround == elementsAroundQuarterEso + elementsAroundHalfEso: - idx = idxMat[bodyStartIdx][n3][elementsAroundHalfDuod - (1 if nAround == elementsAroundQuarterEso else 0)] - elif elementsAroundQuarterEso < nAround < elementsAroundHalfEso + 2: - idx = idxMat[bodyStartIdx + 1][n3][elementsAroundHalfDuod - 1 + n1] + idx = idxMat[bodyStartIdx][n3][elementsAroundHalfDuod - (1 if nAround == elementsAroundQuarterEso + else 0)] + n1 = 1 + elif elementsAroundQuarterEso < nAround < elementsAroundHalfEso - 1: + idx = idxMat[bodyStartIdx + n1][n3][elementsAroundHalfDuod - 1] + n1 += 1 + elif elementsAroundHalfEso - 1 <= nAround <= elementsAroundHalfEso + 1: + idx = idxMat[annulusBodyOpenRingIdx + 1][n3][elementsAroundHalfDuod + m] + m += 1 + n1 = 1 + elif elementsAroundHalfEso + 1 < nAround < elementsAroundHalfEso + elementsAroundQuarterEso: + idx = idxMat[annulusBodyOpenRingIdx + 1 - n1][n3][elementsAroundHalfDuod] n1 += 1 + elif elementsAroundHalfEso + elementsAroundQuarterEso < nAround < elementsCountAroundEso - 1: + idx = idxMat[bodyStartIdx - n1][n3][elementsAroundHalfDuod] + n1 += 1 + else: + idx = idxMat[annulusFundusOpenRingIdx - 1][n3][elementsAroundHalfDuod + 1] endPoints_x[n3][nAround] = xList[idx - stomachStartNode] endPoints_d1[n3][nAround] = d1List[idx - stomachStartNode] From 06630ecd37e9f6662f4ba42d15f6d1b8db941f3d Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 10 Aug 2023 17:42:46 +1200 Subject: [PATCH 17/30] Clean up code --- .../meshtypes/meshtype_3d_stomach1.py | 1125 +++++++---------- 1 file changed, 438 insertions(+), 687 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 276674d2..3e185a42 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -11,9 +11,9 @@ from cmlibs.maths.vectorops import cross, sub from cmlibs.utils.zinc.field import find_or_create_field_coordinates -from cmlibs.utils.zinc.finiteelement import get_maximum_element_identifier, get_maximum_node_identifier +from cmlibs.utils.zinc.finiteelement import get_element_node_identifiers, get_maximum_node_identifier from cmlibs.utils.zinc.general import ChangeManager -from cmlibs.zinc.element import Element, Elementbasis +from cmlibs.zinc.element import Element from cmlibs.zinc.field import Field from cmlibs.zinc.node import Node from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups, \ @@ -458,7 +458,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 2, - 'Number of elements through wall': 1, # 4, later + 'Number of elements through wall': 1, 'Unit scale': 0.0105 * 101, 'Outlet': False, 'Ostium diameter': 25.0, @@ -664,7 +664,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Human 2' in parameterSetName: - options['Number of elements through wall'] = 1 # 4 later + options['Number of elements through wall'] = 1 options['Wall thickness'] = 0.0525 * 101 elif 'Mouse 1' in parameterSetName: options['Number of elements around duodenum'] = 16 @@ -824,8 +824,7 @@ def generateBaseMesh(cls, region, options): materialCentralPath = cls.centralPathDefaultScaffoldPackages['Material'] limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] - elementsCountAroundEso = options['Number of elements around esophagus'] - elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) + allAnnotationGroups = [] stomachTermsAlong = [None, 'fundus of stomach', 'body of stomach', @@ -836,87 +835,83 @@ def generateBaseMesh(cls, region, options): coordinates = find_or_create_field_coordinates(fm) geometricCentralPath = StomachCentralPath(region, geometricCentralPath, stomachTermsAlong) - # geometricCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path.exf") - arcLengthOfGroupsAlong = geometricCentralPath.arcLengthOfGroupsAlong - allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier = \ + allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongGroups = \ createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, centralPath=geometricCentralPath, - options=options, nodeIdentifier=1, elementIdentifier=1, splitCoordinates=False, - materialCoordinates=False) - - # # Material coordinates - # stomach_coordinates = find_or_create_field_coordinates(fm, name="stomach coordinates") - # allAnnotationGroupsMaterial = [] - # tmp_region = region.createRegion() - # tmp_fm = tmp_region.getFieldmodule() - # with ChangeManager(tmp_fm): - # tmp_stomach_coordinates = find_or_create_field_coordinates(tmp_fm, name="stomach coordinates") - # - # materialCentralPath = StomachCentralPath(tmp_region, materialCentralPath, stomachTermsAlong) - # materialCentralPath._path_region.writeFile("C:\\Users\\mlin865\\tmp\\km_stomach_path_material.exf") - # - # allAnnotationGroupsMaterial, nextNodeIdentifier, nextElementIdentifier = \ - # createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, - # allAnnotationGroupsMaterial, - # centralPath=materialCentralPath, options=options, nodeIdentifier=1, - # elementIdentifier=1, splitCoordinates=False, materialCoordinates=True) - # - # # Write two coordinates - # sir = tmp_region.createStreaminformationRegion() - # srm = sir.createStreamresourceMemory() - # tmp_region.write(sir) - # result, buffer = srm.getBuffer() - # - # sir = region.createStreaminformationRegion() - # srm = sir.createStreamresourceMemoryBuffer(buffer) - # region.read(sir) - # - # del srm - # del sir - # del tmp_stomach_coordinates - # del tmp_fm - # del tmp_region - - # # Create markers - # markerTermNameStomachCoordinatesMap = { - # 'body-antrum junction along the greater curvature on luminal surface': [0.6020919166990195, -0.45004378032192227, 0.0], - # 'body-antrum junction along the greater curvature on serosa': [0.6, -0.5, 0.0], - # 'distal point of lower esophageal sphincter serosa on the greater curvature of stomach': [1.280068326927052, 0.7999733714717442, 4.9153708368810965e-16], - # 'distal point of lower esophageal sphincter serosa on the lesser curvature of stomach': [1.1200683310311637, 0.8000096111703247, 5.132730495672042e-16], - # 'esophagogastric junction along the greater curvature on luminal surface': [1.3499430436270714, 0.44878481258293096, -4.212552457001039e-17], - # 'esophagogastric junction along the greater curvature on serosa': [1.3499935896233386, 0.4987847870339471, -2.4350160282618435e-17], - # 'esophagogastric junction along the lesser curvature on luminal surface': [1.0489058130975502, 0.4491717442850351, 3.0345621453573164e-16], - # 'esophagogastric junction along the lesser curvature on serosa': [1.050012637401148, 0.4991433628042418, 2.8296958630895795e-16], - # 'gastroduodenal junction along the greater curvature on luminal surface': [0.2, -0.15, 0.0], - # 'gastroduodenal junction along the greater curvature on serosa': [0.2, -0.2, 0.0], - # 'gastroduodenal junction along the lesser curvature on luminal surface': [0.2, 0.15, 0.0], - # 'gastroduodenal junction along the lesser curvature on serosa': [0.20, 0.20, 0.00], - # 'limiting ridge at the greater curvature on the luminal surface' if limitingRidge else - # 'fundus-body junction along the greater curvature on luminal surface': [1.1997241080276948, -0.4500013598322351, -0.0002446732391805909], - # 'limiting ridge at the greater curvature on serosa' if limitingRidge else - # 'fundus-body junction along the greater curvature on serosa': [1.2, -0.5, 0.0] - # } - # if elementsCountThroughWall == 4: - # markerTermNameStomachCoordinatesCMLMMap = { - # 'body-antrum junction along the greater curvature on circular-longitudinal muscle interface': [0.6005229791747548, -0.48751094508048054, 0.0], - # 'esophagogastric junction along the greater curvature on circular-longitudinal muscle interface': [1.349980953124272, 0.4862847934211931, -2.8794001354466424e-17], - # 'esophagogastric junction along the lesser curvature on circular-longitudinal muscle interface': [1.0497365634804512, 0.4866625412064305, 3.2195156437946623e-16], - # 'gastroduodenal junction along the greater curvature on circular-longitudinal muscle interface': [0.2, -0.1875, 0.0], - # 'gastroduodenal junction along the lesser curvature on circular-longitudinal muscle interface': [0.2, 0.1875, 0.0], - # 'limiting ridge at the greater curvature on the circular-longitudinal muscle interface' if limitingRidge - # else 'fundus-body junction along the greater curvature on circular-longitudinal muscle interface': [1.199934138287874, -0.48750032317766967, -6.116839191743296e-05] - # } - # markerTermNameStomachCoordinatesMap.update(markerTermNameStomachCoordinatesCMLMMap) - # - # nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - # nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) - # - # for termName, stomachCoordinatesValues in markerTermNameStomachCoordinatesMap.items(): - # annotationGroup = findOrCreateAnnotationGroupForTerm( - # allAnnotationGroups, region, get_stomach_term(termName), isMarker=True) - # annotationGroup.createMarkerNode(nodeIdentifier, stomach_coordinates, stomachCoordinatesValues) - # nodeIdentifier += 1 + options=options, nodeIdentifier=1, elementIdentifier=1) + + # Material coordinates + stomach_coordinates = find_or_create_field_coordinates(fm, name="stomach coordinates") + allAnnotationGroupsMaterial = [] + tmp_region = region.createRegion() + tmp_fm = tmp_region.getFieldmodule() + with ChangeManager(tmp_fm): + tmp_stomach_coordinates = find_or_create_field_coordinates(tmp_fm, name="stomach coordinates") + + materialCentralPath = StomachCentralPath(tmp_region, materialCentralPath, stomachTermsAlong) + + allAnnotationGroupsMaterial, nextNodeIdentifier, nextElementIdentifier = \ + createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, + allAnnotationGroupsMaterial, + centralPath=materialCentralPath, options=options, nodeIdentifier=1, + elementIdentifier=1, elementsAlongSections=elementsAlongGroups, + materialCoordinates=True)[:-1] + + # Write two coordinates + sir = tmp_region.createStreaminformationRegion() + srm = sir.createStreamresourceMemory() + tmp_region.write(sir) + result, buffer = srm.getBuffer() + + sir = region.createStreaminformationRegion() + srm = sir.createStreamresourceMemoryBuffer(buffer) + region.read(sir) + + del srm + del sir + del tmp_stomach_coordinates + del tmp_fm + del tmp_region + + # Create markers + markerTermNameStomachCoordinatesMap = { + 'body-antrum junction along the greater curvature on luminal surface': [-0.6, -0.45, 6.34622e-18], + 'body-antrum junction along the greater curvature on serosa': [-0.6, -0.5, 0.0], + 'distal point of lower esophageal sphincter serosa on the greater curvature of stomach': [0.08, 0.8, 4.48345e-16], + 'distal point of lower esophageal sphincter serosa on the lesser curvature of stomach': [-0.08, 0.8, 4.67938e-16], + 'esophagogastric junction along the greater curvature on luminal surface': [0.14885, 0.451205, 3.88484e-14], + 'esophagogastric junction along the greater curvature on serosa': [0.149987, 0.501192, 3.72966e-16], + 'esophagogastric junction along the lesser curvature on luminal surface': [-0.15, 0.45, 3.33066e-16], + 'esophagogastric junction along the lesser curvature on serosa': [-0.15, 0.5, 2.28983e-16], + 'gastroduodenal junction along the greater curvature on luminal surface': [-1.1, -0.15, 7.93284e-18], + 'gastroduodenal junction along the greater curvature on serosa': [-1.1, -0.2, 0], + 'gastroduodenal junction along the lesser curvature on luminal surface': [-1.1, 0.15, -4.73333e-17], + 'gastroduodenal junction along the lesser curvature on serosa': [-1.1, 0.2, -2.77556e-16], + 'limiting ridge at the greater curvature on the luminal surface' if limitingRidge else + 'fundus-body junction along the greater curvature on luminal surface': [-2.60734e-23, -0.450001, -0.00024468], + 'fundus-body junction along the greater curvature on serosa': [2.77556e-17, -0.5, 5.74685e-16] + } + if elementsCountThroughWall == 4: + markerTermNameStomachCoordinatesCMLMMap = { + 'body-antrum junction along the greater curvature on circular-longitudinal muscle interface': [-0.6, -0.4875, -8.32667e-17], + 'esophagogastric junction along the greater curvature on circular-longitudinal muscle interface': [0.149703, 0.488695, 9.99176e-15], + 'esophagogastric junction along the lesser curvature on circular-longitudinal muscle interface': [-0.15, 0.4875, 2.76195e-16], + 'gastroduodenal junction along the greater curvature on circular-longitudinal muscle interface': [-1.1, -0.1875, 1.66533e-16], + 'gastroduodenal junction along the lesser curvature on circular-longitudinal muscle interface': [-1.1, 0.1875, -2.24625e-16], + 'limiting ridge at the greater curvature on the circular-longitudinal muscle interface' if limitingRidge + else 'fundus-body junction along the greater curvature on circular-longitudinal muscle interface': [3.75751e-17, -0.4875, -6.117e-05] + } + markerTermNameStomachCoordinatesMap.update(markerTermNameStomachCoordinatesCMLMMap) + + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + nodeIdentifier = max(1, get_maximum_node_identifier(nodes) + 1) + + for termName, stomachCoordinatesValues in markerTermNameStomachCoordinatesMap.items(): + annotationGroup = findOrCreateAnnotationGroupForTerm( + allAnnotationGroups, region, get_stomach_term(termName), isMarker=True) + annotationGroup.createMarkerNode(nodeIdentifier, stomach_coordinates, stomachCoordinatesValues) + nodeIdentifier += 1 return allAnnotationGroups, None @@ -935,257 +930,257 @@ def refineMesh(cls, meshrefinement, options): refineElementsCountThroughWall) return - # @classmethod - # def defineFaceAnnotations(cls, region, options, annotationGroups): - # """ - # Add face annotation groups from the highest dimension mesh. - # Must have defined faces and added subelements for highest dimension groups. - # :param region: Zinc region containing model. - # :param options: Dict containing options. See getDefaultOptions(). - # :param annotationGroups: List of annotation groups for top-level elements. - # New face annotation groups are appended to this list. - # """ - # - # limitingRidge = options['Limiting ridge'] - # elementsCountThroughWall = options['Number of elements through wall'] - # - # stomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("stomach")) - # dorsalStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("dorsal stomach")) - # ventralStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("ventral stomach")) - # bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("body of stomach")) - # cardiaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("cardia of stomach")) - # duodenumGroup = getAnnotationGroupForTerm(annotationGroups, get_smallintestine_term("duodenum")) - # fundusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("fundus of stomach")) - # antrumGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric antrum")) - # pylorusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric canal")) - # esoGroup = getAnnotationGroupForTerm(annotationGroups, get_esophagus_term("esophagus")) - # nearLCGroup = getAnnotationGroupForTerm(annotationGroups, - # ("elements adjacent to lesser curvature", "None")) - # - # # Create new groups - # stomachLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("luminal surface of stomach")) - # stomachSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("serosa of stomach")) - # bodyLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("luminal surface of body of stomach")) - # bodySerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("serosa of body of stomach")) - # cardiaLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term( - # "luminal surface of cardia of stomach")) - # cardiaSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("serosa of cardia of stomach")) - # duodenumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_smallintestine_term("luminal surface of duodenum")) - # duodenumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_smallintestine_term("serosa of duodenum")) - # esoLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_esophagus_term("luminal surface of esophagus")) - # esoSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_esophagus_term("serosa of esophagus")) - # fundusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term( - # "luminal surface of fundus of stomach")) - # fundusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("serosa of fundus of stomach")) - # antrumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("luminal surface of pyloric antrum")) - # antrumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("serosa of pyloric antrum")) - # pylorusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("luminal surface of pyloric canal")) - # pylorusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("serosa of pyloric canal")) - # gastroduodenalJunctionGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("gastroduodenal junction")) - # - # fm = region.getFieldmodule() - # mesh2d = fm.findMeshByDimension(2) - # mesh1d = fm.findMeshByDimension(1) - # - # is_exterior = fm.createFieldIsExterior() - # is_exterior_face_outer = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) - # is_exterior_face_inner = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) - # - # is_gastroduod = fm.createFieldAnd(duodenumGroup.getGroup(), pylorusGroup.getGroup()) - # gastroduodenalJunctionGroup.getMeshGroup(mesh2d).addElementsConditional(is_gastroduod) - # - # is_dorsal = dorsalStomachGroup.getGroup() - # is_ventral = ventralStomachGroup.getGroup() - # is_curvatures = fm.createFieldAnd(is_dorsal, is_ventral) - # - # is_nearLC = nearLCGroup.getGroup() - # is_lesserCurvature = fm.createFieldAnd(is_curvatures, is_nearLC) - # lesserCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("lesser curvature of stomach")) - # lesserCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_lesserCurvature) - # - # is_nearGC = fm.createFieldNot(is_nearLC) - # is_greaterCurvature = fm.createFieldAnd(is_curvatures, is_nearGC) - # greaterCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("greater curvature of stomach")) - # greaterCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_greaterCurvature) - # - # if elementsCountThroughWall == 4: - # CMLMInterfaceGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of stomach")) - # circularMuscleGroup = getAnnotationGroupForTerm(annotationGroups, - # get_stomach_term("circular muscle layer of stomach")) - # longitudinalMuscleGroup = \ - # getAnnotationGroupForTerm(annotationGroups, get_stomach_term("longitudinal muscle layer of stomach")) - # is_CM = circularMuscleGroup.getGroup() - # is_LM = longitudinalMuscleGroup.getGroup() - # is_CMLMInterface = fm.createFieldAnd(is_CM, is_LM) - # CMLMInterfaceGroup.getMeshGroup(mesh2d).addElementsConditional(is_CMLMInterface) - # is_curvatures_CMLM = fm.createFieldAnd(is_curvatures, is_CMLMInterface) - # is_greaterCurvature_CMLM = fm.createFieldAnd(is_greaterCurvature, is_CMLMInterface) - # is_lesserCurvature_CMLM = fm.createFieldAnd(is_lesserCurvature, is_CMLMInterface) - # - # dorsalStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of dorsal stomach")) - # ventralStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of ventral stomach")) - # is_dorsal_CMLM = fm.createFieldAnd(is_dorsal, is_CMLMInterface) - # dorsalStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_dorsal_CMLM) - # is_ventral_CMLM = fm.createFieldAnd(is_ventral, is_CMLMInterface) - # ventralStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_ventral_CMLM) - # - # gastroduod_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of gastroduodenal junction")) - # is_gastroduod_CMLM = fm.createFieldAnd(is_gastroduod, is_CMLMInterface) - # gastroduod_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_gastroduod_CMLM) - # - # bodyCurvaturesCMLMGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of body of stomach along the gastric-omentum attachment")) - # duodenumCurvaturesCMLMGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_smallintestine_term("circular-longitudinal muscle interface of " - # "first segment of the duodenum along the " - # "gastric-omentum attachment")) - # esoCurvaturesCMLMGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_esophagus_term( - # "circular-longitudinal muscle interface of esophagus along the cut margin")) - # fundusCurvaturesCMLMGroup =\ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of fundus of stomach along the greater curvature")) - # antrumGreaterCurvatureCMLMGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of pyloric antrum along the greater curvature")) - # antrumLesserCurvatureCMLMGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of pyloric antrum along the lesser curvature")) - # pylorusGreaterCurvatureCMLMGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of pyloric canal along the greater curvature")) - # pylorusLesserCurvatureCMLMGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "circular-longitudinal muscle interface of pyloric canal along the lesser curvature")) - # - # sectionCurvaturesCMLMGroups = [None, bodyCurvaturesCMLMGroup, None, duodenumCurvaturesCMLMGroup, - # esoCurvaturesCMLMGroup, fundusCurvaturesCMLMGroup, - # antrumGreaterCurvatureCMLMGroup, pylorusGreaterCurvatureCMLMGroup, - # antrumLesserCurvatureCMLMGroup, pylorusLesserCurvatureCMLMGroup] - # - # sectionGroups = [stomachGroup, bodyGroup, cardiaGroup, duodenumGroup, esoGroup, fundusGroup, antrumGroup, - # pylorusGroup] - # sectionSerosaGroups = [stomachSerosaGroup, bodySerosaGroup, cardiaSerosaGroup, duodenumSerosaGroup, - # esoSerosaGroup, fundusSerosaGroup, antrumSerosaGroup, - # pylorusSerosaGroup] - # sectionLuminalGroups = [stomachLuminalGroup, bodyLuminalGroup, cardiaLuminalGroup, duodenumLuminalGroup, - # esoLuminalGroup, fundusLuminalGroup, antrumLuminalGroup, - # pylorusLuminalGroup] - # - # for i in range(len(sectionGroups)): - # is_section = sectionGroups[i].getGroup() - # is_sectionSerosa = fm.createFieldAnd(is_section, is_exterior_face_outer) - # sectionSerosaGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionSerosa) - # is_sectionLuminal = fm.createFieldAnd(is_section, is_exterior_face_inner) - # sectionLuminalGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionLuminal) - # - # if elementsCountThroughWall == 4: - # if sectionGroups[i] is antrumGroup or sectionGroups[i] is pylorusGroup: - # is_sectionGreaterCurvatureCMLM = fm.createFieldAnd(is_section, is_greaterCurvature_CMLM) - # is_sectionLesserCurvatureCMLM = fm.createFieldAnd(is_section, is_lesserCurvature_CMLM) - # if sectionCurvaturesCMLMGroups[i]: - # sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ - # addElementsConditional(is_sectionGreaterCurvatureCMLM) - # sectionCurvaturesCMLMGroups[i+2].getMeshGroup(mesh1d). \ - # addElementsConditional(is_sectionLesserCurvatureCMLM) - # else: - # is_sectionCurvaturesCMLM = fm.createFieldAnd(is_section, is_curvatures_CMLM) - # if sectionCurvaturesCMLMGroups[i]: - # sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ - # addElementsConditional(is_sectionCurvaturesCMLM) - # - # if limitingRidge: - # limitingRidgeGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("forestomach-glandular stomach junction")) - # innerLimitingRidgeGroup = \ - # findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("limiting ridge on luminal surface")) - # outerLimitingRidgeGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, - # get_stomach_term("limiting ridge on serosa")) - # - # is_antrum = antrumGroup.getGroup() - # is_body = bodyGroup.getGroup() - # is_cardia = cardiaGroup.getGroup() - # is_fundus = fundusGroup.getGroup() - # is_limitingRidgeBody = fm.createFieldAnd(is_fundus, is_body) - # is_limitingRidgeCardia = fm.createFieldAnd(is_body, is_cardia) - # is_limitingRidgeAntrum = fm.createFieldAnd(is_antrum, is_cardia) - # is_limitingRidgeBodyCardia = fm.createFieldOr(is_limitingRidgeBody, is_limitingRidgeCardia) - # is_limitingRidgeAntrumCardia = fm.createFieldOr(is_limitingRidgeAntrum, is_limitingRidgeCardia) - # is_limitingRidge = fm.createFieldOr(is_limitingRidgeBodyCardia, is_limitingRidgeAntrumCardia) - # - # if elementsCountThroughWall == 4: - # mucosaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("mucosa of stomach")) - # is_mucosa = mucosaGroup.getGroup() - # is_bodyMucosa = fm.createFieldAnd(is_body, is_mucosa) - # is_antrumMucosa = fm.createFieldAnd(is_antrum, is_mucosa) - # is_bodyAntrumMucosa = fm.createFieldOr(is_bodyMucosa, is_antrumMucosa) - # - # is_xi1Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), - # fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) - # is_xi1All = fm.createFieldOr(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), - # fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) - # is_xi1BodyAntrumMucosaAll = fm.createFieldAnd(is_bodyAntrumMucosa, is_xi1All) - # is_limitingRidgeAroundCardia = fm.createFieldAnd(is_xi1BodyAntrumMucosaAll, - # fm.createFieldNot(is_xi1Interior)) - # - # is_xi2Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), - # fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_1)) - # is_xi2ZeroBodyMucosa = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), is_bodyMucosa) - # is_limitingRidgeBodyBoundary = fm.createFieldAnd(is_xi2ZeroBodyMucosa, - # fm.createFieldNot(is_xi2Interior)) - # - # is_limitingRidgeMucosa = fm.createFieldOr(is_limitingRidgeAroundCardia, is_limitingRidgeBodyBoundary) - # is_limitingRidge = fm.createFieldOr(is_limitingRidge, is_limitingRidgeMucosa) - # - # limitingRidgeGroup.getMeshGroup(mesh2d).addElementsConditional(is_limitingRidge) - # - # is_xi3Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0), - # fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) - # is_xi3ZeroLimitingRidge = fm.createFieldAnd(is_limitingRidge, - # fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) - # is_xi3OneLimitingRidge = fm.createFieldAnd(is_limitingRidge, - # fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) - # - # is_limitingRidgeInner = fm.createFieldAnd(is_xi3ZeroLimitingRidge, fm.createFieldNot(is_xi3Interior)) - # innerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeInner) - # - # is_limitingRidgeOuter = fm.createFieldAnd(is_xi3OneLimitingRidge, fm.createFieldNot(is_xi3Interior)) - # outerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeOuter) - # - # if elementsCountThroughWall == 4: - # limitingRidge_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( - # "limiting ridge on circular-longitudinal muscle interface")) - # is_limitingRidgeCMLM = fm.createFieldAnd(is_CMLMInterface, is_limitingRidge) - # limitingRidge_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeCMLM) - # - # annotationGroups.remove(nearLCGroup) + @classmethod + def defineFaceAnnotations(cls, region, options, annotationGroups): + """ + Add face annotation groups from the highest dimension mesh. + Must have defined faces and added subelements for highest dimension groups. + :param region: Zinc region containing model. + :param options: Dict containing options. See getDefaultOptions(). + :param annotationGroups: List of annotation groups for top-level elements. + New face annotation groups are appended to this list. + """ + + limitingRidge = options['Limiting ridge'] + elementsCountThroughWall = options['Number of elements through wall'] + + stomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("stomach")) + dorsalStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("dorsal stomach")) + ventralStomachGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("ventral stomach")) + bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("body of stomach")) + cardiaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("cardia of stomach")) + duodenumGroup = getAnnotationGroupForTerm(annotationGroups, get_smallintestine_term("duodenum")) + fundusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("fundus of stomach")) + antrumGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric antrum")) + pylorusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric canal")) + esoGroup = getAnnotationGroupForTerm(annotationGroups, get_esophagus_term("esophagus")) + nearLCGroup = getAnnotationGroupForTerm(annotationGroups, + ("elements adjacent to lesser curvature", "None")) + + # Create new groups + stomachLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("luminal surface of stomach")) + stomachSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("serosa of stomach")) + bodyLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("luminal surface of body of stomach")) + bodySerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("serosa of body of stomach")) + cardiaLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term( + "luminal surface of cardia of stomach")) + cardiaSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("serosa of cardia of stomach")) + duodenumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_smallintestine_term("luminal surface of duodenum")) + duodenumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_smallintestine_term("serosa of duodenum")) + esoLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_esophagus_term("luminal surface of esophagus")) + esoSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_esophagus_term("serosa of esophagus")) + fundusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term( + "luminal surface of fundus of stomach")) + fundusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("serosa of fundus of stomach")) + antrumLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("luminal surface of pyloric antrum")) + antrumSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("serosa of pyloric antrum")) + pylorusLuminalGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("luminal surface of pyloric canal")) + pylorusSerosaGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("serosa of pyloric canal")) + gastroduodenalJunctionGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("gastroduodenal junction")) + + fm = region.getFieldmodule() + mesh2d = fm.findMeshByDimension(2) + mesh1d = fm.findMeshByDimension(1) + + is_exterior = fm.createFieldIsExterior() + is_exterior_face_outer = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) + is_exterior_face_inner = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) + + is_gastroduod = fm.createFieldAnd(duodenumGroup.getGroup(), pylorusGroup.getGroup()) + gastroduodenalJunctionGroup.getMeshGroup(mesh2d).addElementsConditional(is_gastroduod) + + is_dorsal = dorsalStomachGroup.getGroup() + is_ventral = ventralStomachGroup.getGroup() + is_curvatures = fm.createFieldAnd(is_dorsal, is_ventral) + + is_nearLC = nearLCGroup.getGroup() + is_lesserCurvature = fm.createFieldAnd(is_curvatures, is_nearLC) + lesserCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("lesser curvature of stomach")) + lesserCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_lesserCurvature) + + is_nearGC = fm.createFieldNot(is_nearLC) + is_greaterCurvature = fm.createFieldAnd(is_curvatures, is_nearGC) + greaterCurvatureGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("greater curvature of stomach")) + greaterCurvatureGroup.getMeshGroup(mesh2d).addElementsConditional(is_greaterCurvature) + + if elementsCountThroughWall == 4: + CMLMInterfaceGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of stomach")) + circularMuscleGroup = getAnnotationGroupForTerm(annotationGroups, + get_stomach_term("circular muscle layer of stomach")) + longitudinalMuscleGroup = \ + getAnnotationGroupForTerm(annotationGroups, get_stomach_term("longitudinal muscle layer of stomach")) + is_CM = circularMuscleGroup.getGroup() + is_LM = longitudinalMuscleGroup.getGroup() + is_CMLMInterface = fm.createFieldAnd(is_CM, is_LM) + CMLMInterfaceGroup.getMeshGroup(mesh2d).addElementsConditional(is_CMLMInterface) + is_curvatures_CMLM = fm.createFieldAnd(is_curvatures, is_CMLMInterface) + is_greaterCurvature_CMLM = fm.createFieldAnd(is_greaterCurvature, is_CMLMInterface) + is_lesserCurvature_CMLM = fm.createFieldAnd(is_lesserCurvature, is_CMLMInterface) + + dorsalStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of dorsal stomach")) + ventralStomach_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of ventral stomach")) + is_dorsal_CMLM = fm.createFieldAnd(is_dorsal, is_CMLMInterface) + dorsalStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_dorsal_CMLM) + is_ventral_CMLM = fm.createFieldAnd(is_ventral, is_CMLMInterface) + ventralStomach_CMLMGroup.getMeshGroup(mesh2d).addElementsConditional(is_ventral_CMLM) + + gastroduod_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of gastroduodenal junction")) + is_gastroduod_CMLM = fm.createFieldAnd(is_gastroduod, is_CMLMInterface) + gastroduod_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_gastroduod_CMLM) + + bodyCurvaturesCMLMGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of body of stomach along the gastric-omentum attachment")) + duodenumCurvaturesCMLMGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_smallintestine_term("circular-longitudinal muscle interface of " + "first segment of the duodenum along the " + "gastric-omentum attachment")) + esoCurvaturesCMLMGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_esophagus_term( + "circular-longitudinal muscle interface of esophagus along the cut margin")) + fundusCurvaturesCMLMGroup =\ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of fundus of stomach along the greater curvature")) + antrumGreaterCurvatureCMLMGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of pyloric antrum along the greater curvature")) + antrumLesserCurvatureCMLMGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of pyloric antrum along the lesser curvature")) + pylorusGreaterCurvatureCMLMGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of pyloric canal along the greater curvature")) + pylorusLesserCurvatureCMLMGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "circular-longitudinal muscle interface of pyloric canal along the lesser curvature")) + + sectionCurvaturesCMLMGroups = [None, bodyCurvaturesCMLMGroup, None, duodenumCurvaturesCMLMGroup, + esoCurvaturesCMLMGroup, fundusCurvaturesCMLMGroup, + antrumGreaterCurvatureCMLMGroup, pylorusGreaterCurvatureCMLMGroup, + antrumLesserCurvatureCMLMGroup, pylorusLesserCurvatureCMLMGroup] + + sectionGroups = [stomachGroup, bodyGroup, cardiaGroup, duodenumGroup, esoGroup, fundusGroup, antrumGroup, + pylorusGroup] + sectionSerosaGroups = [stomachSerosaGroup, bodySerosaGroup, cardiaSerosaGroup, duodenumSerosaGroup, + esoSerosaGroup, fundusSerosaGroup, antrumSerosaGroup, + pylorusSerosaGroup] + sectionLuminalGroups = [stomachLuminalGroup, bodyLuminalGroup, cardiaLuminalGroup, duodenumLuminalGroup, + esoLuminalGroup, fundusLuminalGroup, antrumLuminalGroup, + pylorusLuminalGroup] + + for i in range(len(sectionGroups)): + is_section = sectionGroups[i].getGroup() + is_sectionSerosa = fm.createFieldAnd(is_section, is_exterior_face_outer) + sectionSerosaGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionSerosa) + is_sectionLuminal = fm.createFieldAnd(is_section, is_exterior_face_inner) + sectionLuminalGroups[i].getMeshGroup(mesh2d).addElementsConditional(is_sectionLuminal) + + if elementsCountThroughWall == 4: + if sectionGroups[i] is antrumGroup or sectionGroups[i] is pylorusGroup: + is_sectionGreaterCurvatureCMLM = fm.createFieldAnd(is_section, is_greaterCurvature_CMLM) + is_sectionLesserCurvatureCMLM = fm.createFieldAnd(is_section, is_lesserCurvature_CMLM) + if sectionCurvaturesCMLMGroups[i]: + sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ + addElementsConditional(is_sectionGreaterCurvatureCMLM) + sectionCurvaturesCMLMGroups[i+2].getMeshGroup(mesh1d). \ + addElementsConditional(is_sectionLesserCurvatureCMLM) + else: + is_sectionCurvaturesCMLM = fm.createFieldAnd(is_section, is_curvatures_CMLM) + if sectionCurvaturesCMLMGroups[i]: + sectionCurvaturesCMLMGroups[i].getMeshGroup(mesh1d). \ + addElementsConditional(is_sectionCurvaturesCMLM) + + if limitingRidge: + limitingRidgeGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("forestomach-glandular stomach junction")) + innerLimitingRidgeGroup = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("limiting ridge on luminal surface")) + outerLimitingRidgeGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_stomach_term("limiting ridge on serosa")) + + is_antrum = antrumGroup.getGroup() + is_body = bodyGroup.getGroup() + is_cardia = cardiaGroup.getGroup() + is_fundus = fundusGroup.getGroup() + is_limitingRidgeBody = fm.createFieldAnd(is_fundus, is_body) + is_limitingRidgeCardia = fm.createFieldAnd(is_body, is_cardia) + is_limitingRidgeAntrum = fm.createFieldAnd(is_antrum, is_cardia) + is_limitingRidgeBodyCardia = fm.createFieldOr(is_limitingRidgeBody, is_limitingRidgeCardia) + is_limitingRidgeAntrumCardia = fm.createFieldOr(is_limitingRidgeAntrum, is_limitingRidgeCardia) + is_limitingRidge = fm.createFieldOr(is_limitingRidgeBodyCardia, is_limitingRidgeAntrumCardia) + + if elementsCountThroughWall == 4: + mucosaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("mucosa of stomach")) + is_mucosa = mucosaGroup.getGroup() + is_bodyMucosa = fm.createFieldAnd(is_body, is_mucosa) + is_antrumMucosa = fm.createFieldAnd(is_antrum, is_mucosa) + is_bodyAntrumMucosa = fm.createFieldOr(is_bodyMucosa, is_antrumMucosa) + + is_xi1Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), + fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) + is_xi1All = fm.createFieldOr(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), + fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1)) + is_xi1BodyAntrumMucosaAll = fm.createFieldAnd(is_bodyAntrumMucosa, is_xi1All) + is_limitingRidgeAroundCardia = fm.createFieldAnd(is_xi1BodyAntrumMucosaAll, + fm.createFieldNot(is_xi1Interior)) + + is_xi2Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), + fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_1)) + is_xi2ZeroBodyMucosa = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0), is_bodyMucosa) + is_limitingRidgeBodyBoundary = fm.createFieldAnd(is_xi2ZeroBodyMucosa, + fm.createFieldNot(is_xi2Interior)) + + is_limitingRidgeMucosa = fm.createFieldOr(is_limitingRidgeAroundCardia, is_limitingRidgeBodyBoundary) + is_limitingRidge = fm.createFieldOr(is_limitingRidge, is_limitingRidgeMucosa) + + limitingRidgeGroup.getMeshGroup(mesh2d).addElementsConditional(is_limitingRidge) + + is_xi3Interior = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0), + fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) + is_xi3ZeroLimitingRidge = fm.createFieldAnd(is_limitingRidge, + fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) + is_xi3OneLimitingRidge = fm.createFieldAnd(is_limitingRidge, + fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) + + is_limitingRidgeInner = fm.createFieldAnd(is_xi3ZeroLimitingRidge, fm.createFieldNot(is_xi3Interior)) + innerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeInner) + + is_limitingRidgeOuter = fm.createFieldAnd(is_xi3OneLimitingRidge, fm.createFieldNot(is_xi3Interior)) + outerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeOuter) + + if elementsCountThroughWall == 4: + limitingRidge_CMLMGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term( + "limiting ridge on circular-longitudinal muscle interface")) + is_limitingRidgeCMLM = fm.createFieldAnd(is_CMLMInterface, is_limitingRidge) + limitingRidge_CMLMGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeCMLM) + + annotationGroups.remove(nearLCGroup) class StomachCentralPath: """ @@ -1250,42 +1245,6 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): self.cd13Groups = cd13Groups -def findD1CurvatureAround(xAround, d1Around, normsAround): - """ - Rearrange points around so that the group of points starts from left side of the annulus to the greater curvature - and ends on the right side of the annulus. This put points in consecutive order for calculating curvature. - The calculated curvatures are then re-arranged such that it starts from the greater curvature and goes to the right - side of the annulus, followed by the left side of the annulus and closing the loop back at the greater curvature. - :param xAround: points around a loop joining to the annulus. - :param d1Around: derivative of points. - :param normsAround: radial normal at each point. - :return: curvature in the original order. - """ - xLoop = xAround[int(len(xAround) * 0.5 + 1):] + xAround[: int(len(xAround) * 0.5 + 1)] - d1Loop = d1Around[int(len(d1Around) * 0.5 + 1):] + d1Around[: int(len(d1Around) * 0.5 + 1)] - normsLoop = normsAround[int(len(d1Around) * 0.5 + 1):] + normsAround[: int(len(d1Around) * 0.5 + 1)] - curvature = findCurvatureAlongLine(xLoop, d1Loop, normsLoop) - # Rearrange to correct order - d1CurvatureAround = curvature[int(len(xAround) * 0.5):] + curvature[: int(len(xAround) * 0.5):] - - return d1CurvatureAround - - -def findDerivativeBetweenPoints(v1, v2): - """ - Find vector difference between two points and rescale vector difference using cubic hermite arclength - between the points to derive the derivative between the points. - :param v1: start vector - :param v2: end vector - :return: derivative of between v1 and v2 - """ - d = [v2[c] - v1[c] for c in range(3)] - arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) - d = [c * arcLengthAround for c in vector.normalise(d)] - - return d - - def findCurvatureAroundLoop(nx, nd, radialVectors): """ Calculate curvature for points lying along a loop. @@ -1327,9 +1286,8 @@ def findCurvatureAlongLine(nx, nd, radialVectors): return curvature -def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, - centralPath, options, nodeIdentifier, elementIdentifier, - splitCoordinates, materialCoordinates=False): +def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, centralPath, options, + nodeIdentifier, elementIdentifier, elementsAlongSections = [], materialCoordinates=False): """ Generates a stomach scaffold in the region using a central path and parameter options. :param region: Region to create elements in. @@ -1341,9 +1299,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio :param options: Parameter options for stomach scaffold. :param nodeIdentifier: First node identifier. :param elementIdentifier: First element identifier. - :param splitCoordinates: Create split coordinates if True. + :param elementsAlongSections: Number of elements along each section. :param materialCoordinates: Create material coordinates if True. - :return allAnnotationGroups, elementsCountGroupList + :return allAnnotationGroups, elementsAlongSections """ elementsCountAroundEso = options['Number of elements around esophagus'] elementsCountAroundDuod = options['Number of elements around duodenum'] @@ -1694,17 +1652,17 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nodeIdentifier = nextNodeIdentifier elementIdentifier = nextElementIdentifier - # if materialCoordinates: - # GEJSettings['Unit scale'] = unitScale - # GEJSettings['Ostium diameter'] = ostiumDiameter - # GEJSettings['Ostium length'] = ostiumLength - # GEJSettings['Ostium wall thickness'] = ostiumWallThickness - # GEJSettings['Ostium wall relative thicknesses'] = ostiumWallRelThicknesses - # GEJSettings['Vessel inner diameter'] = vesselInnerDiameter - # GEJSettings['Vessel wall thickness'] = vesselWallThickness - # GEJSettings['Vessel wall relative thicknesses'] = vesselWallRelThicknesses - # GEJSettings['Vessel angle 1 degrees'] = vesselAngle1 - # GEJSettings['Vessel angle 2 degrees'] = vesselAngle2 + if materialCoordinates: + GEJSettings['Unit scale'] = unitScale + GEJSettings['Ostium diameter'] = ostiumDiameter + GEJSettings['Ostium length'] = ostiumLength + GEJSettings['Ostium wall thickness'] = ostiumWallThickness + GEJSettings['Ostium wall relative thicknesses'] = ostiumWallRelThicknesses + GEJSettings['Vessel inner diameter'] = vesselInnerDiameter + GEJSettings['Vessel wall thickness'] = vesselWallThickness + GEJSettings['Vessel wall relative thicknesses'] = vesselWallRelThicknesses + GEJSettings['Vessel angle 1 degrees'] = vesselAngle1 + GEJSettings['Vessel angle 2 degrees'] = vesselAngle2 # Create location of annulus xAnnulusOuter = [[] for x in range(elementsCountAroundEso)] @@ -1722,14 +1680,18 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d1AnnulusOuter = [] for n in range(elementsCountAroundEso): - d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundEso]) - d1AnnulusOuter.append(d) + v1 = xAnnulusOuter[n] + v2 = xAnnulusOuter[(n + 1) % elementsCountAroundEso] + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + d1 = [c * arcLengthAround for c in vector.normalise(d)] + d1AnnulusOuter.append(d1) + d1AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) d3Annulus = [] for n in range(elementsCountAroundEso): d3 = vector.normalise(vector.crossproduct3(vector.normalise(d1AnnulusOuter[n]), d2AnnulusNorm[n])) d3Annulus.append(d3) - # annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) # for m in range(len(xAnnulusOuter)): # node = nodes.createNode(nodeIdentifier, nodetemplate) @@ -1741,24 +1703,26 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # nodeIdentifier += 1 # Calculate arclength at quarter line between lesser and greater curvature for each region - xQuarterEllipseAll = [] - d2QuarterEllipseAll = [] - for n2 in range(len(xEllipseAroundAll)): - xQuarterEllipseAll.append(xEllipseAroundAll[n2][elementsAroundQuarterDuod]) - d2QuarterEllipseAll.append(d2EllipseAroundAll[n2][elementsAroundQuarterDuod]) - totalQuarterLength = interp.getCubicHermiteCurvesLength(xQuarterEllipseAll, d2QuarterEllipseAll) - - ratioArcLengthSections = [] - for i in range(len(nodeStartEndSections)): - xList = [] - d2List = [] - for n in range(nodeStartEndSections[i][0], nodeStartEndSections[i][1] + 1): - xList.append(xQuarterEllipseAll[n]) - d2List.append(d2QuarterEllipseAll[n]) - quarterLengthSection = interp.getCubicHermiteCurvesLength(xList, d2List) - ratioArcLengthSections.append(quarterLengthSection / totalQuarterLength) - - elementsAlongSections = [math.ceil(c / targetLength) for c in ratioArcLengthSections] + if not elementsAlongSections: + xQuarterEllipseAll = [] + d2QuarterEllipseAll = [] + for n2 in range(len(xEllipseAroundAll)): + xQuarterEllipseAll.append(xEllipseAroundAll[n2][elementsAroundQuarterDuod]) + d2QuarterEllipseAll.append(d2EllipseAroundAll[n2][elementsAroundQuarterDuod]) + totalQuarterLength = interp.getCubicHermiteCurvesLength(xQuarterEllipseAll, d2QuarterEllipseAll) + + ratioArcLengthSections = [] + for i in range(len(nodeStartEndSections)): + xList = [] + d2List = [] + for n in range(nodeStartEndSections[i][0], nodeStartEndSections[i][1] + 1): + xList.append(xQuarterEllipseAll[n]) + d2List.append(d2QuarterEllipseAll[n]) + quarterLengthSection = interp.getCubicHermiteCurvesLength(xList, d2List) + ratioArcLengthSections.append(quarterLengthSection / totalQuarterLength) + + elementsAlongSections = [math.ceil(c / targetLength) for c in ratioArcLengthSections] + totalElementsAlong = sum(elementsAlongSections) xSampledAlong = [[] for n1 in range(elementsCountAroundDuod)] @@ -2190,15 +2154,15 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio else: nodeIdxGC.append(idxMat[n2][n3][0]) - # for n2 in range(1, bodyStartIdx + 1): - # for n3 in range(len(idxMat[n2])): - # nodeIdxGC.append(idxMat[n2][n3][int(0.5 * len(xSampledAroundAlong[n2]))]) - # - # nodeIdxLC = [] - # for n2 in range(elementsAlongCardiaToDuod + 1): - # for n3 in range(len(idxMat[n2])): - # nodeIdxLC.append( - # idxMat[elementsAlongFundusApexToCardia + elementsAroundHalfEso - 2 + n2][n3][elementsAroundHalfDuod]) + for n2 in range(1, annulusFundusOpenRingIdx + 1): + for n3 in range(len(idxMat[n2])): + nodeIdxGC.append(idxMat[n2][n3][int(0.5 * len(xSampledAroundAlong[n2]))]) + + nodeIdxLC = [] + for n2 in range(annulusBodyOpenRingIdx, len(xSampledAroundAlong)): + for n3 in range(len(idxMat[n2])): + nodeIdxLC.append( + idxMat[n2][n3][elementsAroundHalfDuod]) for n2 in range(len(xList)): node = nodes.createNode(nodeIdentifier, nodetemplate) @@ -2520,273 +2484,60 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, coordinates=coordinates) - # elementIdxThroughWall = [] - # n = lastDuodenumElementIdentifier - 1 - # for n3 in range(elementsCountThroughWall): - # elementIdxAround = [] - # for n1 in range(elementsCountAroundEso): - # n += 1 - # elementIdxAround.append(n) - # elementIdxThroughWall.append(elementIdxAround) - # elementIdxMat.append(elementIdxThroughWall) - # - # # delete mucosa layer in fundus when there is a limiting ridge - # mesh_destroy_elements_and_nodes_by_identifiers(mesh, fundusMucosaElementIdentifiers) - # - # # Create annotation groups for dorsal and ventral parts of the stomach - # dorsalGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("dorsal stomach")) - # ventralGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("ventral stomach")) - # dorsalMeshGroup = dorsalGroup.getMeshGroup(mesh) - # ventralMeshGroup = ventralGroup.getMeshGroup(mesh) - # - # for e2 in range(len(elementIdxMat)): - # for e3 in range(len(elementIdxMat[e2])): - # for e1 in range(len(elementIdxMat[e2][e3])): - # elementIdx = elementIdxMat[e2][e3][e1] - # element = mesh.findElementByIdentifier(elementIdx) - # if e1 < 0.5 * len(elementIdxMat[e2][e3]): - # ventralMeshGroup.addElement(element) - # else: - # dorsalMeshGroup.addElement(element) - # if dorsalGroup not in allAnnotationGroups: - # allAnnotationGroups.append(dorsalGroup) - # if ventralGroup not in allAnnotationGroups: - # allAnnotationGroups.append(ventralGroup) - # - # nodesOnLCMargin = [] - # for n2 in range(elementsAlongEsophagus + 1): - # for n3 in range(elementsThroughEsophagusWall + 1): - # nodeIdxOnLCMargin = 1 + elementsAroundHalfEso + \ - # n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ - # n3 * elementsCountAroundEso - # nodesOnLCMargin.append(nodeIdxOnLCMargin) - # allNodesOnLC = nodesOnLCMargin + nodeIdxLC - # - # nearLCGroup = AnnotationGroup(region, ("elements adjacent to lesser curvature", "None")) - # - # elementIter = mesh.createElementiterator() - # element = elementIter.next() - # while element.isValid(): - # eft = element.getElementfieldtemplate(coordinates, -1) - # nodeIdentifiers = get_element_node_identifiers(element, eft) - # for n in range(len(nodeIdentifiers)): - # if nodeIdentifiers[n] in allNodesOnLC: - # nearLCGroup.getMeshGroup(mesh).addElement(element) - # break - # element = elementIter.next() - # allAnnotationGroups.append(nearLCGroup) - - # # Create split coordinate field - # if splitCoordinates: - # nodesOnSplitMargin = [] - # - # for n2 in range(elementsAlongEsophagus + 1): - # for n3 in range(elementsThroughEsophagusWall + 1): - # nodeIdxOnGCMargin = 1 + n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ - # n3 * elementsCountAroundEso - # nodesOnSplitMargin.append(nodeIdxOnGCMargin) - # nodeIdxOnLCMargin = 1 + elementsAroundHalfEso + \ - # n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ - # n3 * elementsCountAroundEso - # nodesOnSplitMargin.append(nodeIdxOnLCMargin) - # - # nodesOnSplitMargin += nodeIdxGC + nodeIdxLC - # - # splitCoordinates = findOrCreateFieldCoordinates(fm, name="split coordinates") - # splitNodetemplate1 = nodes.createNodetemplate() - # splitNodetemplate1.defineField(splitCoordinates) - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_VALUE, 1) - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - # if useCrossDerivatives: - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) - # if useCubicHermiteThroughWall: - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS3, 1) - # if useCrossDerivatives: - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) - # splitNodetemplate1.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) - # - # splitNodetemplate2 = nodes.createNodetemplate() - # splitNodetemplate2.defineField(splitCoordinates) - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_VALUE, 2) - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS1, 2) - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS2, 2) - # if useCrossDerivatives: - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 2) - # if useCubicHermiteThroughWall: - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D_DS3, 2) - # if useCrossDerivatives: - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 2) - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 2) - # splitNodetemplate2.setValueNumberOfVersions(splitCoordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 2) - # - # nodeIter = nodes.createNodeiterator() - # node = nodeIter.next() - # while node.isValid(): - # # if not markerPoints.containsNode(node): - # cache.setNode(node) - # identifier = node.getIdentifier() - # marginNode = identifier in nodesOnSplitMargin - # x = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, 3)[1] - # d1 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, 3)[1] - # d2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, 3)[1] - # if useCrossDerivatives: - # d1d2 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, 3)[1] - # if useCubicHermiteThroughWall: - # d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, 3)[1] - # if useCrossDerivatives: - # d1d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, 3)[1] - # d2d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, 3)[1] - # d1d2d3 = coordinates.getNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, 3)[1] - # - # node.merge(splitNodetemplate2 if marginNode else splitNodetemplate1) - # versionCount = 2 if marginNode else 1 - # for vn in range(versionCount): - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, vn + 1, x) - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, vn + 1, d1) - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, vn + 1, d2) - # if useCrossDerivatives: - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, vn + 1, d1d2) - # if useCubicHermiteThroughWall: - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, vn + 1, d3) - # if useCrossDerivatives: - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, vn + 1, d1d3) - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, vn + 1, d2d3) - # splitCoordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, vn + 1, d1d2d3) - # node = nodeIter.next() - # - # elementIter = mesh.createElementiterator() - # element = elementIter.next() - # splitElementtemplate1 = mesh.createElementtemplate() - # splitElementtemplate2 = mesh.createElementtemplate() - # - # count = 0 - # elementsInOstium = elementsCountAroundEso * elementsAlongEsophagus * elementsThroughEsophagusWall - # closedLoopElementId = nextElementIdentifier - elementsCountAroundEso * elementsCountAcrossCardia - \ - # elementsCountAroundDuod * elementsCountThroughWall * (elementsAlongCardiaToDuod + 1) - # - # allValueLabels = [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, - # Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3, - # Node.VALUE_LABEL_D2_DS2DS3, Node.VALUE_LABEL_D3_DS1DS2DS3] - # - # while element.isValid(): - # eft = element.getElementfieldtemplate(coordinates, -1) - # nodeIdentifiers = get_element_node_identifiers(element, eft) - # elementId = element.getIdentifier() - # marginDorsal = False - # for n in range(len(nodeIdentifiers)): - # marginElement = nodeIdentifiers[n] in nodesOnSplitMargin - # if marginElement: - # count += 1 - # if count < 3 and (elementId <= elementsInOstium or elementId > closedLoopElementId): - # marginDorsal = True - # elif count >= 3 and (elementId <= elementsInOstium or elementId > closedLoopElementId): - # if count == 4: - # count = 0 - # elif elementsInOstium < elementId < elementsInOstium + len(xOuter[0]) + 1: - # marginDorsal = True - # count = 0 - # elif elementsInOstium + len(xOuter[0]) < elementId < elementsInOstium + len(xOuter[0]) * 2 + 1: - # count = 0 - # elif count < 2 and elementId > elementsInOstium + 2 * (len(xOuter[0])): - # marginDorsal = True - # elif count >= 2 and elementId > elementsInOstium + 2 * (len(xOuter[0])): - # if count == 2: - # count = 0 - # break - # - # if marginDorsal: - # # Find nodes on margin to remap with version 2 - # lnRemapV2 = [] - # for n in range(len(nodeIdentifiers)): - # if nodeIdentifiers[n] in nodesOnSplitMargin: - # lnRemapV2.append(n + 1) - # eft2 = eft - # remapEftNodeValueLabelsVersion(eft2, lnRemapV2, allValueLabels, 2) - # - # splitElementtemplate2.defineField(splitCoordinates, -1, eft2) - # element.merge(splitElementtemplate2) - # element.setNodesByIdentifier(eft2, nodeIdentifiers) - # if eft2.getNumberOfLocalScaleFactors() > 0: - # element.setScaleFactor(eft2, 1, -1.0) - # else: - # splitElementtemplate1.defineField(splitCoordinates, -1, eft) - # element.merge(splitElementtemplate1) - # element.setNodesByIdentifier(eft, nodeIdentifiers) - # if eft.getNumberOfLocalScaleFactors() == 1: - # element.setScaleFactors(eft, [-1.0]) - # - # element = elementIter.next() - # - # allAnnotationGroups.append(nearLCGroup) - - nextNodeIdentifier = nodeIdentifier - nextElementIdentifier = elementIdentifier - - # for n2 in range(len(cxGroup)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxGroup[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd2Group[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd1Group[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, cd3Group[n2]) - # nodeIdentifier += 1 - - return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier - - -def findCentreOnCentralPathFromCrossAxisEndPt(xPoint, xCentralPath, dCentralPath): - """ - Find point on central path which intersects with cross axis endpoint. - :param xPoint: cross axis endpoint - :param xCentralPath: List of points on central path - :param dCentralPath: List of cross axis derivatives along central path - :return xPtOnCP: intersection point on central path - """ - arcLength = 0.0 - for n in range(len(xCentralPath) - 1): - arcLength += interp.getCubicHermiteArcLength(xCentralPath[n], dCentralPath[n], - xCentralPath[n + 1], dCentralPath[n + 1]) - arcLow = 0.0 - arcUp = arcLength - - for iter in range(100): - thetaLow = findThetaFromArcDistance(xPoint, arcLow, xCentralPath, dCentralPath) - thetaUp = findThetaFromArcDistance(xPoint, arcUp, xCentralPath, dCentralPath) - arcDistance = (arcLow + arcUp) * 0.5 - - if abs(thetaLow - thetaUp) < 1e-06: - xPtOnCP = interp.getCubicHermiteCurvesPointAtArcDistance(xCentralPath, dCentralPath, arcDistance)[0] - break - elif thetaLow > thetaUp: - arcLow = arcDistance - elif thetaLow < thetaUp: - arcUp = arcDistance - - if iter > 99: - print('Search for findCentreOnCentralPathFromCrossAxisEndPt - Max iters reached:', iter) - - return xPtOnCP - - -def findThetaFromArcDistance(xPt, arcDistance, xCentralPath, dCentralPath): - """ - Find angle between a vector between a guess point on the central path to a cross axis endpoint and the cross-axis - of the central path. - :param xPt: Cross axis endpoint - :param arcDistance: Arclength along central path where guess point sits - :param xCentralPath: List of points along central path - :param dCentralPath: List of cross axis derivatives along central path - :return theta: angle between vectors - """ - xGuess, dGuess = interp.getCubicHermiteCurvesPointAtArcDistance(xCentralPath, dCentralPath, arcDistance)[0:2] - if xGuess == xPt: - return 0.0 - else: - dxPt = findDerivativeBetweenPoints(xGuess, xPt) - cosTheta = vector.dotproduct(dGuess, dxPt) / (vector.magnitude(dGuess) * vector.magnitude(dxPt)) - if abs(cosTheta) > 1.0: - cosTheta = 1.0 if cosTheta > 0.0 else -1.0 - theta = abs(math.pi * 0.5 - math.acos(cosTheta)) - return theta + elementIdxThroughWall = [] + n = lastDuodenumElementIdentifier - 1 + for n3 in range(elementsCountThroughWall): + elementIdxAround = [] + for n1 in range(elementsCountAroundEso): + n += 1 + elementIdxAround.append(n) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + + # delete mucosa layer in fundus when there is a limiting ridge + mesh_destroy_elements_and_nodes_by_identifiers(mesh, fundusMucosaElementIdentifiers) + + # Create annotation groups for dorsal and ventral parts of the stomach + dorsalGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("dorsal stomach")) + ventralGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("ventral stomach")) + dorsalMeshGroup = dorsalGroup.getMeshGroup(mesh) + ventralMeshGroup = ventralGroup.getMeshGroup(mesh) + + for e2 in range(len(elementIdxMat)): + for e3 in range(len(elementIdxMat[e2])): + for e1 in range(len(elementIdxMat[e2][e3])): + elementIdx = elementIdxMat[e2][e3][e1] + element = mesh.findElementByIdentifier(elementIdx) + if e1 < 0.5 * len(elementIdxMat[e2][e3]): + ventralMeshGroup.addElement(element) + else: + dorsalMeshGroup.addElement(element) + if dorsalGroup not in allAnnotationGroups: + allAnnotationGroups.append(dorsalGroup) + if ventralGroup not in allAnnotationGroups: + allAnnotationGroups.append(ventralGroup) + + nodesOnLCMargin = [] + for n2 in range(elementsAlongEsophagus + 1): + for n3 in range(elementsThroughEsophagusWall + 1): + nodeIdxOnLCMargin = 1 + elementsAroundHalfEso + \ + n2 * (elementsThroughEsophagusWall + 1) * elementsCountAroundEso + \ + n3 * elementsCountAroundEso + nodesOnLCMargin.append(nodeIdxOnLCMargin) + allNodesOnLC = nodesOnLCMargin + nodeIdxLC + + nearLCGroup = AnnotationGroup(region, ("elements adjacent to lesser curvature", "None")) + + elementIter = mesh.createElementiterator() + element = elementIter.next() + while element.isValid(): + eft = element.getElementfieldtemplate(coordinates, -1) + nodeIdentifiers = get_element_node_identifiers(element, eft) + for n in range(len(nodeIdentifiers)): + if nodeIdentifiers[n] in allNodesOnLC: + nearLCGroup.getMeshGroup(mesh).addElement(element) + break + element = elementIter.next() + allAnnotationGroups.append(nearLCGroup) + + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongSections From 140fa60240963140fef9c0404550bdc9fec97b34 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 11 Aug 2023 13:04:19 +1200 Subject: [PATCH 18/30] Fix linear mapping at corners around annulus --- .../meshtypes/meshtype_3d_stomach1.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 3e185a42..d5467db5 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1755,6 +1755,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio aPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[s][n1], startGuessPosition) aProportion = trackSurfaceStomach.getProportion(aPosition) + # endDerivative = d2EllipseAroundAll[s][n1] if i == 1 else None + if i == 0 and n1 in n1IdxAtBodyStartIdxPlusMinusOne: bPosition = xAnnulusOuterPosition[annulusIdxAtBodyStartIdxMinusOne[count]] elementsOut = elementsAlongSections[i] - (elementsAroundQuarterEso - 1) @@ -1767,6 +1769,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx, nd1, nd2, nd3, proportions = trackSurfaceStomach.createHermiteCurvePoints( aProportion[0], aProportion[1], bProportion[0], bProportion[1], elementsOut, + # derivativeEnd=endDerivative, curveMode=TrackSurface.HermiteCurveMode.UNIFORM_SIZE) nx, nd1, nd2, nd3 = \ @@ -2292,7 +2295,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio if e2 == annulusFundusOpenRingIdx - 2: if e1 == elementsAroundHalfDuod - 2: + scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) @@ -2326,6 +2333,42 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + if e2 == annulusFundusOpenRingIdx - 1: + if e1 == elementsAroundHalfDuod - 2: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod - 1: + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + if e2 == annulusBodyOpenRingIdx: + if e1 == elementsAroundHalfDuod - 2: + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsAroundHalfDuod - 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2336,6 +2379,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2362,7 +2407,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementtemplate1 = elementtemplateX elif e1 == elementsAroundHalfDuod + 1: + scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) From 42a17aa085b4b8a49a5ecb97e03df3815be3f8b6 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 11 Aug 2023 16:30:41 +1200 Subject: [PATCH 19/30] Make smooth curves from apex to annulus and annulus to body --- .../meshtypes/meshtype_3d_stomach1.py | 77 +++++++++++++++---- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index d5467db5..d09046ee 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -667,7 +667,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Number of elements through wall'] = 1 options['Wall thickness'] = 0.0525 * 101 elif 'Mouse 1' in parameterSetName: - options['Number of elements around duodenum'] = 16 options['Wall thickness'] = 0.05145 options['Mucosa relative thickness'] = 0.75 options['Submucosa relative thickness'] = 0.05 @@ -675,7 +674,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.05 options['Limiting ridge'] = True elif 'Pig 1' in parameterSetName: - options['Number of elements around duodenum'] = 16 + options['Target element unit length'] = 0.07 options['Wall thickness'] = 0.059 options['Mucosa relative thickness'] = 0.47 options['Submucosa relative thickness'] = 0.1 @@ -683,7 +682,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.1 options['Limiting ridge'] = False elif 'Rat 1' in parameterSetName: - options['Number of elements around duodenum'] = 16 options['Wall thickness'] = 0.0215 options['Mucosa relative thickness'] = 0.65 options['Submucosa relative thickness'] = 0.12 @@ -691,7 +689,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.05 options['Limiting ridge'] = True elif 'Material' in parameterSetName: - options['Number of elements around duodenum'] = 16 options['Wall thickness'] = 0.05 options['Mucosa relative thickness'] = 0.25 options['Submucosa relative thickness'] = 0.25 @@ -1745,35 +1742,81 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # do a tracksurface sampling to divide the elements into equal sized elements while keeping the start and # end derivatives direction at both pts elementsOut = elementsAlongSections[i] + startDerivative = None + startDerivativeMag = None + endDerivative = None + endDerivativeMag = None + if i == 1 and n1 in n1IdxAtBodyStartIdxPlusMinusOne: + # find endDerivative by spacing elements out evenly as though there is no ostium + startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * n1, + 1.0 / len(xEllipseAroundAll) * s) + aPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[s][n1], startGuessPosition) + aProportion = trackSurfaceStomach.getProportion(aPosition) + + startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * n1, + 1.0 / len(xEllipseAroundAll) * sNext) + bPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[sNext][n1], startGuessPosition) + bProportion = trackSurfaceStomach.getProportion(bPosition) + nx, nd1, nd2, nd3, proportions = trackSurfaceStomach.createHermiteCurvePoints( + aProportion[0], aProportion[1], bProportion[0], bProportion[1], elementsOut, + curveMode=TrackSurface.HermiteCurveMode.UNIFORM_SIZE) + d2Uniform = \ + trackSurfaceStomach.resampleHermiteCurvePointsSmooth(nx, nd1, nd2, nd3, proportions)[1] + endDerivative = d2Uniform[-1] + endDerivativeMag = vector.magnitude(endDerivative) + + # Sample from apex to annulus aPosition = xAnnulusOuterPosition[annulusIdxAtBodyStartIdxPlusOne[count]] - count += 1 + startDerivative = d2AnnulusOuter[annulusIdxAtBodyStartIdxPlusOne[count]] elementsOut = elementsAlongSections[i] - (elementsAroundQuarterEso - 1) + count += 1 else: startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0/elementsCountAroundDuod * n1, 1.0/len(xEllipseAroundAll) * s) aPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[s][n1], startGuessPosition) aProportion = trackSurfaceStomach.getProportion(aPosition) - # endDerivative = d2EllipseAroundAll[s][n1] if i == 1 else None - if i == 0 and n1 in n1IdxAtBodyStartIdxPlusMinusOne: + # find startDerivative by spacing elements out evenly as though there is no ostium + startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * n1, + 1.0 / len(xEllipseAroundAll) * sNext) + bPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[sNext][n1], startGuessPosition) + bProportion = trackSurfaceStomach.getProportion(bPosition) + nx, nd1, nd2, nd3, proportions = trackSurfaceStomach.createHermiteCurvePoints( + aProportion[0], aProportion[1], bProportion[0], bProportion[1], elementsOut, + curveMode=TrackSurface.HermiteCurveMode.UNIFORM_SIZE) + d2Uniform = \ + trackSurfaceStomach.resampleHermiteCurvePointsSmooth(nx, nd1, nd2, nd3, proportions)[1] + startDerivative = d2Uniform[0] + startDerivativeMag = vector.magnitude(startDerivative) + + # Sample from apex to annulus bPosition = xAnnulusOuterPosition[annulusIdxAtBodyStartIdxMinusOne[count]] + d = d2AnnulusOuter[annulusIdxAtBodyStartIdxMinusOne[count]] + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[annulusIdxAtBodyStartIdxMinusOne[count]], + math.pi) + endDerivative = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] + for j in range(3)] elementsOut = elementsAlongSections[i] - (elementsAroundQuarterEso - 1) count += 1 + else: startGuessPosition = trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * n1, 1.0 / len(xEllipseAroundAll) * sNext) bPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[sNext][n1], startGuessPosition) + bProportion = trackSurfaceStomach.getProportion(bPosition) nx, nd1, nd2, nd3, proportions = trackSurfaceStomach.createHermiteCurvePoints( aProportion[0], aProportion[1], bProportion[0], bProportion[1], elementsOut, - # derivativeEnd=endDerivative, + derivativeStart=startDerivative, derivativeEnd=endDerivative, curveMode=TrackSurface.HermiteCurveMode.UNIFORM_SIZE) nx, nd1, nd2, nd3 = \ - trackSurfaceStomach.resampleHermiteCurvePointsSmooth(nx, nd1, nd2, nd3, proportions)[:-1] + trackSurfaceStomach.resampleHermiteCurvePointsSmooth(nx, nd1, nd2, nd3, proportions, + derivativeMagnitudeStart=startDerivativeMag, + derivativeMagnitudeEnd=endDerivativeMag)[:-1] # Rotate nd2 for m in range(len(nx)): @@ -2301,7 +2344,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2312,7 +2355,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2321,7 +2364,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) @@ -2332,7 +2375,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) @@ -2378,7 +2421,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) @@ -2389,7 +2432,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) @@ -2402,7 +2445,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2413,7 +2456,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX From 02d81a639f0c8ca29c7ba4272d28d5e4e41c3f97 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 14 Aug 2023 15:01:14 +1200 Subject: [PATCH 20/30] Allow refinement of cardia surface elements --- .../meshtypes/meshtype_3d_stomach1.py | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index d09046ee..78d1f295 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -11,7 +11,8 @@ from cmlibs.maths.vectorops import cross, sub from cmlibs.utils.zinc.field import find_or_create_field_coordinates -from cmlibs.utils.zinc.finiteelement import get_element_node_identifiers, get_maximum_node_identifier +from cmlibs.utils.zinc.finiteelement import get_element_node_identifiers, get_maximum_element_identifier, \ + get_maximum_node_identifier from cmlibs.utils.zinc.general import ChangeManager from cmlibs.zinc.element import Element from cmlibs.zinc.field import Field @@ -661,6 +662,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Use linear through wall': True, 'Refine': False, 'Refine number of elements surface': 4, + 'Refine number of elements cardia surface': 2, 'Refine number of elements through wall': 1 } if 'Human 2' in parameterSetName: @@ -717,6 +719,7 @@ def getOrderedOptionNames(): 'Use linear through wall', 'Refine', 'Refine number of elements surface', + 'Refine number of elements cardia surface', 'Refine number of elements through wall'] @classmethod @@ -778,6 +781,7 @@ def checkOptions(cls, options): options['Number of elements through wall'] = 4 for key in [ 'Refine number of elements surface', + 'Refine number of elements cardia surface', 'Refine number of elements through wall']: if options[key] < 1: options[key] = 1 @@ -921,11 +925,32 @@ def refineMesh(cls, meshrefinement, options): """ refineElementsCountAround = options['Refine number of elements surface'] refineElementsCountAlong = options['Refine number of elements surface'] + refineElementsCountAlongCardia = options['Refine number of elements cardia surface'] refineElementsCountThroughWall = options['Refine number of elements through wall'] - meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, - refineElementsCountThroughWall) - return + sourceFm = meshrefinement._sourceFm + annotationGroups = meshrefinement._sourceAnnotationGroups + cardiaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("cardia of stomach")) + cardiaMeshGroup = cardiaGroup.getMeshGroup(meshrefinement._sourceMesh) + + lastElementIdentifier = get_maximum_element_identifier(meshrefinement._sourceMesh) + + cache = sourceFm.createFieldcache() + element = meshrefinement._sourceElementiterator.next() + while element.isValid(): + elementIdentifier = element.getIdentifier() + refineElements1 = refineElementsCountAround + refineElements2 = refineElementsCountAlong + refineElements3 = refineElementsCountThroughWall + cache.setElement(element) + if cardiaMeshGroup.containsElement(element): + refineElements2 = refineElementsCountAlongCardia + + meshrefinement.refineElementCubeStandard3d(element, refineElements1, refineElements2, refineElements3) + if elementIdentifier == lastElementIdentifier: + return # finish on last so can continue elsewhere + element = meshrefinement._sourceElementiterator.next() + @classmethod def defineFaceAnnotations(cls, region, options, annotationGroups): From 8457280e3afbba051a814c73592308df22564bb3 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 14 Aug 2023 16:25:15 +1200 Subject: [PATCH 21/30] Allow number of elements along stomach --- .../meshtypes/meshtype_3d_stomach1.py | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 78d1f295..cba5b2d6 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -650,7 +650,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Central path': copy.deepcopy(centralPathOption), 'Number of elements around esophagus': 8, 'Number of elements around duodenum': 16, - 'Target element unit length': 0.1, + 'Number of elements along': 14, 'Number of elements through wall': 4, 'Wall thickness': 0.0525, 'Mucosa relative thickness': 0.55, @@ -669,6 +669,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Number of elements through wall'] = 1 options['Wall thickness'] = 0.0525 * 101 elif 'Mouse 1' in parameterSetName: + options['Number of elements along'] = 12 options['Wall thickness'] = 0.05145 options['Mucosa relative thickness'] = 0.75 options['Submucosa relative thickness'] = 0.05 @@ -676,7 +677,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.05 options['Limiting ridge'] = True elif 'Pig 1' in parameterSetName: - options['Target element unit length'] = 0.07 options['Wall thickness'] = 0.059 options['Mucosa relative thickness'] = 0.47 options['Submucosa relative thickness'] = 0.1 @@ -707,7 +707,7 @@ def getOrderedOptionNames(): 'Central path', 'Number of elements around esophagus', 'Number of elements around duodenum', - 'Target element unit length', + 'Number of elements along', 'Number of elements through wall', 'Wall thickness', 'Mucosa relative thickness', @@ -777,6 +777,8 @@ def checkOptions(cls, options): 'Number of elements around duodenum']: if options[key] % 4 > 0: options[key] = options[key] // 4 * 4 + if options['Number of elements along'] < 10: + options['Number of elements along'] = 10 if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 for key in [ @@ -1327,7 +1329,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio """ elementsCountAroundEso = options['Number of elements around esophagus'] elementsCountAroundDuod = options['Number of elements around duodenum'] - targetLength = options['Target element unit length'] + elementsCountAlong = options['Number of elements along'] elementsCountThroughWall = options['Number of elements through wall'] mucosaRelThickness = options['Mucosa relative thickness'] submucosaRelThickness = options['Submucosa relative thickness'] @@ -1743,7 +1745,22 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio quarterLengthSection = interp.getCubicHermiteCurvesLength(xList, d2List) ratioArcLengthSections.append(quarterLengthSection / totalQuarterLength) - elementsAlongSections = [math.ceil(c / targetLength) for c in ratioArcLengthSections] + elementsAlongSections = [math.floor(c * elementsCountAlong) for c in ratioArcLengthSections] + + modGroups = [] + for i in range(len(elementsAlongSections)): + if elementsAlongSections[i] < 1: + elementsAlongSections[i] == 1 + + mod = ratioArcLengthSections[i] * elementsCountAlong - elementsAlongSections[i] + modGroups.append(mod) + + excessElements = elementsCountAlong - sum(elementsAlongSections) + + for i in range(excessElements): + maxIdx = max(range(len(modGroups)), key=modGroups.__getitem__) + elementsAlongSections[maxIdx] += 1 + modGroups[maxIdx] = ratioArcLengthSections[maxIdx] * elementsCountAlong - elementsAlongSections[maxIdx] totalElementsAlong = sum(elementsAlongSections) From 43f94fff73c20dd2f3459e16a27b36eac3cc93e2 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Tue, 15 Aug 2023 13:13:41 +1200 Subject: [PATCH 22/30] Update mouse central path for apex and flatter duodenum --- .../meshtypes/meshtype_3d_stomach1.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index cba5b2d6..083657ce 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -181,18 +181,18 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.42,0.72,0.00], [0.04,-0.04,0.00], [0.07,0.03,0.00], [0.14,0.03,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), - (2, [[0.46,0.65,0.00], [0.03,-0.10,0.00], [0.19,0.04,0.00], [0.10,-0.01,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), - (3, [[0.48,0.53,0.00], [0.01,-0.15,0.00], [0.26,-0.00,0.00], [0.06,-0.07,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), - (4, [[0.47,0.36,0.00], [-0.04,-0.17,0.00], [0.30,-0.12,0.00], [0.02,-0.12,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), + (1, [[0.54,0.71,0.00], [-0.01,-0.06,0.00], [0.08,-0.01,0.00], [0.10,-0.02,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), + (2, [[0.53,0.63,0.00], [-0.01,-0.10,0.00], [0.17,-0.03,0.00], [0.08,-0.02,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), + (3, [[0.51,0.52,0.00], [-0.03,-0.14,0.00], [0.24,-0.06,0.00], [0.07,-0.04,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), + (4, [[0.47,0.36,0.00], [-0.05,-0.16,0.00], [0.30,-0.12,0.00], [0.03,-0.09,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), (5, [[0.40,0.20,0.00], [-0.11,-0.15,0.00], [0.29,-0.24,0.00], [-0.05,-0.11,0.00], [0.00,0.00,0.38], [0.00,0.00,0.02]]), (6, [[0.26,0.08,0.00], [-0.20,-0.11,0.00], [0.19,-0.34,0.00], [-0.13,-0.08,0.00], [0.00,0.00,0.39], [0.00,0.00,0.00]]), (7, [[0.00,0.00,0.00], [-0.29,-0.01,0.00], [0.01,-0.40,0.00], [-0.19,0.01,0.00], [0.00,0.00,0.38], [0.00,0.00,-0.01]]), - (8, [[-0.29,0.07,0.00], [-0.24,0.13,0.00], [-0.20,-0.32,0.00], [-0.11,0.10,0.00], [0.00,0.00,0.36], [0.01,0.00,-0.03]]), - (9, [[-0.46,0.24,-0.00], [-0.09,0.19,0.00], [-0.23,-0.21,0.00], [0.02,0.12,0.00], [0.01,0.00,0.32], [-0.00,0.00,-0.08]]), - (10, [[-0.48,0.42,0.00], [-0.01,0.16,0.00], [-0.17,-0.08,0.00], [0.07,0.09,0.00], [0.00,0.00,0.21], [-0.00,0.00,-0.09]]), - (11, [[-0.48,0.56,0.00], [-0.03,0.14,0.00], [-0.10,-0.02,0.00], [0.03,0.01,0.00], [0.00,0.00,0.13], [0.00,0.00,-0.04]]), - (12, [[-0.53,0.69,0.00], [-0.07,0.12,0.00], [-0.10,-0.06,0.00], [-0.03,-0.09,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) + (8, [[-0.29,0.07,0.00], [-0.24,0.13,0.00], [-0.20,-0.32,0.00], [-0.11,0.10,0.00], [0.00,0.00,0.36], [0.00,0.00,-0.03]]), + (9, [[-0.46,0.23,0.00], [-0.10,0.19,0.00], [-0.23,-0.21,0.00], [0.02,0.12,0.00], [0.00,0.00,0.32], [0.00,0.00,-0.08]]), + (10, [[-0.48,0.42,0.00], [-0.01,0.17,0.00], [-0.17,-0.08,0.00], [0.07,0.09,0.00], [0.00,0.00,0.21], [0.00,0.00,-0.09]]), + (11, [[-0.48,0.56,0.00], [-0.01,0.14,0.00], [-0.10,-0.02,0.00], [0.03,0.02,0.00], [0.00,0.00,0.13], [0.00,0.00,-0.05]]), + (12, [[-0.51,0.70,0.00], [-0.04,0.14,0.00], [-0.11,-0.04,0.00], [-0.05,-0.06,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) ]), 'userAnnotationGroups': [ @@ -1631,7 +1631,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) # Visualise track surface - # tmpRegion = region.createRegion() # nodeIdentifier, elementIdentifier = trackSurfaceStomach.generateMesh(region) # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction @@ -1806,9 +1805,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d2Uniform = \ trackSurfaceStomach.resampleHermiteCurvePointsSmooth(nx, nd1, nd2, nd3, proportions)[1] endDerivative = d2Uniform[-1] - endDerivativeMag = vector.magnitude(endDerivative) - # Sample from apex to annulus + # Sample from annulus to body aPosition = xAnnulusOuterPosition[annulusIdxAtBodyStartIdxPlusOne[count]] startDerivative = d2AnnulusOuter[annulusIdxAtBodyStartIdxPlusOne[count]] elementsOut = elementsAlongSections[i] - (elementsAroundQuarterEso - 1) @@ -1984,6 +1982,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2SmoothedAlongLC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + d2SmoothedAlongLC[0] = vector.setMagnitude(d2SmoothedAlongLC[0], 0.5*(vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso]) + (vector.magnitude(d2SmoothedAlongLC[0])))) @@ -2673,5 +2672,5 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio break element = elementIter.next() allAnnotationGroups.append(nearLCGroup) - + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongSections From 1aad9537d3f70d68812c52a400c9ccc0627e58b1 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Tue, 15 Aug 2023 15:31:51 +1200 Subject: [PATCH 23/30] Update number of elements for parameter sets --- .../meshtypes/meshtype_3d_stomach1.py | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 083657ce..ceaa4fff 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -125,13 +125,13 @@ class MeshType_3d_stomach1(Scaffold_base): (4, [[62.470,-113.500,1134.220], [0.315,-6.148,-9.733], [35.400,-3.370,3.270], [4.541,-0.488,0.325], [-5.330,-34.800,21.800], [-0.383,-3.012,1.219]]), (5, [[62.940,-120.610,1122.780], [0.448,-8.598,-13.993], [39.520,-4.010,3.730], [3.189,-0.587,-0.295], [-5.970,-37.560,22.890], [-0.099,-1.218,0.549]]), (6, [[63.320,-130.670,1106.220], [-0.184,-10.489,-16.967], [41.370,-4.520,2.350], [0.495,-2.468,-4.032], [-5.290,-36.560,22.660], [0.257,0.762,0.246]]), - (7, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.801], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), + (7, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.800], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), (8, [[53.670,-152.880,1069.820], [-15.955,-9.817,-16.265], [30.765,-14.468,-15.598], [-14.187,-3.408,-7.577], [-3.580,-35.330,24.820], [2.031,4.346,-1.238]]), - (9, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.623], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), - (10, [[10.360,-162.050,1054.830], [-21.091,1.023,-0.270], [-0.460,-14.000,-17.230], [-8.753,2.830,4.765], [-1.070,-18.150,14.780], [-1.004,7.491,-3.259]]), - (11, [[-8.740,-158.280,1057.630], [-14.760,6.591,2.223], [-6.110,-10.230,-10.220], [-2.404,4.122,5.111], [-3.260,-12.000,13.950], [-1.432,6.623,-3.360]]), - (12, [[-18.830,-150.690,1059.200], [-11.483,11.369,1.057], [-6.410,-5.880,-6.340], [-0.423,3.102,2.580], [-4.200,-5.070,8.950], [-1.380,4.802,-2.401]]), - (13, [[-30.740,-135.240,1059.320], [-12.232,19.364,-0.810], [-7.020,-4.680,-5.740], [-0.797,-0.702,-1.380], [-6.250,-3.510,10.510], [-2.720,-1.682,5.521]]) + (9, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.624], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), + (10, [[10.360,-162.050,1054.830], [-21.098,1.023,-0.272], [-0.460,-14.000,-17.230], [-8.754,2.830,4.764], [-1.070,-18.150,14.780], [-1.003,7.491,-3.260]]), + (11, [[-8.740,-158.280,1057.630], [-17.280,7.584,3.006], [-6.110,-10.230,-10.220], [-2.634,4.430,6.290], [-3.260,-12.000,13.950], [-1.380,7.085,-2.660]]), + (12, [[-23.259,-147.625,1060.642], [-11.148,12.211,0.633], [-5.944,-5.188,-4.599], [-0.696,3.015,1.714], [-3.887,-4.046,9.590], [-2.080,5.832,-2.463]]), + (13, [[-30.740,-135.240,1059.320], [-3.618,11.918,-3.109], [-7.329,-3.791,-6.004], [-2.074,-0.221,-4.524], [-7.127,0.091,8.642], [-4.400,2.442,0.567]]) ]), 'userAnnotationGroups': [ @@ -241,7 +241,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of elements': 10 }, 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [[0.44,0.01,0.00], [-0.01,-0.00,0.00], [0.01,-0.05,0.00], [-0.01,-0.09,0.00], [0.00,0.00,0.08], [0.00,0.00,0.06]]), (2, [[0.42,0.01,0.00], [-0.05,-0.01,0.00], [-0.00,-0.15,0.00], [-0.00,-0.10,0.00], [0.00,0.00,0.15], [0.00,0.00,0.08]]), (3, [[0.33,0.00,0.00], [-0.11,-0.00,0.00], [0.00,-0.28,0.00], [-0.00,-0.13,0.00], [0.00,0.00,0.28], [0.00,0.00,0.12]]), @@ -303,18 +303,18 @@ class MeshType_3d_stomach1(Scaffold_base): 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [[0.492,0.623,0.000], [0.003,-0.035,0.000], [0.060,-0.002,0.000], [0.118,0.016,0.000], [0.000,0.000,0.080], [0.000,0.000,0.077]]), - (2, [[0.490,0.553,0.000], [-0.008,-0.105,0.000], [0.180,-0.006,0.000], [0.122,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.083]]), - (3, [[0.475,0.414,0.000], [-0.038,-0.151,0.000], [0.308,-0.071,0.000], [0.077,-0.090,0.000], [0.000,0.000,0.250], [0.000,0.000,0.072]]), - (4, [[0.409,0.256,0.000], [-0.082,-0.143,0.000], [0.324,-0.191,0.000], [-0.028,-0.116,0.000], [0.000,0.000,0.300], [0.000,0.000,0.040]]), - (5, [[0.315,0.129,0.000], [-0.120,-0.114,0.000], [0.256,-0.304,0.000], [-0.090,-0.100,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), + (2, [[0.490,0.553,0.000], [-0.007,-0.105,0.000], [0.180,-0.006,0.000], [0.122,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.083]]), + (3, [[0.475,0.414,0.000], [-0.039,-0.151,0.000], [0.308,-0.071,0.000], [0.077,-0.090,0.000], [0.000,0.000,0.250], [0.000,0.000,0.072]]), + (4, [[0.409,0.256,0.000], [-0.082,-0.144,0.000], [0.324,-0.191,0.000], [-0.028,-0.116,0.000], [0.000,0.000,0.300], [0.000,0.000,0.040]]), + (5, [[0.315,0.129,0.000], [-0.121,-0.114,0.000], [0.256,-0.304,0.000], [-0.090,-0.100,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), (6, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.059,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), (7, [[0.000,0.000,0.000], [-0.200,0.002,0.000], [0.005,-0.420,0.000], [-0.156,0.002,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), - (8, [[-0.218,0.048,0.000], [-0.209,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), - (9, [[-0.404,0.184,0.000], [-0.146,0.182,0.000], [-0.299,-0.260,0.000], [-0.056,0.122,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), - (10, [[-0.511,0.392,0.000], [-0.040,0.210,0.000], [-0.259,-0.148,0.000], [0.080,0.105,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), - (11, [[-0.490,0.587,0.000], [-0.014,0.157,0.000], [-0.152,-0.045,0.000], [0.076,0.039,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), - (12, [[-0.516,0.708,0.000], [-0.031,0.116,0.000], [-0.111,-0.036,0.000], [0.009,-0.000,0.000], [0.000,0.000,0.120], [0.000,0.000,0.015]]), - (13, [[-0.552,0.820,0.000], [-0.041,0.107,0.000], [-0.132,-0.045,0.000], [-0.050,-0.018,0.000], [0.000,0.000,0.150], [0.000,0.000,0.045]]) + (8, [[-0.218,0.048,0.000], [-0.208,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), + (9, [[-0.404,0.184,0.000], [-0.152,0.178,0.000], [-0.299,-0.260,0.000], [-0.056,0.122,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), + (10, [[-0.511,0.392,0.000], [-0.040,0.213,0.000], [-0.259,-0.148,0.000], [0.080,0.105,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), + (11, [[-0.490,0.587,0.000], [-0.011,0.172,0.000], [-0.152,-0.045,0.000], [0.076,0.039,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), + (12, [[-0.523,0.730,0.000], [-0.032,0.117,0.000], [-0.111,-0.036,0.000], [0.009,-0.000,0.000], [0.000,0.000,0.120], [0.000,0.000,0.015]]), + (13, [[-0.552,0.820,0.000], [-0.025,0.063,0.000], [-0.132,-0.045,0.000], [-0.050,-0.018,0.000], [0.000,0.000,0.150], [0.000,0.000,0.045]]) ]), 'userAnnotationGroups': [ @@ -427,7 +427,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of vessels': 1, 'Number of elements across common': 2, 'Number of elements around ostium': 8, - 'Number of elements along': 2, + 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.0105, 'Outlet': False, @@ -458,7 +458,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of vessels': 1, 'Number of elements across common': 2, 'Number of elements around ostium': 8, - 'Number of elements along': 2, + 'Number of elements along': 3, 'Number of elements through wall': 1, 'Unit scale': 0.0105 * 101, 'Outlet': False, @@ -489,7 +489,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of vessels': 1, 'Number of elements across common': 2, 'Number of elements around ostium': 8, - 'Number of elements along': 2, + 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.147, 'Outlet': False, @@ -520,7 +520,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of vessels': 1, 'Number of elements across common': 2, 'Number of elements around ostium': 8, - 'Number of elements along': 2, + 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.0118, 'Outlet': False, @@ -551,7 +551,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of vessels': 1, 'Number of elements across common': 2, 'Number of elements around ostium': 8, - 'Number of elements along': 2, + 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.043, 'Outlet': False, @@ -582,7 +582,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of vessels': 1, 'Number of elements across common': 2, 'Number of elements around ostium': 8, - 'Number of elements along': 2, + 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 1.0, 'Outlet': False, @@ -648,9 +648,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): options = { 'Central path': copy.deepcopy(centralPathOption), - 'Number of elements around esophagus': 8, - 'Number of elements around duodenum': 16, - 'Number of elements along': 14, + 'Number of elements around esophagus': 12, + 'Number of elements around duodenum': 20, + 'Number of elements along': 24, 'Number of elements through wall': 4, 'Wall thickness': 0.0525, 'Mucosa relative thickness': 0.55, @@ -669,7 +669,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Number of elements through wall'] = 1 options['Wall thickness'] = 0.0525 * 101 elif 'Mouse 1' in parameterSetName: - options['Number of elements along'] = 12 + options['Number of elements along'] = 20 options['Wall thickness'] = 0.05145 options['Mucosa relative thickness'] = 0.75 options['Submucosa relative thickness'] = 0.05 @@ -684,6 +684,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.1 options['Limiting ridge'] = False elif 'Rat 1' in parameterSetName: + options['Number of elements along'] = 20 options['Wall thickness'] = 0.0215 options['Mucosa relative thickness'] = 0.65 options['Submucosa relative thickness'] = 0.12 @@ -691,6 +692,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.05 options['Limiting ridge'] = True elif 'Material' in parameterSetName: + options['Number of elements along'] = 20 options['Wall thickness'] = 0.05 options['Mucosa relative thickness'] = 0.25 options['Submucosa relative thickness'] = 0.25 @@ -2672,5 +2674,5 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio break element = elementIter.next() allAnnotationGroups.append(nearLCGroup) - + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongSections From d1126084148aa3f180fadccb865cb8417c83eade Mon Sep 17 00:00:00 2001 From: mlin865 Date: Tue, 15 Aug 2023 15:55:11 +1200 Subject: [PATCH 24/30] Update unit tests --- tests/test_general.py | 2 +- tests/test_stomach.py | 65 +++++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/tests/test_general.py b/tests/test_general.py index 3d18d716..fceb71ef 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -438,7 +438,7 @@ def test_deletion(self): annotationGroups = scaffoldPackage.getAnnotationGroups() self.assertEqual(73, len(annotationGroups)) scaffoldPackage.deleteElementsInRanges(region, [[313, 496]]) - self.assertEqual(600, mesh3d.getSize()) + self.assertEqual(1896, mesh3d.getSize()) element = mesh3d.findElementByIdentifier(400) self.assertFalse(element.isValid()) diff --git a/tests/test_stomach.py b/tests/test_stomach.py index 9bb9584f..2249dc3f 100644 --- a/tests/test_stomach.py +++ b/tests/test_stomach.py @@ -28,15 +28,15 @@ def test_stomach1(self): parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Mouse 1", "Pig 1", "Rat 1", "Material"]) options = scaffold.getDefaultOptions("Rat 1") - self.assertEqual(16, len(options)) - self.assertEqual(16, options.get("Number of elements around duodenum")) - self.assertEqual(6, options.get("Number of elements between cardia and duodenum")) + self.assertEqual(17, len(options)) + self.assertEqual(20, options.get("Number of elements around duodenum")) + self.assertEqual(20, options.get("Number of elements along")) self.assertEqual(0.0215, options.get("Wall thickness")) self.assertEqual(True, options.get("Limiting ridge")) - ostiumOptions = options['Gastro-esophagal junction'] + ostiumOptions = options['Gastro-esophageal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() self.assertEqual(1, ostiumSettings.get("Number of vessels")) - self.assertEqual(8, ostiumSettings.get("Number of elements around ostium")) + self.assertEqual(12, ostiumSettings.get("Number of elements around ostium")) self.assertEqual(4, ostiumSettings.get("Number of elements through wall")) self.assertEqual(5.0, ostiumSettings.get("Ostium diameter")) self.assertEqual(5.0, ostiumSettings.get("Ostium length")) @@ -56,26 +56,26 @@ def test_stomach1(self): fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) - self.assertEqual(810, mesh3d.getSize()) + self.assertEqual(1572, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) - self.assertEqual(2695, mesh2d.getSize()) + self.assertEqual(5208, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) - self.assertEqual(2964, mesh1d.getSize()) + self.assertEqual(5706, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(1099, nodes.getSize()) + self.assertEqual(2090, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [0.475, -0.4440296937068191, -0.37800000000001466], 1.0E-6) - assertAlmostEqualList(self, maximums, [1.9665783603056544, 0.867, 0.37800000000001466], 1.0E-6) + assertAlmostEqualList(self, minimums, [-0.77, -0.42, -0.36293353103307363], 1.0E-6) + assertAlmostEqualList(self, maximums, [0.780854631116736, 0.8713406657835177, 0.3629335310330727], 1.0E-6) stomachCoordinates = fieldmodule.findFieldByName("stomach coordinates").castFiniteElement() minimums, maximums = evaluateFieldNodesetRange(stomachCoordinates, nodes) - assertAlmostEqualList(self, minimums, [0.0, -0.509814453125, -0.509814453125], 1.0E-4) - assertAlmostEqualList(self, maximums, [2.0, 0.8001543944920241, 0.509814453125], 1.0E-4) + assertAlmostEqualList(self, minimums, [-1.3, -0.5014130864747104, -0.5014130864747104], 1.0E-4) + assertAlmostEqualList(self, maximums, [0.7, 0.8, 0.5014130864747104], 1.0E-4) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -87,21 +87,21 @@ def test_stomach1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 4.2162907021158285, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 4.109097109853743, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 0.05913279323188687, delta=1.0E-6) + self.assertAlmostEqual(volume, 0.05866824043828919, delta=1.0E-6) # check some annotationGroups: expectedSizes3d = { - "body of stomach": 248, - "esophagus": 64, - "cardia of stomach": 24, - "fundus of stomach": 282, - "pyloric antrum": 64, - "pyloric canal": 64, - "duodenum": 64, - "stomach": 810 + "body of stomach": 464, + "esophagus": 144, + "cardia of stomach": 36, + "fundus of stomach": 528, + "pyloric antrum": 160, + "pyloric canal": 160, + "duodenum": 80, + "stomach": 1572 } for name in expectedSizes3d: @@ -146,13 +146,13 @@ def test_stomach1(self): self.assertEqual(75, len(annotationGroups)) # mesh3d = refineFieldmodule.findMeshByDimension(3) - self.assertEqual(51840, mesh3d.getSize()) + self.assertEqual(99456, mesh3d.getSize()) mesh2d = refineFieldmodule.findMeshByDimension(2) - self.assertEqual(159760, mesh2d.getSize()) + self.assertEqual(306144, mesh2d.getSize()) mesh1d = refineFieldmodule.findMeshByDimension(1) - self.assertEqual(164016, mesh1d.getSize()) + self.assertEqual(313944, mesh1d.getSize()) nodes = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(56116, nodes.getSize()) + self.assertEqual(107276, nodes.getSize()) datapoints = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) @@ -166,7 +166,12 @@ def test_stomach1(self): term = get_stomach_term(name) group = getAnnotationGroupForTerm(annotationGroups, term) size = group.getMeshGroup(mesh3d).getSize() - self.assertEqual(expectedSizes3d[name]*64, size, name) + if name == "cardia of stomach": + self.assertEqual(expectedSizes3d[name] * 32, size, name) + elif name == "stomach": + self.assertEqual(expectedSizes3d[name] * 64 - expectedSizes3d["cardia of stomach"] * 32, size, name) + else: + self.assertEqual(expectedSizes3d[name]*64, size, name) # test finding a marker in refined scaffold markerGroup = refineFieldmodule.findFieldByName("marker").castGroup() @@ -183,8 +188,8 @@ def test_stomach1(self): self.assertTrue(node.isValid()) cache.setNode(node) element, xi = markerLocation.evaluateMeshLocation(cache, 3) - self.assertEqual(3840, element.getIdentifier()) - assertAlmostEqualList(self, xi, [1.0, 0.9996922150576828, 0.786908054385139], 1.0E-06) + self.assertEqual(8832, element.getIdentifier()) + assertAlmostEqualList(self, xi, [1.0, 1.0, 1.0], 1.0E-06) if __name__ == "__main__": From bdd69df28380efc7332272545a38c4c2e35e7507 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Tue, 22 Aug 2023 15:14:46 +1200 Subject: [PATCH 25/30] Fix problem with large number of elements around duodenum --- .../meshtypes/meshtype_3d_stomach1.py | 59 ++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index ceaa4fff..57a89edf 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1776,6 +1776,61 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio annulusIdxAtBodyStartIdxPlusOne = list(range(elementsAroundHalfEso - 1, elementsAroundHalfEso + 2)) + # Sample from quarterDuod to annulus at the quadrant points. + # 1st Quadrant + startGuessPosition = \ + trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * elementsAroundQuarterDuod, + 1.0 / len(xEllipseAroundAll) * sectionIdx[1]) + aPosition = trackSurfaceStomach.findNearestPosition(xEllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod], + startGuessPosition) + aProportion = trackSurfaceStomach.getProportion(aPosition) + + bPosition = xAnnulusOuterPosition[elementsAroundQuarterEso] + bProportion = trackSurfaceStomach.getProportion(bPosition) + + nx, nd1, nd2, nd3, proportions = trackSurfaceStomach.createHermiteCurvePoints( + aProportion[0], aProportion[1], bProportion[0], bProportion[1], elementsAroundQuarterDuod - 1, + derivativeStart=d1EllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod], + curveMode=TrackSurface.HermiteCurveMode.UNIFORM_SIZE) + + nxR, nd1R, nd2R, nd3R = \ + trackSurfaceStomach.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart= + vector.magnitude(d1EllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod]))[0:-1] + + # Replace the values in xEllipseAroundAll at quadrants + for n in range(len(nxR)): + xEllipseAroundAll[sectionIdx[1]][n + elementsAroundQuarterDuod] = nxR[n] + d1EllipseAroundAll[sectionIdx[1]][n + elementsAroundQuarterDuod] = nd1R[n] + d2EllipseAroundAll[sectionIdx[1]][n + elementsAroundQuarterDuod] = nd2R[n] + + # 2nd quadrant + aPosition = xAnnulusOuterPosition[-elementsAroundQuarterEso] + aProportion = trackSurfaceStomach.getProportion(aPosition) + + startGuessPosition = \ + trackSurfaceStomach.createPositionProportion(1.0 / elementsCountAroundDuod * + (elementsAroundQuarterDuod + elementsAroundHalfDuod), + 1.0 / len(xEllipseAroundAll) * sectionIdx[1]) + bPosition = \ + trackSurfaceStomach.findNearestPosition( + xEllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod + elementsAroundHalfDuod], startGuessPosition) + bProportion = trackSurfaceStomach.getProportion(bPosition) + + nx, nd1, nd2, nd3, proportions = trackSurfaceStomach.createHermiteCurvePoints( + aProportion[0], aProportion[1], bProportion[0], bProportion[1], elementsAroundQuarterDuod - 1, + derivativeEnd=d1EllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod + elementsAroundHalfDuod], + curveMode=TrackSurface.HermiteCurveMode.UNIFORM_SIZE) + + nxR, nd1R, nd2R, nd3R = \ + trackSurfaceStomach.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeEnd= + vector.magnitude(d1EllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod + elementsAroundHalfDuod]))[0:-1] + + for n in range(len(nxR)): + xEllipseAroundAll[sectionIdx[1]][elementsAroundHalfDuod + 1 + n] = nxR[n] + d1EllipseAroundAll[sectionIdx[1]][elementsAroundHalfDuod + 1 + n] = nd1R[n] + for i in range(len(sectionIdx) - 1): s = sectionIdx[i] sNext = sectionIdx[i + 1] @@ -1785,9 +1840,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # do a tracksurface sampling to divide the elements into equal sized elements while keeping the start and # end derivatives direction at both pts elementsOut = elementsAlongSections[i] - startDerivative = None + startDerivative = d2EllipseAroundAll[s][n1] startDerivativeMag = None - endDerivative = None + endDerivative = d2EllipseAroundAll[sNext][n1] endDerivativeMag = None if i == 1 and n1 in n1IdxAtBodyStartIdxPlusMinusOne: From 2a30ea874ab977c6a7c05294783142eaa72b2a6c Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 24 Aug 2023 11:35:20 +1200 Subject: [PATCH 26/30] Make derivatives around annulus in correct direction and magnitude --- .../meshtypes/meshtype_3d_stomach1.py | 234 ++++++++++-------- 1 file changed, 124 insertions(+), 110 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 57a89edf..d56f433c 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -2006,12 +2006,13 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio if annulusFundusOpenRingIdx <= n2 <= annulusBodyOpenRingIdx: d1SmoothedLeft = \ interp.smoothCubicHermiteDerivativesLine(xSampledAroundAlong[n2][0:elementsAroundHalfDuod], - d1SampledAroundAlong[n2][0:elementsAroundHalfDuod]) + d1SampledAroundAlong[n2][0:elementsAroundHalfDuod], + fixEndDirection=True) d1SmoothedRight = \ interp.smoothCubicHermiteDerivativesLine(xSampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [xSampledAroundAlong[n2][0]], d1SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + - [d1SampledAroundAlong[n2][0]]) + [d1SampledAroundAlong[n2][0]], fixStartDirection=True) d1Smoothed = d1SmoothedLeft + [[1.0, 0.0, 0.0]] + d1SmoothedRight[:-1] else: @@ -2029,9 +2030,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2SmoothedAlongGC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) - d2SmoothedAlongGC[-1] = vector.setMagnitude(d2SmoothedAlongGC[-1], - 0.5*(vector.magnitude(d2AnnulusOuter[0]) + - vector.magnitude(d2SmoothedAlongGC[-1]))) + d2SmoothedAlongGC[-1] = vector.setMagnitude(d2AnnulusOuter[0], vector.magnitude(d2SmoothedAlongGC[-1])) nx = [] nd2 = [] @@ -2039,11 +2038,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2SmoothedAlongLC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) - - d2SmoothedAlongLC[0] = vector.setMagnitude(d2SmoothedAlongLC[0], - 0.5*(vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso]) + - (vector.magnitude(d2SmoothedAlongLC[0])))) - + d2SmoothedAlongLC[0] = vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso], + vector.magnitude(d2SmoothedAlongLC[0])) d2Smoothed = d2SmoothedAlongGC + \ [[0.0, 1.0, 0.0] for n in range(2 * (elementsAroundQuarterEso - 2) + 1)] + \ d2SmoothedAlongLC @@ -2056,38 +2052,31 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio if n1 == elementsAroundHalfDuod - 1: d2Smoothed[annulusFundusOpenRingIdx - 1] = \ - vector.setMagnitude( - d1AnnulusOuter[1], - 0.5 * (vector.magnitude(d2Smoothed[annulusFundusOpenRingIdx - 1]) + - vector.magnitude(d1AnnulusOuter[1]))) - d2Smoothed[bodyStartIdx] = \ - vector.setMagnitude(d2Smoothed[bodyStartIdx], - vector.magnitude(d1AnnulusOuter[elementsAroundQuarterEso])) + vector.setMagnitude(d2AnnulusOuter[1], vector.magnitude(nd2[annulusFundusOpenRingIdx - 1])) + + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = m + 2 + d2Smoothed[annulusFundusOpenRingIdx + m] = \ + vector.setMagnitude(d2AnnulusOuter[annulusIdx], + vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx + m][n1])) + d2Smoothed[annulusBodyOpenRingIdx + 1] = \ - vector.setMagnitude( - d1AnnulusOuter[elementsAroundHalfEso - 1], - 0.5 * (vector.magnitude(d2Smoothed[annulusBodyOpenRingIdx + 1]) + - vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso - 1]))) + vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso - 1], + vector.magnitude(nd2[annulusBodyOpenRingIdx + 1])) if n1 == elementsAroundHalfDuod + 1: - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[-1], math.pi) - d1 = d1AnnulusOuter[-1] - d2 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] d2Smoothed[annulusFundusOpenRingIdx - 1] = \ - vector.setMagnitude( - d2, 0.5*(vector.magnitude(d2Smoothed[annulusFundusOpenRingIdx - 1]) + - vector.magnitude(d1AnnulusOuter[-1]))) + vector.setMagnitude(d2AnnulusOuter[-1], vector.magnitude(nd2[annulusFundusOpenRingIdx - 1])) - d2Smoothed[bodyStartIdx] = \ - vector.setMagnitude(d2Smoothed[bodyStartIdx], - vector.magnitude(d1AnnulusOuter[-elementsAroundQuarterEso])) + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = -(m + 2) + d2Smoothed[annulusFundusOpenRingIdx + m] = \ + vector.setMagnitude(d2AnnulusOuter[annulusIdx], + vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx + m][n1])) - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundHalfEso + 1], math.pi) - d1 = d1AnnulusOuter[elementsAroundHalfEso + 1] - d2 = [rotFrame[j][0] * d1[0] + rotFrame[j][1] * d1[1] + rotFrame[j][2] * d1[2] for j in range(3)] d2Smoothed[annulusBodyOpenRingIdx + 1] = \ - vector.setMagnitude(d2, 0.5 * (vector.magnitude(d2Smoothed[annulusBodyOpenRingIdx + 1]) + - vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso + 1]))) + vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso + 1], + vector.magnitude(nd2[annulusBodyOpenRingIdx + 1])) for n2 in range(len(d2Smoothed)): d2SampledAroundAlong[n2][n1] = d2Smoothed[n2] @@ -2102,12 +2091,34 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3SampledAroundAlong[n2][n1]) # nodeIdentifier += 1 + # Replace derivatives around annulus + for n in range(3): + d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][n1IdxAtBodyStartIdxPlusMinusOne[n]] = \ + d1AnnulusOuter[annulusIdxAtBodyStartIdxMinusOne[n]] + d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][n1IdxAtBodyStartIdxPlusMinusOne[n]] = \ + d1AnnulusOuter[annulusIdxAtBodyStartIdxPlusOne[n]] + + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = m + 2 + d1SampledAroundAlong[annulusFundusOpenRingIdx + m][elementsAroundHalfDuod - 1] = d1AnnulusOuter[annulusIdx] + d1SampledAroundAlong[annulusFundusOpenRingIdx + m][elementsAroundHalfDuod + 1] = d1AnnulusOuter[-annulusIdx] + # calculate d3 for n2 in range(len(xSampledAroundAlong)): for n1 in range(len(xSampledAroundAlong[n2])): d3SampledAroundAlong[n2][n1] = vector.normalise(vector.crossproduct3( vector.normalise(d1SampledAroundAlong[n2][n1]), vector.normalise(d2SampledAroundAlong[n2][n1]))) + # for n2 in range(len(xSampledAroundAlong)): + # for n1 in range(len(xSampledAroundAlong[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3SampledAroundAlong[n2][n1]) + # nodeIdentifier += 1 + # Calculate curvature around d1CurvatureAroundAlong = [[0.0 for n in range(elementsCountAroundDuod)]] for n2 in range(1, len(xSampledAroundAlong)): @@ -2127,47 +2138,6 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d3SampledAroundAlong[n2]) d1CurvatureAroundAlong.append(d1Curvature) - # Replace derivatives around annulus - # bodyStartIdx - 1 - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[1], math.pi) - d2 = d2AnnulusOuter[1] - d1 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod - 1] = \ - vector.setMagnitude( - d1, - 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod - 1]) + - vector.magnitude(d2AnnulusOuter[1]))) - - d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod] = \ - vector.setMagnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod], - vector.magnitude(d1AnnulusOuter[0])) - - d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod + 1] = \ - vector.setMagnitude( - d2AnnulusOuter[-1], - 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx - 1][elementsAroundHalfDuod + 1]) + - vector.magnitude(d2AnnulusOuter[-1]))) - - # bodyStartIdx + 1 - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[elementsAroundHalfEso - 1], math.pi) - d2 = d2AnnulusOuter[elementsAroundHalfEso - 1] - d1 = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod - 1] = \ - vector.setMagnitude( - d1, - 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod - 1]) + - vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso - 1]))) - - d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod] = \ - vector.setMagnitude(d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod], - vector.magnitude(d1AnnulusOuter[elementsAroundHalfEso])) - - d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod + 1] = \ - vector.setMagnitude( - d2AnnulusOuter[elementsAroundHalfEso + 1], - 0.5 * (vector.magnitude(d1SampledAroundAlong[annulusBodyOpenRingIdx + 1][elementsAroundHalfDuod + 1]) + - vector.magnitude(d2AnnulusOuter[elementsAroundHalfEso + 1]))) - # Calculate curvature along d2CurvatureAroundAlong = [[[] for n1 in range(len(xSampledAroundAlong[n2]))] for n2 in range(len(xSampledAroundAlong))] @@ -2440,44 +2410,56 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [])]) + [(Node.VALUE_LABEL_D_DS2, [1])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 145 elif e1 == elementsAroundHalfDuod - 1: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [1])]) + [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [])]) + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print('1', elementIdentifier) # 146 elif e1 == elementsAroundHalfDuod: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [1])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print('2', elementIdentifier) #147 elif e1 == elementsAroundHalfDuod + 1: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1])]) + [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) #148 if e2 == annulusFundusOpenRingIdx - 1: if e1 == elementsAroundHalfDuod - 2: @@ -2485,45 +2467,82 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 165 elif e1 == elementsAroundHalfDuod - 1: + scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 166 - if e2 == annulusBodyOpenRingIdx: + elif (elementsAroundQuarterEso - 2) > 0 and annulusFundusOpenRingIdx <= e2 <= annulusFundusOpenRingIdx + 1 + (elementsAroundQuarterEso - 2): if e1 == elementsAroundHalfDuod - 2: + scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 183, 201 elif e1 == elementsAroundHalfDuod - 1: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + [(Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 184, 202 - if e2 == annulusBodyOpenRingIdx + 1: + if e2 == annulusBodyOpenRingIdx: if e1 == elementsAroundHalfDuod - 2: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 219 elif e1 == elementsAroundHalfDuod - 1: scaleFactors = [-1.0] @@ -2533,30 +2552,32 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 220 - elif e1 == elementsAroundHalfDuod: + if e2 == annulusBodyOpenRingIdx + 1: + if e1 == elementsAroundHalfDuod - 2: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [])]) + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print('1', elementIdentifier) #237 elif e1 == elementsAroundHalfDuod + 1: - scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [])]) + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + # print(elementIdentifier) #240 element = mesh.createElement(elementIdentifier, elementtemplate1) element.setNodesByIdentifier(eft1, nodeIdentifiers) @@ -2624,14 +2645,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n3 in range(elementsCountThroughWall + 1): for nAround in range(elementsCountAroundEso): - if nAround == 0: - endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, -1, 0), None) - elif 1 <= nAround < elementsAroundHalfEso: - endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == elementsAroundHalfEso: - endDerivativesMap[n3][nAround] = (None, None, None) - else: - endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) + endDerivativesMap[n3][nAround] = (None, None, None) startProportions = [] for n in range(elementsCountAroundEso): From b65e498eebba416dbd25ab735bda6fe5b097a7df Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 24 Aug 2023 13:13:22 +1200 Subject: [PATCH 27/30] Set minimum elements in fundus and pylorus --- .../meshtypes/meshtype_3d_stomach1.py | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index d56f433c..772d3fd9 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -648,9 +648,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): options = { 'Central path': copy.deepcopy(centralPathOption), - 'Number of elements around esophagus': 12, - 'Number of elements around duodenum': 20, - 'Number of elements along': 24, + 'Number of elements around esophagus': 8, + 'Number of elements around duodenum': 16, + 'Number of elements along': 14, 'Number of elements through wall': 4, 'Wall thickness': 0.0525, 'Mucosa relative thickness': 0.55, @@ -669,7 +669,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Number of elements through wall'] = 1 options['Wall thickness'] = 0.0525 * 101 elif 'Mouse 1' in parameterSetName: - options['Number of elements along'] = 20 options['Wall thickness'] = 0.05145 options['Mucosa relative thickness'] = 0.75 options['Submucosa relative thickness'] = 0.05 @@ -684,7 +683,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.1 options['Limiting ridge'] = False elif 'Rat 1' in parameterSetName: - options['Number of elements along'] = 20 options['Wall thickness'] = 0.0215 options['Mucosa relative thickness'] = 0.65 options['Submucosa relative thickness'] = 0.12 @@ -692,7 +690,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Longitudinal muscle layer relative thickness'] = 0.05 options['Limiting ridge'] = True elif 'Material' in parameterSetName: - options['Number of elements along'] = 20 options['Wall thickness'] = 0.05 options['Mucosa relative thickness'] = 0.25 options['Submucosa relative thickness'] = 0.25 @@ -779,8 +776,8 @@ def checkOptions(cls, options): 'Number of elements around duodenum']: if options[key] % 4 > 0: options[key] = options[key] // 4 * 4 - if options['Number of elements along'] < 10: - options['Number of elements along'] = 10 + if options['Number of elements along'] < 12: + options['Number of elements along'] = 12 if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 for key in [ @@ -1736,32 +1733,25 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d2QuarterEllipseAll.append(d2EllipseAroundAll[n2][elementsAroundQuarterDuod]) totalQuarterLength = interp.getCubicHermiteCurvesLength(xQuarterEllipseAll, d2QuarterEllipseAll) - ratioArcLengthSections = [] + quarterLengthSections = [] for i in range(len(nodeStartEndSections)): xList = [] d2List = [] for n in range(nodeStartEndSections[i][0], nodeStartEndSections[i][1] + 1): xList.append(xQuarterEllipseAll[n]) d2List.append(d2QuarterEllipseAll[n]) - quarterLengthSection = interp.getCubicHermiteCurvesLength(xList, d2List) - ratioArcLengthSections.append(quarterLengthSection / totalQuarterLength) + quarterLengthSections.append(interp.getCubicHermiteCurvesLength(xList, d2List)) - elementsAlongSections = [math.floor(c * elementsCountAlong) for c in ratioArcLengthSections] - - modGroups = [] - for i in range(len(elementsAlongSections)): - if elementsAlongSections[i] < 1: - elementsAlongSections[i] == 1 - - mod = ratioArcLengthSections[i] * elementsCountAlong - elementsAlongSections[i] - modGroups.append(mod) - - excessElements = elementsCountAlong - sum(elementsAlongSections) + targetLengthPerElement = totalQuarterLength/elementsCountAlong + minElementsInSections = [4, 3, 2, 2, 1] + excessElements = elementsCountAlong - sum(minElementsInSections) + diff = [quarterLengthSections[c] - targetLengthPerElement * minElementsInSections[c] for c in range(len(minElementsInSections))] for i in range(excessElements): - maxIdx = max(range(len(modGroups)), key=modGroups.__getitem__) - elementsAlongSections[maxIdx] += 1 - modGroups[maxIdx] = ratioArcLengthSections[maxIdx] * elementsCountAlong - elementsAlongSections[maxIdx] + maxIdx = max(range(len(diff)), key=diff.__getitem__) + minElementsInSections[maxIdx] += 1 + diff[maxIdx] -= targetLengthPerElement + elementsAlongSections = minElementsInSections totalElementsAlong = sum(elementsAlongSections) From 5704223973e6cdc8b418af9461781fdb8c397797 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 24 Aug 2023 15:26:36 +1200 Subject: [PATCH 28/30] Update mouse and rat central paths --- .../meshtypes/meshtype_3d_stomach1.py | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 772d3fd9..a834a3ab 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -181,18 +181,18 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.54,0.71,0.00], [-0.01,-0.06,0.00], [0.08,-0.01,0.00], [0.10,-0.02,0.00], [0.00,0.00,0.04], [0.00,0.00,0.12]]), - (2, [[0.53,0.63,0.00], [-0.01,-0.10,0.00], [0.17,-0.03,0.00], [0.08,-0.02,0.00], [0.00,0.00,0.16], [0.00,0.00,0.12]]), - (3, [[0.51,0.52,0.00], [-0.03,-0.14,0.00], [0.24,-0.06,0.00], [0.07,-0.04,0.00], [0.00,0.00,0.27], [0.00,0.00,0.10]]), - (4, [[0.47,0.36,0.00], [-0.05,-0.16,0.00], [0.30,-0.12,0.00], [0.03,-0.09,0.00], [0.00,0.00,0.35], [0.00,0.00,0.06]]), - (5, [[0.40,0.20,0.00], [-0.11,-0.15,0.00], [0.29,-0.24,0.00], [-0.05,-0.11,0.00], [0.00,0.00,0.38], [0.00,0.00,0.02]]), - (6, [[0.26,0.08,0.00], [-0.20,-0.11,0.00], [0.19,-0.34,0.00], [-0.13,-0.08,0.00], [0.00,0.00,0.39], [0.00,0.00,0.00]]), - (7, [[0.00,0.00,0.00], [-0.29,-0.01,0.00], [0.01,-0.40,0.00], [-0.19,0.01,0.00], [0.00,0.00,0.38], [0.00,0.00,-0.01]]), - (8, [[-0.29,0.07,0.00], [-0.24,0.13,0.00], [-0.20,-0.32,0.00], [-0.11,0.10,0.00], [0.00,0.00,0.36], [0.00,0.00,-0.03]]), - (9, [[-0.46,0.23,0.00], [-0.10,0.19,0.00], [-0.23,-0.21,0.00], [0.02,0.12,0.00], [0.00,0.00,0.32], [0.00,0.00,-0.08]]), - (10, [[-0.48,0.42,0.00], [-0.01,0.17,0.00], [-0.17,-0.08,0.00], [0.07,0.09,0.00], [0.00,0.00,0.21], [0.00,0.00,-0.09]]), - (11, [[-0.48,0.56,0.00], [-0.01,0.14,0.00], [-0.10,-0.02,0.00], [0.03,0.02,0.00], [0.00,0.00,0.13], [0.00,0.00,-0.05]]), - (12, [[-0.51,0.70,0.00], [-0.04,0.14,0.00], [-0.11,-0.04,0.00], [-0.05,-0.06,0.00], [0.00,0.00,0.12], [0.00,0.00,0.02]]) + (1, [[0.540,0.710,0.000], [-0.005,-0.065,0.000], [0.080,-0.010,0.000], [0.098,-0.016,0.000], [0.000,0.000,0.040], [0.000,0.000,0.124]]), + (2, [[0.530,0.630,0.000], [-0.015,-0.095,0.000], [0.170,-0.030,0.000], [0.082,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.116]]), + (3, [[0.510,0.520,0.000], [-0.029,-0.135,0.000], [0.240,-0.060,0.000], [0.066,-0.042,0.000], [0.000,0.000,0.270], [0.000,0.000,0.098]]), + (4, [[0.470,0.360,0.000], [-0.055,-0.161,0.000], [0.300,-0.120,0.000], [0.026,-0.089,0.000], [0.000,0.000,0.350], [0.000,0.000,0.056]]), + (5, [[0.400,0.200,0.000], [-0.107,-0.145,0.000], [0.290,-0.240,0.000], [-0.054,-0.110,0.000], [0.000,0.000,0.380], [0.000,0.000,0.020]]), + (6, [[0.260,0.080,0.000], [-0.202,-0.111,0.000], [0.190,-0.340,0.000], [-0.132,-0.084,0.000], [0.000,0.000,0.390], [0.000,0.000,0.002]]), + (7, [[0.000,0.000,0.000], [-0.288,-0.009,0.000], [0.010,-0.400,0.000], [-0.194,0.007,0.000], [0.000,0.000,0.380], [0.000,0.000,-0.015]]), + (8, [[-0.290,0.070,0.000], [-0.237,0.128,0.000], [-0.200,-0.320,0.000], [-0.109,0.097,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.031]]), + (9, [[-0.460,0.230,0.000], [-0.099,0.191,0.000], [-0.230,-0.210,0.000], [0.020,0.121,0.000], [0.000,0.000,0.320], [0.000,0.000,-0.079]]), + (10, [[-0.486,0.419,0.000], [-0.008,0.167,0.000], [-0.170,-0.080,0.000], [0.069,0.087,0.000], [0.000,0.000,0.210], [0.000,0.000,-0.109]]), + (11, [[-0.480,0.560,0.000], [-0.012,0.142,0.000], [-0.094,-0.025,0.000], [0.030,0.020,0.000], [0.000,0.000,0.102], [0.000,0.000,-0.046]]), + (12, [[-0.510,0.700,0.000], [-0.048,0.137,0.000], [-0.110,-0.040,0.000], [-0.062,-0.050,0.000], [0.000,0.000,0.120], [0.000,0.000,0.082]]) ]), 'userAnnotationGroups': [ @@ -302,19 +302,19 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.492,0.623,0.000], [0.003,-0.035,0.000], [0.060,-0.002,0.000], [0.118,0.016,0.000], [0.000,0.000,0.080], [0.000,0.000,0.077]]), - (2, [[0.490,0.553,0.000], [-0.007,-0.105,0.000], [0.180,-0.006,0.000], [0.122,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.083]]), - (3, [[0.475,0.414,0.000], [-0.039,-0.151,0.000], [0.308,-0.071,0.000], [0.077,-0.090,0.000], [0.000,0.000,0.250], [0.000,0.000,0.072]]), - (4, [[0.409,0.256,0.000], [-0.082,-0.144,0.000], [0.324,-0.191,0.000], [-0.028,-0.116,0.000], [0.000,0.000,0.300], [0.000,0.000,0.040]]), - (5, [[0.315,0.129,0.000], [-0.121,-0.114,0.000], [0.256,-0.304,0.000], [-0.090,-0.100,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), - (6, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.059,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), - (7, [[0.000,0.000,0.000], [-0.200,0.002,0.000], [0.005,-0.420,0.000], [-0.156,0.002,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), + (1, [[0.601,0.602,0.000], [-0.027,-0.056,0.000], [0.077,-0.036,0.000], [0.122,-0.056,0.000], [0.000,0.000,0.080], [0.000,0.000,0.076]]), + (2, [[0.564,0.524,0.000], [-0.047,-0.100,-0.000], [0.189,-0.097,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.160], [0.000,0.000,0.084]]), + (3, [[0.507,0.402,0.000], [-0.071,-0.139,-0.000], [0.273,-0.171,0.000], [0.062,-0.070,-0.000], [0.000,0.000,0.250], [0.000,0.000,0.073]]), + (4, [[0.420,0.248,0.000], [-0.097,-0.137,-0.000], [0.307,-0.237,0.000], [-0.011,-0.067,-0.000], [0.000,0.000,0.300], [0.000,0.000,0.039]]), + (5, [[0.315,0.129,0.000], [-0.125,-0.109,-0.000], [0.256,-0.304,0.000], [-0.080,-0.076,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), + (6, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.058,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), + (7, [[0.000,0.000,0.000], [-0.200,0.002,0.000], [0.005,-0.420,0.000], [-0.156,0.003,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), (8, [[-0.218,0.048,0.000], [-0.208,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), - (9, [[-0.404,0.184,0.000], [-0.152,0.178,0.000], [-0.299,-0.260,0.000], [-0.056,0.122,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), - (10, [[-0.511,0.392,0.000], [-0.040,0.213,0.000], [-0.259,-0.148,0.000], [0.080,0.105,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.112]]), - (11, [[-0.490,0.587,0.000], [-0.011,0.172,0.000], [-0.152,-0.045,0.000], [0.076,0.039,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.067]]), - (12, [[-0.523,0.730,0.000], [-0.032,0.117,0.000], [-0.111,-0.036,0.000], [0.009,-0.000,0.000], [0.000,0.000,0.120], [0.000,0.000,0.015]]), - (13, [[-0.552,0.820,0.000], [-0.025,0.063,0.000], [-0.132,-0.045,0.000], [-0.050,-0.018,0.000], [0.000,0.000,0.150], [0.000,0.000,0.045]]) + (9, [[-0.404,0.184,0.000], [-0.142,0.162,0.000], [-0.299,-0.260,0.000], [-0.044,0.113,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), + (10, [[-0.497,0.356,0.000], [-0.049,0.209,0.000], [-0.255,-0.188,0.000], [0.077,0.107,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.111]]), + (11, [[-0.490,0.587,0.000], [-0.018,0.189,-0.000], [-0.152,-0.045,0.000], [0.069,0.049,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.073]]), + (12, [[-0.523,0.730,0.000], [-0.032,0.116,0.000], [-0.111,-0.036,0.000], [0.003,-0.002,0.000], [0.000,0.000,0.120], [0.000,0.000,0.018]]), + (13, [[-0.552,0.820,0.000], [-0.026,0.063,0.000], [-0.132,-0.045,0.000], [-0.045,-0.016,0.000], [0.000,0.000,0.150], [0.000,0.000,0.042]]) ]), 'userAnnotationGroups': [ @@ -2484,7 +2484,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementtemplate1 = elementtemplateX # print(elementIdentifier) # 166 - elif (elementsAroundQuarterEso - 2) > 0 and annulusFundusOpenRingIdx <= e2 <= annulusFundusOpenRingIdx + 1 + (elementsAroundQuarterEso - 2): + elif (elementsAroundQuarterEso - 2) > 0 and annulusFundusOpenRingIdx <= e2 < annulusFundusOpenRingIdx + 2.0 * (elementsAroundQuarterEso - 2): if e1 == elementsAroundHalfDuod - 2: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() From 6ca1bbb9351c15624ff39d0b9974f86c13298fbb Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 25 Aug 2023 10:27:30 +1200 Subject: [PATCH 29/30] Update curvature for derivatives around annulus --- .../meshtypes/meshtype_3d_stomach1.py | 82 ++++++++++++++++++- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index a834a3ab..e02513d5 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1714,6 +1714,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n in range(elementsCountAroundEso): d3 = vector.normalise(vector.crossproduct3(vector.normalise(d1AnnulusOuter[n]), d2AnnulusNorm[n])) d3Annulus.append(d3) + d1AnnulusCurvatureOuter = findCurvatureAroundLoop(xAnnulusOuter, d1AnnulusOuter, d3Annulus) # for m in range(len(xAnnulusOuter)): # node = nodes.createNode(nodeIdentifier, nodetemplate) @@ -1969,21 +1970,25 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xSampledAroundAlong = [] d1SampledAroundAlong = [] d2SampledAroundAlong = [] + d2SmoothB4ChangeAroundAlong = [] d3SampledAroundAlong = [] for n2 in range(totalElementsAlong + 1): xSampledAround = [] d1SampledAround = [] d2SampledAround = [] + d2SmoothB4ChangeAround = [] d3SampledAround = [] for n1 in range(elementsCountAroundDuod): xSampledAround.append(xSampledAlong[n1][n2]) d1SampledAround.append(d1SampledAlong[n1][n2]) d2SampledAround.append(d2SampledAlong[n1][n2]) + d2SmoothB4ChangeAround.append([]) d3SampledAround.append(d3SampledAlong[n1][n2]) xSampledAroundAlong.append(xSampledAround) d1SampledAroundAlong.append(d1SampledAround) d2SampledAroundAlong.append(d2SampledAround) + d2SmoothB4ChangeAroundAlong.append(d2SmoothB4ChangeAround) d3SampledAroundAlong.append(d3SampledAround) bodyStartIdx = elementsAlongSections[0] @@ -2002,7 +2007,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio interp.smoothCubicHermiteDerivativesLine(xSampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + [xSampledAroundAlong[n2][0]], d1SampledAroundAlong[n2][elementsAroundHalfDuod + 1:] + - [d1SampledAroundAlong[n2][0]], fixStartDirection=True) + [d1SampledAroundAlong[n2][0]], + fixStartDirection=True) + d1Smoothed = d1SmoothedLeft + [[1.0, 0.0, 0.0]] + d1SmoothedRight[:-1] else: @@ -2012,6 +2019,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d1SampledAroundAlong = d1SmoothedAroundAlong # Smooth d2 along + d2AnnulusNew = [[] for n in range(elementsCountAroundEso)] for n1 in range(elementsCountAroundDuod): nx = [] nd2 = [] @@ -2020,7 +2028,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2SmoothedAlongGC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + d2SmoothedAlongGCB4Change = copy.deepcopy(d2SmoothedAlongGC) d2SmoothedAlongGC[-1] = vector.setMagnitude(d2AnnulusOuter[0], vector.magnitude(d2SmoothedAlongGC[-1])) + d2AnnulusNew[0] = d2SmoothedAlongGC[-1] nx = [] nd2 = [] @@ -2028,48 +2038,61 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2SmoothedAlongLC = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + d2SmoothedAlongLCB4Change = copy.deepcopy(d2SmoothedAlongLC) d2SmoothedAlongLC[0] = vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso], vector.magnitude(d2SmoothedAlongLC[0])) + d2AnnulusNew[elementsAroundHalfEso] = d2SmoothedAlongLC[0] d2Smoothed = d2SmoothedAlongGC + \ [[0.0, 1.0, 0.0] for n in range(2 * (elementsAroundQuarterEso - 2) + 1)] + \ d2SmoothedAlongLC + d2SmoothedB4Change = d2SmoothedAlongGCB4Change + \ + [[0.0, 1.0, 0.0] for n in range(2 * (elementsAroundQuarterEso - 2) + 1)] + \ + d2SmoothedAlongLCB4Change else: for n2 in range(len(xSampledAroundAlong)): nx.append(xSampledAroundAlong[n2][n1]) nd2.append(d2SampledAroundAlong[n2][n1]) d2Smoothed = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + d2SmoothedB4Change = copy.deepcopy(d2Smoothed) if n1 == elementsAroundHalfDuod - 1: d2Smoothed[annulusFundusOpenRingIdx - 1] = \ vector.setMagnitude(d2AnnulusOuter[1], vector.magnitude(nd2[annulusFundusOpenRingIdx - 1])) + d2AnnulusNew[1] = d2Smoothed[annulusFundusOpenRingIdx - 1] for m in range(2 * (elementsAroundQuarterEso - 2) + 1): annulusIdx = m + 2 d2Smoothed[annulusFundusOpenRingIdx + m] = \ vector.setMagnitude(d2AnnulusOuter[annulusIdx], vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx + m][n1])) + d2AnnulusNew[annulusIdx] = d2Smoothed[annulusFundusOpenRingIdx + m] d2Smoothed[annulusBodyOpenRingIdx + 1] = \ vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso - 1], vector.magnitude(nd2[annulusBodyOpenRingIdx + 1])) + d2AnnulusNew[elementsAroundHalfEso - 1] = d2Smoothed[annulusBodyOpenRingIdx + 1] if n1 == elementsAroundHalfDuod + 1: d2Smoothed[annulusFundusOpenRingIdx - 1] = \ vector.setMagnitude(d2AnnulusOuter[-1], vector.magnitude(nd2[annulusFundusOpenRingIdx - 1])) + d2AnnulusNew[-1] = d2Smoothed[annulusFundusOpenRingIdx - 1] for m in range(2 * (elementsAroundQuarterEso - 2) + 1): annulusIdx = -(m + 2) d2Smoothed[annulusFundusOpenRingIdx + m] = \ vector.setMagnitude(d2AnnulusOuter[annulusIdx], vector.magnitude(d1SampledAroundAlong[annulusFundusOpenRingIdx + m][n1])) + d2AnnulusNew[annulusIdx] = d2Smoothed[annulusFundusOpenRingIdx + m] d2Smoothed[annulusBodyOpenRingIdx + 1] = \ vector.setMagnitude(d2AnnulusOuter[elementsAroundHalfEso + 1], vector.magnitude(nd2[annulusBodyOpenRingIdx + 1])) + d2AnnulusNew[elementsAroundHalfEso + 1] = d2Smoothed[annulusBodyOpenRingIdx + 1] for n2 in range(len(d2Smoothed)): d2SampledAroundAlong[n2][n1] = d2Smoothed[n2] + d2SmoothB4ChangeAroundAlong[n2][n1] = d2SmoothedB4Change[n2] # for n2 in range(len(xSampledAroundAlong)): # for n1 in range(len(xSampledAroundAlong[n2])): @@ -2128,7 +2151,26 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d3SampledAroundAlong[n2]) d1CurvatureAroundAlong.append(d1Curvature) + # Replace curvatures around annulus + for n in range(3): + d1CurvatureAroundAlong[annulusFundusOpenRingIdx - 1][n1IdxAtBodyStartIdxPlusMinusOne[n]] = \ + d1AnnulusCurvatureOuter[annulusIdxAtBodyStartIdxMinusOne[n]] + d1CurvatureAroundAlong[annulusBodyOpenRingIdx + 1][n1IdxAtBodyStartIdxPlusMinusOne[n]] = \ + d1AnnulusCurvatureOuter[annulusIdxAtBodyStartIdxPlusOne[n]] + + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = m + 2 + d1CurvatureAroundAlong[annulusFundusOpenRingIdx + m][elementsAroundHalfDuod - 1] = \ + d1AnnulusCurvatureOuter[annulusIdx] + d1CurvatureAroundAlong[annulusFundusOpenRingIdx + m][elementsAroundHalfDuod + 1] = \ + d1AnnulusCurvatureOuter[-annulusIdx] + # Calculate curvature along + d2AnnulusCurvature = [] + for n in range(elementsCountAroundEso): + d2AnnulusCurvature.append(interp.getCubicHermiteCurvature(o1_x[-1][n], vector.setMagnitude(o1_d2[-1][n], sf), + xAnnulusOuter[n], d2AnnulusNew[n], d3Annulus[n], 1.0)) + d2CurvatureAroundAlong = [[[] for n1 in range(len(xSampledAroundAlong[n2]))] for n2 in range(len(xSampledAroundAlong))] @@ -2139,7 +2181,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio if n1 == elementsAroundHalfDuod: for n2 in range(annulusFundusOpenRingIdx): nx.append(xSampledAroundAlong[n2][n1]) - nd2.append(d2SampledAroundAlong[n2][n1]) + nd2.append(d2SmoothB4ChangeAroundAlong[n2][n1]) nd3.append(d3SampledAroundAlong[n2][n1]) d2CurvatureAlongGC = findCurvatureAlongLine(nx, nd2, nd3) @@ -2148,7 +2190,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nd3 = [] for n2 in range(annulusBodyOpenRingIdx + 1, len(xSampledAroundAlong)): nx.append(xSampledAroundAlong[n2][n1]) - nd2.append(d2SampledAroundAlong[n2][n1]) + nd2.append(d2SmoothB4ChangeAroundAlong[n2][n1]) nd3.append(d3SampledAroundAlong[n2][n1]) d2CurvatureAlongLC = findCurvatureAlongLine(nx, nd2, nd3) d2CurvatureAlong = d2CurvatureAlongGC + \ @@ -2158,10 +2200,42 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio else: for n2 in range(len(xSampledAroundAlong)): nx.append(xSampledAroundAlong[n2][n1]) - nd2.append(d2SampledAroundAlong[n2][n1]) + nd2.append(d2SmoothB4ChangeAroundAlong[n2][n1]) nd3.append(d3SampledAroundAlong[n2][n1]) d2CurvatureAlong = findCurvatureAlongLine(nx, nd2, nd3) + if n1 == elementsAroundHalfDuod - 1: + d2CurvatureAlong[annulusFundusOpenRingIdx - 1] = \ + 0.5 * (d2CurvatureAlong[annulusFundusOpenRingIdx - 1] + d2AnnulusCurvature[1]) + d2CurvatureAlong[annulusBodyOpenRingIdx + 1] = \ + 0.5 * (d2AnnulusCurvature[elementsAroundHalfEso - 1] + + interp.getCubicHermiteCurvature(xAnnulusOuter[elementsAroundHalfEso - 1], + d2AnnulusNew[elementsAroundHalfEso - 1], + xSampledAroundAlong[annulusBodyOpenRingIdx + 2][n1], + d2SampledAroundAlong[annulusBodyOpenRingIdx + 2][n1], + d3SampledAroundAlong[annulusBodyOpenRingIdx + 1][n1], 0.0)) + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = m + 2 + d2CurvatureAlong[annulusFundusOpenRingIdx + m] = \ + 0.5 * (d2AnnulusCurvature[annulusIdx] + + d1CurvatureAroundAlong[annulusFundusOpenRingIdx + m][n1]) + + if n1 == elementsAroundHalfDuod + 1: + d2CurvatureAlong[annulusFundusOpenRingIdx - 1] = \ + 0.5 * (d2CurvatureAlong[annulusFundusOpenRingIdx - 1] + d2AnnulusCurvature[-1]) + d2CurvatureAlong[annulusBodyOpenRingIdx + 1] = \ + 0.5 * (d2AnnulusCurvature[elementsAroundHalfEso + 1] + + interp.getCubicHermiteCurvature(xAnnulusOuter[elementsAroundHalfEso + 1], + d2AnnulusNew[elementsAroundHalfEso + 1], + xSampledAroundAlong[annulusBodyOpenRingIdx + 2][n1], + d2SampledAroundAlong[annulusBodyOpenRingIdx + 2][n1], + d3SampledAroundAlong[annulusBodyOpenRingIdx + 1][n1], 0.0)) + for m in range(2 * (elementsAroundQuarterEso - 2) + 1): + annulusIdx = m + 2 + d2CurvatureAlong[annulusFundusOpenRingIdx + m] = \ + 0.5 * (d2AnnulusCurvature[-annulusIdx] + + d1CurvatureAroundAlong[annulusFundusOpenRingIdx + m][n1]) + for n2 in range(len(d2CurvatureAlong)): d2CurvatureAroundAlong[n2][n1] = d2CurvatureAlong[n2] From fe3d331db87cecc514c63d262f3e374de54dbd1e Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 25 Aug 2023 10:51:02 +1200 Subject: [PATCH 30/30] Update unit tests --- tests/test_general.py | 8 +++--- tests/test_stomach.py | 57 ++++++++++++++++++++++--------------------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/tests/test_general.py b/tests/test_general.py index fceb71ef..17ec4c2f 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -408,11 +408,11 @@ def test_deletion(self): self.assertTrue(scaffoldPackage.isUserAnnotationGroup(bobGroup)) self.assertFalse(bobGroup.isMarker()) nextNodeIdentifier = scaffoldPackage.getNextNodeIdentifier() - node = bobGroup.createMarkerNode(nextNodeIdentifier, stomachCoordinatesField, [0.900712, 0.291771, 0.391829]) + node = bobGroup.createMarkerNode(nextNodeIdentifier, stomachCoordinatesField, [-0.165034, 0.12313, 0.484541]) bobNodeIdentifier = node.getIdentifier() self.assertEqual(nextNodeIdentifier, bobNodeIdentifier) stomachCoordinatesFieldOut, stomachCoordinatesValueOut = bobGroup.getMarkerMaterialCoordinates() - self.assertEqual([0.900712, 0.291771, 0.391829], stomachCoordinatesValueOut) + self.assertEqual([-0.165034, 0.12313, 0.484541], stomachCoordinatesValueOut) # check bob is made before deletion bob = scaffoldPackage.findAnnotationGroupByName('bob') @@ -438,7 +438,7 @@ def test_deletion(self): annotationGroups = scaffoldPackage.getAnnotationGroups() self.assertEqual(73, len(annotationGroups)) scaffoldPackage.deleteElementsInRanges(region, [[313, 496]]) - self.assertEqual(1896, mesh3d.getSize()) + self.assertEqual(824, mesh3d.getSize()) element = mesh3d.findElementByIdentifier(400) self.assertFalse(element.isValid()) @@ -457,7 +457,7 @@ def test_deletion(self): # check that bob is deleted annotationGroups = scaffoldPackage.getAnnotationGroups() - self.assertEqual(72, len(annotationGroups)) + self.assertEqual(70, len(annotationGroups)) bob = scaffoldPackage.findAnnotationGroupByName('bob') self.assertNotIn(bob, annotationGroups) node = nodes.findNodeByIdentifier(bobNodeIdentifier) diff --git a/tests/test_stomach.py b/tests/test_stomach.py index 2249dc3f..c0fc2557 100644 --- a/tests/test_stomach.py +++ b/tests/test_stomach.py @@ -29,14 +29,14 @@ def test_stomach1(self): self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Mouse 1", "Pig 1", "Rat 1", "Material"]) options = scaffold.getDefaultOptions("Rat 1") self.assertEqual(17, len(options)) - self.assertEqual(20, options.get("Number of elements around duodenum")) - self.assertEqual(20, options.get("Number of elements along")) + self.assertEqual(16, options.get("Number of elements around duodenum")) + self.assertEqual(14, options.get("Number of elements along")) self.assertEqual(0.0215, options.get("Wall thickness")) self.assertEqual(True, options.get("Limiting ridge")) ostiumOptions = options['Gastro-esophageal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() self.assertEqual(1, ostiumSettings.get("Number of vessels")) - self.assertEqual(12, ostiumSettings.get("Number of elements around ostium")) + self.assertEqual(8, ostiumSettings.get("Number of elements around ostium")) self.assertEqual(4, ostiumSettings.get("Number of elements through wall")) self.assertEqual(5.0, ostiumSettings.get("Ostium diameter")) self.assertEqual(5.0, ostiumSettings.get("Ostium length")) @@ -56,26 +56,26 @@ def test_stomach1(self): fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) - self.assertEqual(1572, mesh3d.getSize()) + self.assertEqual(906, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) - self.assertEqual(5208, mesh2d.getSize()) + self.assertEqual(3007, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) - self.assertEqual(5706, mesh1d.getSize()) + self.assertEqual(3300, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(2090, nodes.getSize()) + self.assertEqual(1219, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [-0.77, -0.42, -0.36293353103307363], 1.0E-6) - assertAlmostEqualList(self, maximums, [0.780854631116736, 0.8713406657835177, 0.3629335310330727], 1.0E-6) + assertAlmostEqualList(self, minimums, [-0.752, -0.42, -0.36], 1.0E-6) + assertAlmostEqualList(self, maximums, [0.7735083767257301, 0.8700275257183235, 0.36], 1.0E-6) stomachCoordinates = fieldmodule.findFieldByName("stomach coordinates").castFiniteElement() minimums, maximums = evaluateFieldNodesetRange(stomachCoordinates, nodes) - assertAlmostEqualList(self, minimums, [-1.3, -0.5014130864747104, -0.5014130864747104], 1.0E-4) - assertAlmostEqualList(self, maximums, [0.7, 0.8, 0.5014130864747104], 1.0E-4) + assertAlmostEqualList(self, minimums, [-1.3, -0.5009809736137905, -0.5009809735605149], 1.0E-4) + assertAlmostEqualList(self, maximums, [0.7, 0.8, 0.5009809736137903], 1.0E-4) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -87,21 +87,21 @@ def test_stomach1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 4.109097109853743, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 4.090555416482455, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 0.05866824043828919, delta=1.0E-6) + self.assertAlmostEqual(volume, 0.05785162434759533, delta=1.0E-6) # check some annotationGroups: expectedSizes3d = { - "body of stomach": 464, - "esophagus": 144, - "cardia of stomach": 36, - "fundus of stomach": 528, - "pyloric antrum": 160, - "pyloric canal": 160, - "duodenum": 80, - "stomach": 1572 + "body of stomach": 184, + "esophagus": 96, + "cardia of stomach": 24, + "fundus of stomach": 282, + "pyloric antrum": 128, + "pyloric canal": 128, + "duodenum": 64, + "stomach": 906 } for name in expectedSizes3d: @@ -130,6 +130,7 @@ def test_stomach1(self): refineRegion = region.createRegion() refineFieldmodule = refineRegion.getFieldmodule() options['Refine number of elements surface'] = 4 + options['Refine number of elements cardia surface'] = 4 options['Refine number of elements through wall'] = 4 meshrefinement = MeshRefinement(region, refineRegion, annotationGroups) scaffold.refineMesh(meshrefinement, options) @@ -146,13 +147,13 @@ def test_stomach1(self): self.assertEqual(75, len(annotationGroups)) # mesh3d = refineFieldmodule.findMeshByDimension(3) - self.assertEqual(99456, mesh3d.getSize()) + self.assertEqual(57984, mesh3d.getSize()) mesh2d = refineFieldmodule.findMeshByDimension(2) - self.assertEqual(306144, mesh2d.getSize()) + self.assertEqual(178576, mesh2d.getSize()) mesh1d = refineFieldmodule.findMeshByDimension(1) - self.assertEqual(313944, mesh1d.getSize()) + self.assertEqual(183216, mesh1d.getSize()) nodes = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(107276, nodes.getSize()) + self.assertEqual(62644, nodes.getSize()) datapoints = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) @@ -167,9 +168,9 @@ def test_stomach1(self): group = getAnnotationGroupForTerm(annotationGroups, term) size = group.getMeshGroup(mesh3d).getSize() if name == "cardia of stomach": - self.assertEqual(expectedSizes3d[name] * 32, size, name) + self.assertEqual(expectedSizes3d[name] * 64, size, name) elif name == "stomach": - self.assertEqual(expectedSizes3d[name] * 64 - expectedSizes3d["cardia of stomach"] * 32, size, name) + self.assertEqual(expectedSizes3d[name] * 64, size, name) else: self.assertEqual(expectedSizes3d[name]*64, size, name) @@ -188,7 +189,7 @@ def test_stomach1(self): self.assertTrue(node.isValid()) cache.setNode(node) element, xi = markerLocation.evaluateMeshLocation(cache, 3) - self.assertEqual(8832, element.getIdentifier()) + self.assertEqual(5888, element.getIdentifier()) assertAlmostEqualList(self, xi, [1.0, 1.0, 1.0], 1.0E-06)