From 94eaf10d1c644ab5ba631fd451aacf8f61323503 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 5 Mar 2021 10:17:12 +1300 Subject: [PATCH 01/38] Initial commit for stomach scaffold --- .../meshtypes/meshtype_3d_stomach1.py | 1892 +++++++++++++++++ src/scaffoldmaker/scaffolds.py | 2 + .../utils/eftfactory_tricubichermite.py | 26 + 3 files changed, 1920 insertions(+) create mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py new file mode 100644 index 00000000..a7cc6fc8 --- /dev/null +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -0,0 +1,1892 @@ +""" +Generates a 3-D stomach mesh along the central line, with variable +numbers of elements around oesophagus and duodenum, along and through +wall, with variable radius and thickness along. +""" + +from __future__ import division +import math +import copy +from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates +from opencmiss.zinc.element import Element +from opencmiss.zinc.field import Field +from opencmiss.zinc.node import Node +from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1, extractPathParametersFromRegion +from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1, generateOstiumMesh +from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base +from scaffoldmaker.scaffoldpackage import ScaffoldPackage +from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d +from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear +from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite +from scaffoldmaker.utils.eft_utils import scaleEftNodeValueLabels, setEftScaleFactorIds, remapEftNodeValueLabel +from scaffoldmaker.utils.geometry import createEllipsePoints +from scaffoldmaker.utils.tracksurface import TrackSurface +from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues +from scaffoldmaker.utils import interpolation as interp +from scaffoldmaker.utils import matrix +from scaffoldmaker.utils import vector + + +class MeshType_3d_stomach1(Scaffold_base): + """ + Generates a 3-D stomach mesh with variable numbers of elements around the oesophagus and duodenum, + along the central line, and through wall. The stomach is created by a function that generates a bean + volume defined by a central path as its longitudinal axis. D2 of the central path points to the greater + curvature of the stomach and magnitude of D2 and D3 are the radii of the stomach in the respective + direction. + """ + centralPathDefaultScaffoldPackages = { + 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 5 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[17.0, 14.0, 0.0], [-12.4, -22.4, 0.0], [7.9, -4.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 0.0]], + [[10.0, 0.0, 0.0], [-19.8, -2.6, 0.0], [1.1, -8.9, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 0.0]], + [[0.0, 0.0, 0.0], [-19.8, -2.6, 0.0], [1.1, -8.9, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 0.0]], + [[-10.0, 7.0, 0.0], [-8.1, 9.4, 0.0], [-1.9, -1.6, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.5], + [0.0, 0.0, 0.0]], + [[-15.0, 7.0, 0.0], [-8.1, 9.4, 0.0], [-1.9, -1.6, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.5], + [0.0, 0.0, 0.0]], + [[-17.0, 14.0, 0.0], [0.2, 2.6, 0.0], [-3.5, 0.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 3.5], + [0.0, 0.0, 0.0]]]) + }), + 'Human 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 3 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[17.0, 14.0, 0.0], [-12.4, -22.4, 0.0], [7.9, -4.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 0.0]], + [[0.0, 0.0, 0.0], [-19.8, -2.6, 0.0], [1.1, -8.9, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 0.0]], + [[-15.0, 7.0, 0.0], [-6.2, 7.0, 0.0], [-2.0, -1.4, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.5], + [0.0, 0.0, 0.0]], + [[-19.2, 13.9, 0.0], [-4.1, 9.0, 0.0], [-3.2, -1.4, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 3.5], + [0.0, 0.0, 0.0]]]) + }), + } + + ostiumDefaultScaffoldPackages = { + 'Rat 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'scaffoldSettings': { + 'Number of vessels': 1, + 'Number of elements across common': 2, + 'Number of elements around ostium': 8, + 'Number of elements along': 2, + 'Number of elements through wall': 1, # not implemented for > 1 + 'Unit scale': 1.0, + 'Outlet': False, + 'Ostium diameter': 5.0, + 'Ostium length': 5.0, + 'Ostium wall thickness': 0.5, + 'Ostium inter-vessel distance': 0.0, + 'Ostium inter-vessel height': 0.0, + 'Use linear through ostium wall': True, + 'Vessel end length factor': 1.0, + 'Vessel inner diameter': 1.25, + 'Vessel wall thickness': 0.5, + 'Vessel angle 1 degrees': 0.0, + 'Vessel angle 1 spread degrees': 0.0, + 'Vessel angle 2 degrees': 0.0, + 'Use linear through vessel wall': True, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + }, + }), + 'Human 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'scaffoldSettings': { + 'Number of vessels': 1, + 'Number of elements across common': 2, + 'Number of elements around ostium': 8, + 'Number of elements along': 2, + 'Number of elements through wall': 1, # not implemented for > 1 + 'Unit scale': 1.0, + 'Outlet': False, + 'Ostium diameter': 5.0, + 'Ostium length': 5.0, + 'Ostium wall thickness': 0.5, + 'Ostium inter-vessel distance': 0.0, + 'Ostium inter-vessel height': 0.0, + 'Use linear through ostium wall': True, + 'Vessel end length factor': 1.0, + 'Vessel inner diameter': 1.25, + 'Vessel wall thickness': 0.5, + 'Vessel angle 1 degrees': 0.0, + 'Vessel angle 1 spread degrees': 0.0, + 'Vessel angle 2 degrees': 0.0, + 'Use linear through vessel wall': True, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + }, + }), + } + + @staticmethod + def getName(): + return '3D Stomach 1' + + @staticmethod + def getParameterSetNames(): + return [ + 'Default', + 'Rat 1', + 'Human 1'] + + @classmethod + def getDefaultOptions(cls, parameterSetName='Default'): + if 'Rat 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] + else: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + + options = { + 'Central path': copy.deepcopy(centralPathOption), + 'Number of elements around oesophagus': 8, + 'Number of elements around duodenum': 12, + 'Number of elements along': 8, + 'Number of elements through wall': 1, + 'Wall thickness': 0.5, + 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), + 'Gastro-oesophagal junction position along factor': 0.3, + 'Use cross derivatives': False, + 'Use linear through wall' : False, # need to deal with wedge not available in bicubichermite + 'Refine': False, + 'Refine number of elements around': 1, + 'Refine number of elements along': 1, + 'Refine number of elements through wall': 1 + } + # Add default options for Rat and human later + + cls.updateSubScaffoldOptions(options) + return options + + @staticmethod + def getOrderedOptionNames(): + return [ + 'Central path', + 'Number of elements around oesophagus', + 'Number of elements around duodenum', + 'Number of elements along', + 'Number of elements through wall', + 'Wall thickness', + 'Gastro-oesophagal junction', + 'Gastro-oesophagal junction position along factor', + 'Use cross derivatives', + 'Use linear through wall', + 'Refine', + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall'] + + @classmethod + def getOptionValidScaffoldTypes(cls, optionName): + if optionName == 'Central path': + return [MeshType_1d_path1] + if optionName == 'Gastro-oesophagal junction': + return [MeshType_3d_ostium1] + return [] + + @classmethod + def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): + if optionName == 'Central path': + return list(cls.centralPathDefaultScaffoldPackages.keys()) + if optionName == 'Gastro-oesophagal junction': + return list(cls.ostiumDefaultScaffoldPackages.keys()) + assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ + cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ + 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() + return scaffoldType.getParameterSetNames() + + @classmethod + def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): + ''' + :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. + :return: ScaffoldPackage. + ''' + if parameterSetName: + assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ + 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() + if optionName == 'Central path': + if not parameterSetName: + parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] + return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + if optionName == 'Gastro-oesophagal junction': + if not parameterSetName: + parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] + return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) + assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' + + @classmethod + 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-oesophagal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( + 'Gastro-oesophagal junction'): + options['Gastro-oesophagal junction'] = cls.getOptionScaffoldPackage('Gastro-oesophagal junction', + MeshType_3d_ostium1) + if options['Number of elements around oesophagus'] < 8: + options['Number of elements around oesophagus'] = 8 + if options['Number of elements around duodenum'] < 12: + options['Number of elements around duodenum'] = 12 + for key in [ + 'Number of elements around oesophagus', + 'Number of elements around duodenum']: + if options[key] % 2: + options[key] += 1 + if options['Number of elements along'] < 8: + options['Number of elements along'] = 8 + if options['Number of elements through wall'] < 1: + options['Number of elements through wall'] = 1 + for key in [ + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall']: + if options[key] < 1: + options[key] = 1 + + cls.updateSubScaffoldOptions(options) + + @classmethod + def updateSubScaffoldOptions(cls, options): + ''' + Update ostium sub-scaffold options which depend on parent options. + ''' + wallThickness = options['Wall thickness'] + ostiumOptions = options['Gastro-oesophagal junction'] + ostiumSettings = ostiumOptions.getScaffoldSettings() + ostiumSettings['Ostium wall thickness'] = wallThickness + + @classmethod + def generateBaseMesh(cls, region, options): + """ + Generate the base tricubic Hermite mesh. See also generateMesh(). + :param region: Zinc region to define model in. Must be empty. + :param options: Dict containing options. See getDefaultOptions(). + :return: None + """ + cls.updateSubScaffoldOptions(options) + centralPath = options['Central path'] + elementsCountAroundOesophagus = options['Number of elements around oesophagus'] + elementsCountAroundDuodenum = options['Number of elements around duodenum'] + elementsCountAlong = options['Number of elements along'] + elementsCountThroughWall = options['Number of elements through wall'] + wallThickness = options['Wall thickness'] + useCrossDerivatives = options['Use cross derivatives'] + useCubicHermiteThroughWall = not (options['Use linear through wall']) + + GOJPositionAlongFactor = options['Gastro-oesophagal junction position along factor'] + GOJOptions = options['Gastro-oesophagal junction'] + GOJSettings = GOJOptions.getScaffoldSettings() + oesophagusDiameter = GOJSettings['Ostium diameter'] + + elementsCountAlongTrackSurface = 20 + + ############################################################################################ + zero = [0.0, 0.0, 0.0] + + fm = region.getFieldmodule() + fm.beginChange() + + coordinates = findOrCreateFieldCoordinates(fm) + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) + if useCubicHermiteThroughWall: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) + + cache = fm.createFieldcache() + ########################################################################################### + + firstNodeIdentifier = 1 + firstElementIdentifier = 1 + + # Central path + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + cx, cd1, cd2, cd3, cd12, cd13 = extractPathParametersFromRegion(tmpRegion, + [Node.VALUE_LABEL_VALUE, + Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, + Node.VALUE_LABEL_D_DS3, + Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS1DS3]) + del tmpRegion + # for i in range(len(cx)): + # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') + + sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongTrackSurface) + sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) + sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) + + # Calculate length of central path + stomachCentralPathLength = 0.0 + for e in range(len(sx) - 1): + arcLength = interp.getCubicHermiteArcLength(sx[e], sd1[e], sx[e + 1], sd1[e + 1]) + # print(e+1, arcLength) + stomachCentralPathLength += arcLength + lengthElementAlong = stomachCentralPathLength / elementsCountAlongTrackSurface + + nodeIdentifier = firstNodeIdentifier + elementIdentifier = firstElementIdentifier + + # Fundus diameter + fundusRadius = vector.magnitude(sd2[0]) + elementsAlongFundus = int(fundusRadius / lengthElementAlong) + + d2Apex = [] + d2 = sd2[0] + for n1 in range(elementsCountAroundDuodenum): + rotAngle = n1 * 2.0 * math.pi / elementsCountAroundDuodenum + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(sd1[0]), rotAngle) + d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + d2Apex.append(d2Rot) + + xEllipses = [] + d1Ellipses = [] + for n in range(elementsAlongFundus + 1, len(sx)): + px, pd1 = createEllipsePoints(sx[n], 2 * math.pi, sd2[n], sd3[n], elementsCountAroundDuodenum, + startRadians=0.0) + xEllipses.append(px) + d1Ellipses.append(pd1) + + # Find d2 + d2Raw = [] + for n1 in range(elementsCountAroundDuodenum): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses) - 1): + v1 = xEllipses[n2][n1] + v2 = xEllipses[n2 + 1][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v1) + d2Along.append(d2) + xAlong.append(xEllipses[-1][n1]) + d2Along.append(d2) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Raw.append(d2Smoothed) + + # Rearrange d2 + d2Ellipses = [] + for n2 in range(len(xEllipses)): + d2Around = [] + for n1 in range(elementsCountAroundDuodenum): + d2 = d2Raw[n1][n2] + d2Around.append(d2) + d2Ellipses.append(d2Around) + + # for n2 in range(len(xEllipses)): + # for n1 in range(elementsCountAroundDuodenum): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xEllipses[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Ellipses[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Ellipses[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Merge fundus and body + xAll = [[sx[0]] * elementsCountAroundDuodenum] + xEllipses + d2All = [d2Apex] + d2Ellipses + + # for n2 in range(len(xAll)): + # for n1 in range(elementsCountAroundDuodenum): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2All[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Spread out elements + xRaw = [] + d2Raw = [] + for n1 in range(elementsCountAroundDuodenum): + xAlong = [] + d2Along = [] + for n2 in range(len(xAll)): + xAlong.append(xAll[n2][n1]) + d2Along.append(d2All[n2][n1]) + xSampledAlong, d2SampledAlong = interp.sampleCubicHermiteCurves(xAlong, d2Along, + elementsCountAlongTrackSurface, + arcLengthDerivatives=True)[0:2] + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlong, d2SampledAlong) + xRaw.append(xSampledAlong) + d2Raw.append(d2Smoothed) + + # Rearrange x and d2 + xSampledAll = [] + d1SampledAll = [] + d2SampledAll = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + xAround = [] + d1Around = [] + d2Around = [] + for n1 in range(elementsCountAroundDuodenum): + x = xRaw[n1][n2] + d2 = d2Raw[n1][n2] + xAround.append(x) + d2Around.append(d2) + + # Calculate d1 + if n2 > 0: + v1 = xRaw[n1][n2] + v2 = xRaw[n1 + 1 if n1 < elementsCountAroundDuodenum - 2 else 0][n2] + d1 = findDerivativeBetweenPoints(v1, v2) + d1Around.append(d1) + else: + d1Around.append(d2Raw[int(elementsCountAroundDuodenum * 0.75)][0]) + + if n2 > 0: + d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) + else: + d1Smoothed = d1Around + + xSampledAll.append(xAround) + d1SampledAll.append(d1Smoothed) + d2SampledAll.append(d2Around) + + # for n2 in range(elementsCountAlongTrackSurface + 1): + # for n1 in range(elementsCountAroundDuodenum): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Create tracksurface + xTrackSurface = [] + d1TrackSurface = [] + d2TrackSurface = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + for n1 in range(elementsCountAroundDuodenum): + xTrackSurface.append(xSampledAll[n2][n1]) + d1TrackSurface.append(d1SampledAll[n2][n1]) + d2TrackSurface.append(d2SampledAll[n2][n1]) + + trackSurfaceStomach = TrackSurface(elementsCountAroundDuodenum, elementsCountAlongTrackSurface, + xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) + + # for n2 in range(len(xTrackSurface)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TrackSurface[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TrackSurface[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Set up gastro-oesophagal junction + GOJSettings['Number of elements around ostium'] = elementsCountAroundOesophagus + GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) + xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) + axis1 = d1Centre + + # fm = region.getFieldmodule() + mesh = fm.findMeshByDimension(3) + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + + nextNodeIdentifier = nodeIdentifier + nextElementIdentifier = elementIdentifier + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, + nextNodeIdentifier, nextElementIdentifier) + bodyStartNode = nextNodeIdentifier + + # From oesophagus to duodenum along lesser curvature (LC) + elementsOesoToDuodLC = elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) # CHECK + startProportion1, startProportion2 = trackSurfaceStomach.getProportion( + o1_Positions[int(elementsCountAroundOesophagus * 0.5)]) + d1Start = o1_d2[1][int(elementsCountAroundOesophagus * 0.5)] + + xOesoToDuodLC, d2OesoToDuodLC = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, 0.5, 1.0, + elementsOesoToDuodLC) + + # From oesophagus to duodenum along greater curvature (GC) + xAlongGC = [] + d2AlongGC = [] + xAlongGC.append(o1_x[1][0]) + d2AlongGC.append(o1_d2[1][0]) + + oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] + elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) + + # From oesophagus to fundus apex + arcLengthOesoApex = 0.0 + for n2 in range(elementsAlongUpstreamOfOeso): + nAlong = elementsAlongUpstreamOfOeso - n2 + v1 = xSampledAll[nAlong][int(elementsCountAroundDuodenum * 0.5)] + v2 = xSampledAll[nAlong - 1][int(elementsCountAroundDuodenum * 0.5)] + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + arcLengthOesoApex += arcLengthAround + d2 = [c * arcLengthAround for c in vector.normalise(d)] + xAlongGC.append(v1) + d2AlongGC.append(d2) + + # From fundus apex to duodenum + for n2 in range(len(xSampledAll)): + xAlongGC.append(xSampledAll[n2][0]) + d2AlongGC.append(d2SampledAll[n2][0]) + + elementsOesoToDuodGC = elementsCountAlong + int(elementsCountAroundDuodenum * 0.5) - 2 # Check, old - elementsCountAlong + int(elementsCountAroundOesophagus * 0.5) + xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurvesSmooth(xAlongGC, d2AlongGC, elementsOesoToDuodGC, + derivativeMagnitudeStart=0.5 * vector.magnitude( + d2AlongGC[0]))[0:2] + + arcLength = 0.0 + for e in range(len(xOesoToDuodGC) - 1): + arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], + xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) + if arcLength > arcLengthOesoApex: + nodesCountFromOesoToApex = e + 2 + break + + d2OesoToDuodGC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2OesoToDuodGC) + + nodeIdentifier = nextNodeIdentifier + + # for n2 in range(len(xOesoToDuodLC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # for n2 in range(len(xOesoToDuodGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Spread out elements around for each egroup around + # Elements around oesophagus + # Decide where to put extra elements if elementsOesophagus/2 is odd number. + # Right now, extra elements go downstream of bifurcation + # For even numbers, we split elements at bifurcation + + ptsOnTrackSurfaceGC = [] + xAlongAround = [] + d1AlongAround = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) + + for idx in range(math.ceil(elementsCountAroundOesophagus * 0.25)): + # First half + ostiumIdx = int(elementsCountAroundOesophagus * 0.25) + idx + GCIdx = -(elementsCountAlong - int(elementsCountAroundOesophagus * 0.25)) + idx # 4 - elementsCountAlong - math.ceil(elementsCountAroundOesophagus * 0.25) + idx + + # Find closest position to point on GC as track surface is not a simple geometry near dome + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + + endPosition = o1_Positions[ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) + d2 = o1_d2[1][ostiumIdx] + d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] + # remove d1Ave when cleaning up code + xi = 0 #ostiumIdx / int(elementsCountAroundOesophagus * 0.5) + d1Ave = [d1EndOstium[c] * (1 - xi) + d1EndTrackSurface[c] * xi for c in range(3)] + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, + endProportion2, int(0.5 * elementsCountAroundDuodenum + 1), + startDerivative=d1GC, endDerivative=d1Ave, + endDerivativeMagnitude= 0.5 * vector.magnitude(d1Ave)) + + # Second half + ostiumIdx2 = elementsCountAroundOesophagus - (int(elementsCountAroundOesophagus * 0.25) + idx) + startPosition = o1_Positions[ostiumIdx2] + d1StartOstium = o1_d2[1][ostiumIdx2] + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] + # Clean up + d1Ave = [d1StartOstium[c] * (1 - xi) + d1StartTrackSurface[c] * xi for c in range(3)] + + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, + GCProportion2, int(0.5 * elementsCountAroundDuodenum + 1), + startDerivative=d1Ave, endDerivative=d1GC, + startDerivativeMagnitude= 0.5 * vector.magnitude(d1Ave)) + + xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] + d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # Elements downstream of oesophagus + for idx in range(-(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5)), 0): #4 - elementsCountAlong, 0): + startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], + ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + + endPosition = trackSurfaceStomach.findNearestPosition(xOesoToDuodLC[idx]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + d1End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, startProportion2, endProportion1, + endProportion2, int(0.5 * elementsCountAroundDuodenum), + startDerivative=d1Start, endDerivative=d1End) + + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, endProportion1, endProportion2, 1.0, + startProportion2, int(0.5 * elementsCountAroundDuodenum), + startDerivative=d1End, endDerivative=d1Start) + + xAround = xFirstHalf + xSecondHalf[1:-1] + d1Around = d1FirstHalf + d1SecondHalf[1:-1] + d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # for n2 in range(len(xAlongAround)): + # for n1 in range(len(xAlongAround[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # # Joining loops at fundus + ptsOnTrackSurfaceOesoToFundus = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][int(elementsCountAroundDuodenum * 0.5)]) + + xLoopsRight = [] + d2LoopsRight = [] + xLoopsLeft = [] + d2LoopsLeft = [] + + for n in range(int(elementsCountAroundDuodenum * 0.5 - 1)): + GCIdx = n + 1 + if GCIdx < nodesCountFromOesoToApex: + ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus + proportion1 = 0.5 + else: + ptsOnTrackSurface = ptsOnTrackSurfaceGC + proportion1 = 0.0 + d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], + ptsOnTrackSurface, + trackSurfaceStomach, proportion1, + elementsCountAlongTrackSurface)[1] + + if GCIdx < nodesCountFromOesoToApex: + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] + d2GC = d2GCRot + + d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) - n][c] - + xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - n][c] for c in range(3)] + + nx = [ xOesoToDuodGC[GCIdx], xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - n]] + nd2 = [d2GC, d2End] + xRight, d2Right = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25) + (1 if n > 0 else 0), arcLengthDerivatives=True)[0:2] + + # Calculate and append d2 for elements downstream of loop + if n == 0: + xAnnulusRight = xRight + d2AnnulusRight = d2Right + x1 = xAlongAround[1][int(elementsCountAroundDuodenum * 0.5)] + x2 = xOesoToDuodLC[1] + d2 = findDerivativeBetweenPoints(x1, x2) + xAnnulusRight += [x1, x2] + d2AnnulusRight += [d2, d2OesoToDuodLC[1]] + d2AnnulusRight = interp.smoothCubicHermiteDerivativesLine(xAnnulusRight, d2AnnulusRight, + fixStartDirection=True, + fixEndDerivative= True) + # for n2 in range(len(xAnnulusRight)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusRight[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AnnulusRight[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + else: + for n2 in range(1, len(xAlongAround)): + x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5) - n] + x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5) - n] + d2 = findDerivativeBetweenPoints(x2, x1) + xRight.append(x1) + d2Right.append(d2) + + # for n2 in range(len(xRight)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRight[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Right[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + d2Right = interp.smoothCubicHermiteDerivativesLine(xRight, d2Right, fixStartDirection=True) + + xLoopsRight.append(xRight) + d2LoopsRight.append(d2Right) + + # Repeat for left side + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] + d2GC = d2GCRot + + xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + n] + d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5 + 1) + n][c] - + xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + n][c] for c in range(3)] + + nx = [xOesoToDuodGC[GCIdx], xEnd] + nd2 = [d2GC, d2End] + xLeft, d2Left = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25) + (1 if n > 0 else 0), + arcLengthDerivatives=True)[0:2] + + # Calculate and append d2 for elements downstream of loop + if n == 0: + # Deal with addition of elementsAlong later + xAnnulusLeft = xLeft + d2AnnulusLeft = d2Left + x1 = xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) + 1] + x2 = xOesoToDuodLC[1] + d2 = findDerivativeBetweenPoints(x1, x2) + xAnnulusLeft += [x1, x2] + d2AnnulusLeft += [d2, d2OesoToDuodLC[1]] + d2AnnulusLeft = interp.smoothCubicHermiteDerivativesLine(xAnnulusLeft, d2AnnulusLeft, + fixStartDirection=True, + fixEndDerivative=True) + + # for n2 in range(len(xAnnulusLeft)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusLeft[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AnnulusLeft[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + else: + # Issues when elementsCountAroundOesophagus > 8 + for n2 in range(1, len(xAlongAround)): + if n2 == 1: + x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5 + 1) + n] + x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5 + 1) + n] + elif n2 == 2: + x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5) + n] + x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5 + 1) + n] + else: + x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5 ) + n] + x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5 ) + n] + d2 = findDerivativeBetweenPoints(x2, x1) + xLeft.append(x1) + d2Left.append(d2) + + # for n2 in range(len(xLeft)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLeft[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Left[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + d2Left = interp.smoothCubicHermiteDerivativesLine(xLeft, d2Left, fixStartDirection=True) + + xLoopsLeft.append(xLeft) + d2LoopsLeft.append(d2Left) + + # for n1 in range(len(xLoopsRight)): + # for n2 in range(len(xLoopsRight[n1])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsRight[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2LoopsRight[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # for n1 in range(len(xLoopsLeft)): + # for n2 in range(len(xLoopsLeft[n1])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsLeft[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2LoopsLeft[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + xBottom = [] + d2Bottom = [] + for n1 in range(-1, 2): + xAlong = [] + d2Along = [] + for n2 in range(len(xAlongAround)): + x1 = xAlongAround[n2][n1] + x2 = xAlongAround[n2 - 1][n1] + d2 = findDerivativeBetweenPoints(x2, x1) + xAlong.append(x1) + d2Along.append(d2) + d2Along = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + xBottom.append(xAlong) + d2Bottom.append(d2Along) + + # for n1 in range(len(xBottom)): + # for n2 in range(len(xBottom[n1])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBottom[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Bottom[n1][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Join row running along next to GC to oesophagus + # Find point between second row coming down fundus and second row running along the bottom + nx = [xLoopsLeft[-1][1], xBottom[0][0]] + nd1 = [[xLoopsLeft[-1][1][c] - xLoopsLeft[-2][1][c] for c in range(3)], d2Bottom[0][0]] + x, d = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] + xBifurcationBottomLeft = x[1] + + xAround2Left = [] + d1Around2Left = [] + xAround2Left.append(xAnnulusLeft[1]) + for i in range(len(xLoopsLeft)): + xAround2Left.append(xLoopsLeft[i][1]) + xAround2Left.append(xBifurcationBottomLeft) + for i in range(len(xBottom[0])): + xAround2Left.append(xBottom[0][i]) + + for n1 in range(len(xAround2Left) - 1): + x1 = xAround2Left[n1] + x2 = xAround2Left[n1 + 1] + d1 = findDerivativeBetweenPoints(x1, x2) + d1Around2Left.append(d1) + d1Around2Left.append(d1) + d1Around2Left = interp.smoothCubicHermiteDerivativesLine(xAround2Left, d1Around2Left) + + # for n1 in range(len(xAround2Left)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround2Left[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1Around2Left[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Right + # Find point between second row coming down fundus and second row running along the bottom + xAround2Right = [] + d1Around2Right = [] + + nx = [xLoopsRight[-1][1], xBottom[2][0]] + nd1 = [[xLoopsRight[-1][1][c] - xLoopsRight[-2][1][c] for c in range(3)], d2Bottom[2][0]] + x, d = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] + xBifurcationBottomRight = x[1] + + xAround = [] + d1Around = [] + xAround.append(xAnnulusRight[1]) + for i in range(len(xLoopsRight)): + xAround.append(xLoopsRight[i][1]) + xAround.append(xBifurcationBottomRight) + for i in range(len(xBottom[2])): + xAround.append(xBottom[2][i]) + + for n1 in range(len(xAround) - 1): + x1 = xAround[n1] + x2 = xAround[n1 + 1] + d1 = findDerivativeBetweenPoints(x1, x2) + d1Around.append(d1) + d1Around.append(d1) + d1Around = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around) + xAround2Right += xAround + d1Around2Right += d1Around + + # Calculate d in opposite direction to get d1 in correct direction going towards oesophagus + xAround.reverse() + d1AroundReverse = [] + for n1 in range(len(xAround) - 1): + x1 = xAround[n1] + x2 = xAround[n1 + 1] + d1 = findDerivativeBetweenPoints(x1, x2) + d1AroundReverse.append(d1) + d1AroundReverse.append(d1) + d1AroundReverse = interp.smoothCubicHermiteDerivativesLine(xAround, d1AroundReverse) + + for i in range(int(elementsCountAroundDuodenum * 0.5) - 1): + d1Around2Right[i] = d1AroundReverse[-1 - i] + + xAround.reverse() + + # for n2 in range(len(xAround2Right)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround2Right[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1Around2Right[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Calculate d1 for loop joining to bifurcation + xAroundBifurcationLoop = [] + xAroundBifurcationLoop.append(xAnnulusLeft[int(elementsCountAroundOesophagus * 0.25)]) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xAroundBifurcationLoop.append(xLoopsLeft[n1][int(elementsCountAroundOesophagus * 0.25)]) + xAroundBifurcationLoop.append(xBifurcationBottomLeft) + xAroundBifurcationLoop.append(xOesoToDuodGC[int(elementsCountAroundDuodenum * 0.5)]) + xAroundBifurcationLoop.append(xBifurcationBottomRight) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 3, -1, -1): + xAroundBifurcationLoop.append(xLoopsRight[-int(elementsCountAroundDuodenum * 0.5 - 2) + n1][int(elementsCountAroundOesophagus * 0.25)]) + xAroundBifurcationLoop.append(xAnnulusRight[int(elementsCountAroundOesophagus * 0.25)]) + + d1AroundBifurcationLoop = [] + for n1 in range(len(xAroundBifurcationLoop) - 1): + x1 = xAroundBifurcationLoop[n1] + x2 = xAroundBifurcationLoop[n1 + 1] + d = findDerivativeBetweenPoints(x1, x2) + d1AroundBifurcationLoop.append(d) + d1AroundBifurcationLoop.append(d) + d1AroundBifurcationLoop = interp.smoothCubicHermiteDerivativesLine(xAroundBifurcationLoop, + d1AroundBifurcationLoop, + fixStartDirection=True, fixEndDirection=True) + + # nodeIdentifier = 10000 + # for n1 in range(len(xAroundBifurcationLoop)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundBifurcationLoop[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundBifurcationLoop[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Annulus to LC + # xAnnulusToDuodLC = xOesoToDuodLC #[1:] + # d2AnnulusToDuodLC = [] + # for n2 in range(len(xAnnulusToDuodLC) - 1): + # x1 = xAnnulusToDuodLC[n2] + # x2 = xAnnulusToDuodLC[n2 + 1] + # d2 = findDerivativeBetweenPoints(x1, x2) + # d2AnnulusToDuodLC.append(d2) + # d2AnnulusToDuodLC.append(d2) + # + # d2AnnulusToDuodLC = interp.smoothCubicHermiteDerivativesLine(xAnnulusToDuodLC, d2AnnulusToDuodLC) + + xLC = xOesoToDuodLC # [1:] + d2LC = [] + for n2 in range(len(xLC) - 1): + x1 = xLC[n2] + x2 = xLC[n2 + 1] + d2 = findDerivativeBetweenPoints(x1, x2) + d2LC.append(d2) + d2LC.append(d2) + + d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC) + xAnnulusToDuodLC = xLC[1:] + d2AnnulusToDuodLC = d2LC[1:] + # for n2 in range(len(xAnnulusToDuodLC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AnnulusToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Arrange nodes + xOuter = [] + d1Outer = [] + d2Outer = [] + + for n2 in range(elementsCountAlong + 1): + xAround = [] + d1Around = [] + d2Around = [] + if n2 == 0: + for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xAround.append(xOesoToDuodGC[i+1]) + d1Around.append(d2OesoToDuodGC[i + 1]) + d2Around.append(d2AnnulusLeft[0] if i == 0 else d2LoopsLeft[i-1][0]) + + elif n2 == 1: + xAround.append(xOesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) - 1]) + d1Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) - 1]) + d2Around.append(d2LoopsLeft[int(elementsCountAroundDuodenum * 0.5) - 3][0]) + # Right + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, - 1, -1): + xAround.append(xAround2Right[n1]) + d1Around.append(d1Around2Right[n1]) + d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusRight[n2]) + # Left + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): + xAround.append(xAround2Left[n1]) + d1Around.append(d1Around2Left[n1]) + d2Around.append(d2LoopsLeft[n1 - 1][n2] if n1 > 0 else d2AnnulusLeft[n2]) + + elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25): + pass # Handle later + + elif n2 == int(elementsCountAroundOesophagus * 0.25): # Upstream bifurcation row + xAround = xAroundBifurcationLoop[int(elementsCountAroundDuodenum * 0.5):] + d1Around = d1AroundBifurcationLoop[int(elementsCountAroundDuodenum * 0.5): - 1] + d1Around.append(d1AlongAround[0][int(elementsCountAroundDuodenum * 0.5)]) # Annulus right + d1Around.append(d1AlongAround[0][int(elementsCountAroundDuodenum * 0.5) + 1]) # Annulus left + xAround += xAroundBifurcationLoop[: int(elementsCountAroundDuodenum * 0.5)] + d1Around += d1AroundBifurcationLoop[1 : int(elementsCountAroundDuodenum * 0.5)] + + d2Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5)]) # on GC + d2Around.append(d1Around2Right[int(elementsCountAroundDuodenum * 0.5) - 1]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): + d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusRight[int(elementsCountAroundOesophagus * 0.25)]) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): + d2Around.append(d2LoopsLeft[n1 - 1][n2] if n1 > 0 else d2AnnulusLeft[int(elementsCountAroundOesophagus * 0.25)]) + d2Around.append(d1Around2Left[int(elementsCountAroundDuodenum * 0.5) - 1]) # next to GC + + elif n2 == int(elementsCountAroundOesophagus * 0.25) + 1: # Downstream bifurcation row: + xAround = xAlongAround[0][: int(elementsCountAroundDuodenum * 0.5)] + \ + xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) + 2:] + d1Around = d1AlongAround[0][: int(elementsCountAroundDuodenum * 0.5)] + \ + d1AlongAround[0][int(elementsCountAroundDuodenum * 0.5) + 2:] + d2Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) + 1]) # on GC + d2Around.append(d1Around2Right[int(elementsCountAroundDuodenum * 0.5)]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, 0, -1): + d2Around.append(d2LoopsRight[n1 - 1][n2]) + for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): + d2Around.append(d2LoopsLeft[n1 - 1][n2]) + d2Around.append(d1Around2Left[int(elementsCountAroundDuodenum * 0.5)]) # next to GC + + elif n2 > int(elementsCountAroundOesophagus * 0.25) + 1 and n2 <= int(elementsCountAroundOesophagus * 0.5): # n2 == 4 + idx = n2 - (int(elementsCountAroundOesophagus * 0.25) + 1) + xAround = xAlongAround[idx][: int(elementsCountAroundDuodenum * 0.5) + 1] + \ + xAlongAround[idx][int(elementsCountAroundDuodenum * 0.5) + 1:] + d1Around = d1AlongAround[idx][: int(elementsCountAroundDuodenum * 0.5) + 1] + \ + d1AlongAround[idx][int(elementsCountAroundDuodenum * 0.5) + 1:] + d2Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) + 1 + idx]) # on GC + d2Around.append(d1Around2Right[int(elementsCountAroundDuodenum * 0.5) + idx]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): + d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusRight[int(elementsCountAroundOesophagus * 0.25) + 1]) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): + d2Around.append(d2LoopsLeft[n1 - 1][n2] if n1 > 0 else d2AnnulusLeft[int(elementsCountAroundOesophagus * 0.25) + 1]) + d2Around.append(d1Around2Left[int(elementsCountAroundDuodenum * 0.5) + 1]) # next to GC + + elif n2 > int(elementsCountAroundOesophagus * 0.5): # n2 > 4 + idx = n2 - (int(elementsCountAroundOesophagus * 0.25) + 1) + GCIdx = int(elementsCountAroundDuodenum * 0.5) + n2 - 2 + xAround = xAlongAround[idx] + d1Around = d1AlongAround[idx] + d2Around.append(d2OesoToDuodGC[GCIdx]) # on GC + d2Around.append(d1Around2Right[GCIdx - 1]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): + d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusToDuodLC[n2 - 5]) + for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): + d2Around.append(d2LoopsLeft[n1 - 1][n2]) + d2Around.append(d1Around2Left[GCIdx - 1]) # next to GC + + # for n1 in range(len(xAround)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Around[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Around[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + xOuter.append(xAround) + d1Outer.append(d1Around) + d2Outer.append(d2Around) + + d3UnitOuter = [] + for n2 in range(elementsCountAlong + 1): + d3Around = [] + for n1 in range(len(xOuter[n2])): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) + d3UnitOuter.append(d3Around) + + # Calculate curvatures + # Curvatures along GC + xGC = [] + dGC = [] + norms = [] + for n1 in range(len(xOuter[0])): + xGC.append(xOuter[0][n1]) + dGC.append(d1Outer[0][n1]) + norms.append(d3UnitOuter[0][n1]) + for n2 in range(1, elementsCountAlong + 1): + xGC.append(xOuter[n2][0]) + dGC.append(d1Outer[n2][0] if n2 == 1 else d2Outer[n2][0]) + norms.append(d3UnitOuter[n2][0]) + curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 + + # for m1 in range(len(xGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Curvature along left row next to GC and apply same to right side + norms = [] + xTest = [] + for n in range(int(len(xOuter[1]) * 0.5)): # d1s + xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM + norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) + for n2 in range(2, elementsCountAlong + 1): # d2s + xTest.append(xOuter[n2][-1]) # KM + norms.append(d3UnitOuter[n2][-1]) + curvatureAlong2Left = findCurvatureAlongLine(xAround2Left, d1Around2Left, norms) + + # Curvature at GC around loops - excluding annulus points + curvatureLoopsRight = [] + curvatureLoopsLeft = [] + curvaturesOnGC = [] + for n1 in range(len(xLoopsRight)): + normsRight = [] + normsLeft = [] + for n2 in range(len(xLoopsRight[n1])): + if n2 == 0: + norm = d3UnitOuter[0][n1 + 1] if n1 < len(xOuter[0]) - 1 else d3UnitOuter[n1 + 2 - len(xOuter[0])][0] + normsRight.append(norm) + normsLeft.append(norm) + elif n2 == int(elementsCountAroundOesophagus * 0.25) + 1: # bifurcation downstream + normsRight.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) - n1]) + normsLeft.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1 + n1]) + else: + normsRight.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) - 1 - n1]) + normsLeft.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + n1 + (2 if n2 <= elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) else 1)]) + + curvatureRight = findCurvatureAlongLine(xLoopsRight[n1], d2LoopsRight[n1], normsRight) + curvatureLoopsRight.append(curvatureRight) + curvatureLeft = findCurvatureAlongLine(xLoopsLeft[n1], d2LoopsLeft[n1], normsLeft) + curvatureLoopsLeft.append(curvatureLeft) + + curvatureGC = 0.5 * (curvatureRight[0] + curvatureLeft[0]) + curvaturesOnGC.append(curvatureGC) + + # Curvature around annulus + normsRight = [] + normsLeft = [] + for n2 in range(len(xAnnulusRight)): + if n2 == 0: + normsRight.append(d3UnitOuter[0][0]) + normsLeft.append(d3UnitOuter[0][0]) + elif n2 > int(elementsCountAroundOesophagus * 0.25): + normsRight.append(d3UnitOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5)]) + normsLeft.append(d3UnitOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5) + (1 if n2 < elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) else 0)]) + else: + normsRight.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5)]) + normsLeft.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + d2AnnulusRight[-1] = d2Outer[elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) + 1][int(elementsCountAroundDuodenum * 0.5)] + d2AnnulusLeft[-1] = d2Outer[elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) + 1][int(elementsCountAroundDuodenum * 0.5)] + curvatureAnnulusRight = findCurvatureAlongLine(xAnnulusRight, d2AnnulusRight, normsRight) + curvatureAnnulusLeft = findCurvatureAlongLine(xAnnulusLeft, d2AnnulusLeft, normsLeft) + curvatureAnnulusGC = (curvatureAnnulusRight[0] + curvatureAnnulusLeft[0]) * 0.5 + + # Curvature along LC + norms = [] + for n in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): + norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) + curvatureAlongLC = findCurvatureAlongLine(xOesoToDuodLC[1:], d2OesoToDuodLC[1:], norms) + + # Assemble curvatures into matrix + d1CurvatureOuter = [] + d2CurvatureOuter = [] + xCheck = [] + # GC -> n2 == 0 + d1CurvatureOuter.append(curvatureAlongGC[: len(xOuter[0])]) + d2CurvatureOuter.append([curvatureAnnulusGC] + curvaturesOnGC[:-1]) + xCheck.append(xGC[: len(xOuter[0])]) # KM + + # n2 == 1 + n2 = 1 + curvature = [] + xAround = [] + curvature.append(curvatureAlongGC[len(xOuter[0])]) + xAround.append(xGC[len(xOuter[0])]) # KM + for n1 in range(int(len(xOuter[1]) * 0.5)): + xAround.append(xOuter[1][-(1 + n1)]) # KM + curvature.append(curvatureAlong2Left[-(1 + n1)]) + for n1 in range(int(len(xOuter[1]) * 0.5)): + xAround.append(xOuter[1][int(len(xOuter[1]) * 0.5) + n1]) # KM + curvature.append(curvatureAlong2Left[n1]) + xCheck.append(xAround) # KM + d1CurvatureOuter.append(curvature) + + d2Curvature = [] + d2Curvature.append(curvatureAlongGC[-1]) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, - 1, -1): + d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAnnulusRight[n2]) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): + d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2] if n1 > 0 else curvatureAnnulusLeft[n2]) + d2CurvatureOuter.append(d2Curvature) + + # Deal with additional elementsAroundOesophagus later - + # n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25) + + # Downstream of second column + for n2 in range(int(elementsCountAroundOesophagus * 0.25), elementsCountAlong + 1): #int(elementsCountAroundOesophagus * 0.5) + 1): + d2Curvature = [] + elementsCountAround = len(xOuter[n2]) + GCIdx = len(curvatureAlongGC) - (elementsCountAlong - n2 + 1) + if n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation - ignore bifurcation + # re-arrange nodes to calculate curvature + xAround = xOuter[n2][int(elementsCountAround * 0.5) + 2:] + xOuter[n2][: int(elementsCountAround * 0.5)] + d1Around = d1Outer[n2][int(elementsCountAround * 0.5) + 2:] + d1Outer[n2][:int(elementsCountAround * 0.5)] + norms = d3UnitOuter[n2][int(elementsCountAround * 0.5) + 2:] + d3UnitOuter[n2][:int(elementsCountAround * 0.5)] + curvature = findCurvatureAlongLine(xAround, d1Around, norms) + # Arrange curvatures to match original order + x = xAround[int(elementsCountAround * 0.5) - 1: ] + [[0.0, 0.0, 0.0]] + [[0.0, 0.0, 0.0]] + xAround[:int(elementsCountAround * 0.5) - 1] # KM + xCheck.append(x) # KM + curvatureArranged = curvature[int(elementsCountAround * 0.5) - 1: ] + [0.0] + [0.0] + curvature[:int(elementsCountAround * 0.5) - 1] + d1CurvatureOuter.append(curvatureArranged) + + d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC + d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): + d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAnnulusRight[int(elementsCountAroundOesophagus * 0.25)]) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): + d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2] if n1 > 0 else curvatureAnnulusLeft[int(elementsCountAroundOesophagus * 0.25)]) + d2Curvature.append(curvatureAlong2Left[int(elementsCountAroundDuodenum * 0.5) - 1]) # next to GC + d2CurvatureOuter.append(d2Curvature) + + elif n2 == int(elementsCountAroundOesophagus * 0.25) + 1: # downstream bifurcation - include bifurcation + elementsCountAroundUpStreamBifurcation = len(xOuter[int(elementsCountAroundOesophagus * 0.25)]) + xAround = [xOuter[n2-1][int(elementsCountAround * 0.5) + 2]] + xOuter[n2][int(elementsCountAround * 0.5) + 1:] + xOuter[n2][: int(elementsCountAround * 0.5) + 1] + [xOuter[n2-1][int(elementsCountAround * 0.5) + 1]] + d1Around = [d1Outer[n2-1][int(elementsCountAround * 0.5) + 2]] + d1Outer[n2][int(elementsCountAround * 0.5) + 1:] + d1Outer[n2][:int(elementsCountAround * 0.5) + 1] + [d1Outer[n2-1][int(elementsCountAround * 0.5) + 1]] + norms = [d3UnitOuter[n2-1][int(elementsCountAround * 0.5) + 2]] + d3UnitOuter[n2][int(elementsCountAround * 0.5) + 1:] + d3UnitOuter[n2][:int(elementsCountAround * 0.5) + 1] + [d3UnitOuter[n2-1][int(elementsCountAround * 0.5) + 1]] + curvature = findCurvatureAlongLine(xAround, d1Around, norms) + # replace curvature at bifurcation in previous group of elements around + xCheck[len(xCheck) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5)] = xAround[-1] + xCheck[len(xCheck) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5) + 1] = xAround[0] + d1CurvatureOuter[len(d1CurvatureOuter) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5)] = curvature[-1] + d1CurvatureOuter[len(d1CurvatureOuter) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5) + 1] = curvature[0] + # rearrange the rest + x = xAround[int(elementsCountAround * 0.5) + 1: - 1] + xAround[1:int(elementsCountAround * 0.5)+ 1] #KM + xCheck.append(x) # KM + curvatureArranged = curvature[int(elementsCountAround * 0.5) + 1: - 1] + curvature[1:int(elementsCountAround * 0.5) + 1] + d1CurvatureOuter.append(curvatureArranged) + + d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC + d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, 0, -1): + d2Curvature.append(curvatureLoopsRight[n1 - 1][n2]) + for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): + d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2]) + d2Curvature.append(curvatureAlong2Left[int(elementsCountAroundDuodenum * 0.5)]) # next to GC + d2CurvatureOuter.append(d2Curvature) + + elif n2 > int(elementsCountAroundOesophagus * 0.25) + 1 and n2 <= int(elementsCountAroundOesophagus * 0.5): + xAround = xOuter[n2][int(elementsCountAround * 0.5) + 1:] + xOuter[n2][: int(elementsCountAround * 0.5) + 1] + d1Around = d1Outer[n2][int(elementsCountAround * 0.5) + 1:] + d1Outer[n2][: int(elementsCountAround * 0.5) + 1] + norms = d3UnitOuter[n2][int(elementsCountAround * 0.5) + 1:] + d3UnitOuter[n2][: int(elementsCountAround * 0.5) + 1] + curvature = findCurvatureAlongLine(xAround, d1Around, norms) + x = xAround[int(elementsCountAround * 0.5): ] + xAround[:int(elementsCountAround * 0.5)] # KM + curvatureArranged = curvature[int(elementsCountAround * 0.5):] + curvature[:int(elementsCountAround * 0.5)] + d1CurvatureOuter.append(curvatureArranged) + xCheck.append(x) # KM + + d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC + d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): + d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAnnulusRight[int(elementsCountAroundOesophagus * 0.25) + 1]) + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): + d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2] if n1 > 0 else curvatureAnnulusLeft[int(elementsCountAroundOesophagus * 0.25) + 1]) + d2Curvature.append(curvatureAlong2Left[int(elementsCountAroundDuodenum * 0.5) + 1]) # next to GC + d2CurvatureOuter.append(d2Curvature) + + elif n2 > int(elementsCountAroundOesophagus * 0.5): # Downstream of oesophagus + d1CurvatureOuter.append(findCurvatureAroundLoop(xOuter[n2], d1Outer[n2], d3UnitOuter[n2])) + + d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC + d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): + d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAlongLC[n2 - (elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) + 1)]) + for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): + d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2]) + d2Curvature.append(curvatureAlong2Left[GCIdx - 1]) # next to GC + d2CurvatureOuter.append(d2Curvature) + + # Create inner nodes + xList = [] + d1List = [] + d2List = [] + d3List = [] + nodeIdx = bodyStartNode + + idxMat = [] + + for n2 in range(elementsCountAlong + 1): + idxThroughWall = [] + for n3 in range(elementsCountThroughWall + 1): + xi3 = 1 / elementsCountThroughWall * n3 + idxAround = [] + for n1 in range(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 * xi3 * d1CurvatureOuter[n2][n1] + d1 = [factor * c for c in d1Outer[n2][n1]] + d1List.append(d1) + + # d2 + factor = 1.0 - wallThickness * xi3 * d2CurvatureOuter[n2][n1] + d2 = [factor * c for c in d2Outer[n2][n1]] + d2List.append(d2) + + # d3 + d3 = [c * wallThickness / elementsCountThroughWall for c in norm] + d3List.append(d3) + + idxAround.append(nodeIdx) + nodeIdx += 1 + + idxThroughWall.append(idxAround) + idxMat.append(idxThroughWall) + + # Assemble endPoints for annulus + endPoints_x = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endPoints_d1 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endPoints_d2 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endNode_Id = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endDerivativesMap = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + + thicknessIdx = [0, -1] + for nAround in range(elementsCountAroundOesophagus): + for n3 in range(len(thicknessIdx)): + if nAround == 0: + idx = idxMat[nAround][thicknessIdx[n3]][0] + elif nAround <= int(elementsCountAroundOesophagus * 0.25): + idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] + elif int(elementsCountAroundOesophagus * 0.25) < nAround < int(elementsCountAroundOesophagus * 0.5): + idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] + elif nAround == int(elementsCountAroundOesophagus * 0.5): + idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] + elif nAround > int(elementsCountAroundOesophagus * 0.5): + idx = endNode_Id[n3][int(elementsCountAroundOesophagus * 0.5) - (nAround - int(elementsCountAroundOesophagus * 0.5))] + 1 + + endPoints_x[n3][nAround] = xList[idx] + endPoints_d1[n3][nAround] = d1List[idx] + endPoints_d2[n3][nAround] = d2List[idx] + endNode_Id[n3][nAround] = idx + + for nAround in range(elementsCountAroundOesophagus): + if nAround == 0: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + elif 0 < nAround < int(elementsCountAroundOesophagus * 0.5): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) + elif nAround == int(elementsCountAroundOesophagus * 0.5): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = (None, None, None) + elif int(elementsCountAroundOesophagus * 0.5) < nAround < elementsCountAroundOesophagus: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + + 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 + + # for n2 in range(len(xOuter)): + # for n1 in range(len(xOuter[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[n2][n1]) + # nodeIdentifier += 1 + + # Create element + mesh = fm.findMeshByDimension(3) + + 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) + result = elementtemplateStandard.defineField(coordinates, -1, eftStandard) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + elementIdentifier = nextElementIdentifier + + # Row 1 + e2 = 0 + startNode = bodyStartNode + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(int(elementsCountAround1) * 2 + 1): + if e1 != elementsCountAround1: + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < elementsCountAround1: + scaleFactors = [-1.0] + if e1 == 0: + bni11 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + e1 + bni12 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - 1 + else: + bni11 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 + bni12 = bni11 - 1 + bni21 = startNode + elementsAroundThroughWall + 1 + e1 + e3 * elementsCountAround2 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + (elementsCountAround2 if e1 == 0 else elementsCountAround1), + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS1DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], [Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS2DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > elementsCountAround1: + if e1 < elementsCountAround1 * 2: + bni11 = startNode + e1 - elementsCountAround1 - 1 + elementsCountAround1 * e3 + bni12 = bni11 + 1 + else: + bni11 = startNode + elementsCountAround1 + e3 * elementsCountAround1 - 1 + bni12 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + (elementsCountAround1 if e1 < elementsCountAround1 * 2 else elementsCountAround2), + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Row 2 + e2 = 1 + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 2): + if e1 != int(elementsCountAround1 * 0.5 + 1): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + + if e1 < 2: + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) # % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + e1 + bni22 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + (e1 + 1) # % elementsCountAround2 + if e1 == 0: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], 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, [])]) + 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_DS2, [])]) + elif e1 == 1: # Bottom right wedge + nodeIdentifiers = [bni11, bni21, bni22, + bni11 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > 1 and e1 < elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + elif e1 >= elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 2 + bni12 = startNode + e3 * elementsCountAround1 + (e1 - 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + if e1 == elementsCountAround1: # Bottom left wedge + nodeIdentifiers = [bni12, bni21, bni22, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([2, 6]) + elif e1 == elementsCountAround1 + 1: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Upstream bifurcation + e2 = int(elementsCountAroundOesophagus * 0.25) + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1): + if e1 != int(elementsCountAround1 * 0.5): + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + + if e1 < int(elementsCountAround1 * 0.5) - 1: + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + elif e1 == int(elementsCountAround1 * 0.5) - 1: # right wedge + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == int(elementsCountAround1 * 0.5) + 1: # left wedge + bni21 = bni21 - 1 + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni21 = bni21 - 2 + bni22 = startNode + elementsAroundThroughWall + (e1 - 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Downstream bifurcation + e2 = int(elementsCountAroundOesophagus * 0.25) + 1 + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 1): + if e1 < int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 + elif e1 == int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode - len(xOuter[e2-1]) * (elementsCountThroughWall + 1) + e3 * len(xOuter[e2 - 1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + + if e1 < int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + elif e1 == int(elementsCountAround1 * 0.5): + bni12 = startNode - len(xOuter[e2-1]) * (elementsCountThroughWall + 1) + e3 * len(xOuter[e2-1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + + if e1 > int(elementsCountAround1 * 0.5): + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = startNode + elementsAroundThroughWall + (e1 + 2) % elementsCountAround2 + elementsCountAround2 * e3 + else: + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + (len(xOuter[e2 - 1]) if e1 == int(elementsCountAround1 * 0.5) + 1 else elementsCountAround1), + bni12 + (len(xOuter[e2 - 1]) if e1 == int(elementsCountAround1 * 0.5) else elementsCountAround1), + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplateStandard) + result = element.setNodesByIdentifier(eftStandard, nodeIdentifiers) + elementIdentifier = elementIdentifier + 1 + + # Penultimate row connecting to annulus and beyond + for e2 in range(int(elementsCountAroundOesophagus * 0.5), elementsCountAlong): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 - (1 if e2 == int(elementsCountAroundOesophagus * 0.5) else 0)): + scaleFactors = [] # check if needed + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e2 == int(elementsCountAroundOesophagus * 0.5): + bni11 = startNode + e3 * elementsCountAround1 + e1 + (0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni12 = startNode + e3 * elementsCountAround1 + (e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 + # Remap elements next to annulus + if e1 == int(elementsCountAround1 * 0.5) - 1: + scaleFactors = [-1.0] # check if needed + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == int(elementsCountAround1 * 0.5): + scaleFactors = [-1.0] # check if needed + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + else: + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Annulus + 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) + + for n2 in range(len(xTrackSurface)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + nodeIdentifier += 1 + + fm.endChange() + + annotationGroup = [] + return annotationGroup + + @classmethod + def refineMesh(cls, meshrefinement, options): + """ + Refine source mesh into separate region, with change of basis. + :param meshrefinement: MeshRefinement, which knows source and target region. + :param options: Dict containing options. See getDefaultOptions(). + """ + refineElementsCountAround = options['Refine number of elements around'] + refineElementsCountAlong = options['Refine number of elements along'] + refineElementsCountThroughWall = options['Refine number of elements through wall'] + + meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, + refineElementsCountThroughWall) + return + +def findClosestPositionAndDerivativeOnTrackSurface(x, nx, trackSurface, nxProportion1, elementsCountAlongTrackSurface): + """ + Find the closest position and derivative around the tracksurface of a point sitting near the fundus of stomach. + Use a startPosition to improve the search for nearest position on the track surface as the fundus has a curved + and complex track surface. + + :param x: coordinates of point of interest + :param nx: coordinates of points along curve where point of interest lies. + :param trackSurface: track surface where point sits + :param nxProportion1: proportion around track surface of curve + :param elementsCountAlongTrackSurface: number of elements along track surface + :return: position and derivative of point around track surface + """ + closestIdxOnNx = interp.getNearestPointIndex(nx, x) + closestPositionToPoint = trackSurface.createPositionProportion(nxProportion1, closestIdxOnNx / elementsCountAlongTrackSurface) + xPosition = trackSurface.findNearestPosition(x, closestPositionToPoint) + d = trackSurface.evaluateCoordinates(xPosition, derivatives=True)[1] + + return xPosition, d + +def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, startProportion2, endProportion1, + endProportion2, elementsOut, startDerivative = None, endDerivative = None, + startDerivativeMagnitude = None, endDerivativeMagnitude = None): + """ + Create smoothly spaced out hermite curve points between two points a and b on the surface, + each defined by their proportions over the surface in directions 1 and 2. + :param trackSurface: track surface + :param startProportion1, startProportion2: proportion of start point in direction around and along track surface + :param endProportion1, endProportion2: proportion of end point in direction around and along track surface + :param elementsOut: number of elements out + :param startDerivative, endDerivative: optional derivative vectors in 3-D world coordinates + to match at the start and end of the curves. If omitted, fits in with other derivative or is + in a straight line from a to b. + :param derivativeMagnitudeStart, derivativeMagnitudeEnd: optional magnitude of derivatives to match at the start and + end of the curves. + :return: coordinates and derivative of sampled points + """ + + mx, md2, md1, md3, mProportions = \ + trackSurface.createHermiteCurvePoints(startProportion1, startProportion2, endProportion1, endProportion2, + elementsOut, startDerivative, endDerivative) + + xSampled, dSampled = trackSurface.resampleHermiteCurvePointsSmooth(mx, md2, md1, md3, mProportions, + startDerivativeMagnitude, + endDerivativeMagnitude)[0:2] + return xSampled, dSampled + +def findDerivativeBetweenPoints(v1, v2): + """ + + :param v1: + :param v2: + :return: + """ + 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): + """ + + :param nx: + :param nd: + :param radialVectors: + :return: + """ + curvature = [] + for n in range(len(nx)): + prevIdx = n - 1 if n > 0 else -1 + nextIdx = n + 1 if n < len(nx) - 1 else 0 + kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) + kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) + curvature.append(0.5 * (kappam + kappap)) + + return curvature + +def findCurvatureAlongLine(nx, nd, radialVectors): + """ + + :param nx: + :param nd: + :param radialVectors: + :return: + """ + curvature = [] + for n in range(len(nx)): + if n == 0: + curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) + elif n == len(nx) - 1: + curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) + else: + curvature.append(0.5 * ( + interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + + interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) + + return curvature + diff --git a/src/scaffoldmaker/scaffolds.py b/src/scaffoldmaker/scaffolds.py index 26432774..c421b029 100644 --- a/src/scaffoldmaker/scaffolds.py +++ b/src/scaffoldmaker/scaffolds.py @@ -37,6 +37,7 @@ from scaffoldmaker.meshtypes.meshtype_3d_sphereshell1 import MeshType_3d_sphereshell1 from scaffoldmaker.meshtypes.meshtype_3d_sphereshellseptum1 import MeshType_3d_sphereshellseptum1 from scaffoldmaker.meshtypes.meshtype_3d_stellate1 import MeshType_3d_stellate1 +from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1 from scaffoldmaker.meshtypes.meshtype_3d_stomachhuman1 import MeshType_3d_stomachhuman1 from scaffoldmaker.meshtypes.meshtype_3d_tube1 import MeshType_3d_tube1 from scaffoldmaker.meshtypes.meshtype_3d_tubeseptum1 import MeshType_3d_tubeseptum1 @@ -81,6 +82,7 @@ def __init__(self): MeshType_3d_sphereshell1, MeshType_3d_sphereshellseptum1, MeshType_3d_stellate1, + MeshType_3d_stomach1, MeshType_3d_stomachhuman1, MeshType_3d_tube1, MeshType_3d_tubeseptum1, diff --git a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py index f225f3de..2abb705f 100644 --- a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py +++ b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py @@ -1657,3 +1657,29 @@ def replaceTwoElementWithInlet6(self, origElement1, origElement2, startElementId self._mesh.destroyElement(origElement1) self._mesh.destroyElement(origElement2) fm.endChange() + + def createEftWedgeCollapseXi2(self, collapseNodes): + ''' + EDIT + Create a tricubic hermite element field for a wedge element, where xi2 collapsed on xi1 = 1. + :return: Element field template + ''' + eft = self.createEftBasic() + + if collapseNodes in [[4, 8]]: + nodes = [2, 4, 6, 8] + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + ln_map = [1, 2, 3, 2, 4, 5, 6, 5] + + elif collapseNodes in [[3, 7]]: + nodes = [1, 3, 5, 7] + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + ln_map = [1, 2, 1, 3, 4, 5, 4, 6] + + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS2DS3, []) + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D3_DS1DS2DS3, []) + + remapEftLocalNodes(eft, 6, ln_map) + assert eft.validate(), 'eftfactory_tricubichermite.createEftWedgeCollapseXi2: Failed to validate eft' + return eft From efd7386bf17726462345402ae4c13902f913ddf1 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 2 Apr 2021 10:39:16 +1300 Subject: [PATCH 02/38] Space out elements at triple point --- .../meshtypes/meshtype_3d_stomach1.py | 3213 ++++++++++------- src/scaffoldmaker/scaffolds.py | 2 + .../utils/eftfactory_tricubichermite.py | 3 + 3 files changed, 1943 insertions(+), 1275 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index a7cc6fc8..412952ed 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -16,6 +16,7 @@ from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d +from scaffoldmaker.utils.bifurcation import get_bifurcation_triple_point from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite from scaffoldmaker.utils.eft_utils import scaleEftNodeValueLabels, setEftScaleFactorIds, remapEftNodeValueLabel @@ -36,29 +37,27 @@ class MeshType_3d_stomach1(Scaffold_base): direction. """ centralPathDefaultScaffoldPackages = { - 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { + 'Generic 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 5 + 'Number of elements': 4 }, 'meshEdits': exnodeStringFromNodeValues( [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], [ - [[17.0, 14.0, 0.0], [-12.4, -22.4, 0.0], [7.9, -4.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, 0.0]], - [[10.0, 0.0, 0.0], [-19.8, -2.6, 0.0], [1.1, -8.9, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0], [-19.8, -2.6, 0.0], [1.1, -8.9, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, 0.0]], - [[-10.0, 7.0, 0.0], [-8.1, 9.4, 0.0], [-1.9, -1.6, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.5], - [0.0, 0.0, 0.0]], - [[-15.0, 7.0, 0.0], [-8.1, 9.4, 0.0], [-1.9, -1.6, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.5], - [0.0, 0.0, 0.0]], - [[-17.0, 14.0, 0.0], [0.2, 2.6, 0.0], [-3.5, 0.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 3.5], - [0.0, 0.0, 0.0]]]) + [[17.0, 14.0, 0.0], [-17.9, -22.1, 0.0], [7.0, -5.7, 0.0], [-3.3, -6.2, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 1.4]], + [[0.0, 0.0, 0.0], [-15.4, -5.0, 0.0], [2.8, -8.5, 0.0], [-5.2, 0.6, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, -1.4]], + [[-9.7, 0.7, 0.0], [-8.6, 3.8, 0.0], [-2.8, -6.4, 0.0], [-2.1, 3.7, 0.0], [0.0, 0.0, 7.0], + [0.0, 0.0, -3.3]], + [[-15.9, 6.6, 0.0], [-4.8, 6.8, 0.0], [-2.0, -1.4, 0.0], [-0.3, 2.7, 0.0], [0.0, 0.0, 2.5], + [0.0, 0.0, -1.6]], + [[-19.2, 13.9, 0.0], [-1.7, 7.6, 0.0], [-3.4, -0.8, 0.0], [-2.5, -1.4, 0.0], [0.0, 0.0, 3.5], + [0.0, 0.0, 3.6]]]) }), 'Human 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { @@ -66,24 +65,74 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 3 + 'Number of elements': 4 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[17.0, 14.0, 0.0], [-17.9, -22.1, 0.0], [7.0, -5.7, 0.0], [-3.3, -6.2, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 1.4]], + [[0.0, 0.0, 0.0], [-15.4, -5.0, 0.0], [2.8, -8.5, 0.0], [-5.2, 0.6, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, -1.4]], + [[-9.7, 0.7, 0.0], [-8.6, 3.8, 0.0], [-2.8, -6.4, 0.0], [-2.1, 3.7, 0.0], [0.0, 0.0, 7.0], + [0.0, 0.0, -3.3]], + [[-15.9, 6.6, 0.0], [-4.8, 6.8, 0.0], [-2.0, -1.4, 0.0], [-0.3, 2.7, 0.0], [0.0, 0.0, 2.5], + [0.0, 0.0, -1.6]], + [[-19.2, 13.9, 0.0], [-1.7, 7.6, 0.0], [-3.4, -0.8, 0.0], [-2.5, -1.4, 0.0], [0.0, 0.0, 3.5], + [0.0, 0.0, 3.6]]]) + }), + 'Human straight 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 4 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.0, 1.2], [0.0, -0.7, 9.0], + [0.0, 1.2, 1.2]], + [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -8.9, -0.1], [0.0, 1.2, 0.0], [0.0, -0.1, 9.0], + [0.0, 0.0, -1.3]], + [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -7.0, -0.4], [0.0, 3.4, 0.0], [0.0, -0.4, 7.0], + [0.0, 0.0, -3.4]], + [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.7, 0.2], [0.0, -0.1, 2.5], + [0.0, 0.2, -1.7]], + [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.1, 0.2], [0.0, 0.1, 3.5], + [0.0, 0.2, 3.7]]]) + }), + 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 6 }, 'meshEdits': exnodeStringFromNodeValues( [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], [ - [[17.0, 14.0, 0.0], [-12.4, -22.4, 0.0], [7.9, -4.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0], [-19.8, -2.6, 0.0], [1.1, -8.9, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, 0.0]], - [[-15.0, 7.0, 0.0], [-6.2, 7.0, 0.0], [-2.0, -1.4, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 2.5], - [0.0, 0.0, 0.0]], - [[-19.2, 13.9, 0.0], [-4.1, 9.0, 0.0], [-3.2, -1.4, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 3.5], - [0.0, 0.0, 0.0]]]) + [[10.7, 13.3, 0.0], [3.3, -16.0, 0.0], [8.7, -1.4, 0.0], [0.5, -3.7, 0.0], [0.0, 0.0, 7.4], + [0.0, 0.0, 1.6]], + [[9.5, -0.2, 0.0], [-6.0, -9.6, 0.0], [6.6, -5.1, 0.0], [-3.9, -4.3, 0.0], [0.0, 0.0, 8.5], + [0.0, 0.0, 0.7]], + [[2.3, -5.2, 0.0], [-9.3, -2.2, 0.0], [2.1, -9.1, -0.0], [-6.4, -1.6, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, -0.1]], + [[-7.8, -3.9, 0.0], [-7.5, 4.2, 0.0], [-6.0, -8.0, 0.0], [-3.4, 3.4, 0.0], [0.0, 0.0, 8.1], + [0.0, 0.0, -1.5]], + [[-11.7, 1.7, 0.0], [-1.7, 7.2, 0.0], [-6.4, -3.5, 0.0], [1.4, 4.0, 0.0], [0.0, 0.0, 6.2], + [0.0, 0.0, -2.8]], + [[-10.7, 9.4, 0.0], [0.1, 6.6, 0.0], [-2.9, 0.0, 0.0], [1.1, 1.3, 0.0], [0.0, 0.0, 2.4], + [0.0, 0.0, -1.0]], + [[-11.3, 14.8, 0.0], [-1.2, 4.1, 0.0], [-3.5, -0.3, 0.0], [-2.3, -1.9, 0.0], [0.0, 0.0, 3.4], + [0.0, 0.0, 3.0]]]) }), } ostiumDefaultScaffoldPackages = { - 'Rat 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'Human 1': ScaffoldPackage(MeshType_3d_ostium1, { 'scaffoldSettings': { 'Number of vessels': 1, 'Number of elements across common': 2, @@ -112,7 +161,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Refine number of elements through wall': 1 }, }), - 'Human 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'Rat 1': ScaffoldPackage(MeshType_3d_ostium1, { 'scaffoldSettings': { 'Number of vessels': 1, 'Number of elements across common': 2, @@ -151,14 +200,22 @@ def getName(): def getParameterSetNames(): return [ 'Default', - 'Rat 1', - 'Human 1'] + 'Generic 1', + 'Human 1', + 'Human straight 1', + 'Rat 1'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Rat 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] + elif 'Generic 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Generic 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + elif 'Human straight 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Human straight 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] else: centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] @@ -171,7 +228,12 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements through wall': 1, 'Wall thickness': 0.5, 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), - 'Gastro-oesophagal junction position along factor': 0.3, + 'Gastro-oesophagal junction position along factor': 0.35, + 'Annulus derivative factor': 1.0, + 'Number of radial elements in annulus': 1, # KM + 'Show track surface': False, # KM + 'Make stomach': True, # KM + 'Show central path': False, # KM 'Use cross derivatives': False, 'Use linear through wall' : False, # need to deal with wedge not available in bicubichermite 'Refine': False, @@ -179,7 +241,8 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } - # Add default options for Rat and human later + if 'Rat 1' in parameterSetName: + options['Gastro-oesophagal junction position along factor'] = 0.55 cls.updateSubScaffoldOptions(options) return options @@ -195,6 +258,11 @@ def getOrderedOptionNames(): 'Wall thickness', 'Gastro-oesophagal junction', 'Gastro-oesophagal junction position along factor', + 'Annulus derivative factor', + 'Number of radial elements in annulus', + 'Show track surface', + 'Make stomach', + 'Show central path', 'Use cross derivatives', 'Use linear through wall', 'Refine', @@ -251,6 +319,8 @@ def checkOptions(cls, options): MeshType_3d_ostium1) if options['Number of elements around oesophagus'] < 8: options['Number of elements around oesophagus'] = 8 + if options['Number of elements around oesophagus'] % 4 > 0: + options['Number of elements around oesophagus'] = options['Number of elements around oesophagus'] // 4 * 4 if options['Number of elements around duodenum'] < 12: options['Number of elements around duodenum'] = 12 for key in [ @@ -260,9 +330,10 @@ def checkOptions(cls, options): options[key] += 1 if options['Number of elements along'] < 8: options['Number of elements along'] = 8 - if options['Number of elements through wall'] < 1: - options['Number of elements through wall'] = 1 + if options['Annulus derivative factor'] < 0: + options['Annulus derivative factor'] = 0.0 for key in [ + 'Number of elements through wall', 'Refine number of elements around', 'Refine number of elements along', 'Refine number of elements through wall']: @@ -303,6 +374,12 @@ def generateBaseMesh(cls, region, options): GOJOptions = options['Gastro-oesophagal junction'] GOJSettings = GOJOptions.getScaffoldSettings() oesophagusDiameter = GOJSettings['Ostium diameter'] + annulusDerivativeFactor = options['Annulus derivative factor'] + elementsCountAnnulus = options['Number of radial elements in annulus'] + + trackSurface = options['Show track surface'] + makeStomach = options['Make stomach'] + showCentralPath = options['Show central path'] elementsCountAlongTrackSurface = 20 @@ -345,12 +422,23 @@ def generateBaseMesh(cls, region, options): Node.VALUE_LABEL_D2_DS1DS3]) del tmpRegion # for i in range(len(cx)): + # # print(vector.magnitude(cd2[i]), vector.magnitude(cd3[i])) + # cd3[i] = vector.setMagnitude(cd3[i], vector.magnitude(cd2[i])) # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongTrackSurface) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) + # Make sampled d2 and d3 normal to central path + # d2Check = [] + # for c in range(len(sx)): + # td2 = vector.vectorRejection(sd2[c], sd1[c]) + # sd2[c] = vector.setMagnitude(td2, vector.magnitude(sd2[c])) + # d2Check.append(matrix.rotateAboutZAxis(sd2[c], math.pi)) + # td3 = vector.vectorRejection(sd3[c], sd1[c]) + # sd3[c] = vector.setMagnitude(td3, vector.magnitude(sd3[c])) + # Calculate length of central path stomachCentralPathLength = 0.0 for e in range(len(sx) - 1): @@ -370,7 +458,8 @@ def generateBaseMesh(cls, region, options): d2 = sd2[0] for n1 in range(elementsCountAroundDuodenum): rotAngle = n1 * 2.0 * math.pi / elementsCountAroundDuodenum - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(sd1[0]), rotAngle) + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) # vector.normalise(sd1[0]) + 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)] d2Apex.append(d2Rot) @@ -417,6 +506,15 @@ def generateBaseMesh(cls, region, options): # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) # nodeIdentifier += 1 + # for n1 in range(len(sx)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd1[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd2[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Check[n1]) + # nodeIdentifier += 1 + # Merge fundus and body xAll = [[sx[0]] * elementsCountAroundDuodenum] + xEllipses d2All = [d2Apex] + d2Ellipses @@ -502,1274 +600,1838 @@ def generateBaseMesh(cls, region, options): trackSurfaceStomach = TrackSurface(elementsCountAroundDuodenum, elementsCountAlongTrackSurface, xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) - # for n2 in range(len(xTrackSurface)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TrackSurface[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TrackSurface[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Set up gastro-oesophagal junction - GOJSettings['Number of elements around ostium'] = elementsCountAroundOesophagus - GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) - xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) - axis1 = d1Centre - - # fm = region.getFieldmodule() - mesh = fm.findMeshByDimension(3) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - - nextNodeIdentifier = nodeIdentifier - nextElementIdentifier = elementIdentifier - nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, - nextNodeIdentifier, nextElementIdentifier) - bodyStartNode = nextNodeIdentifier - - # From oesophagus to duodenum along lesser curvature (LC) - elementsOesoToDuodLC = elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) # CHECK - startProportion1, startProportion2 = trackSurfaceStomach.getProportion( - o1_Positions[int(elementsCountAroundOesophagus * 0.5)]) - d1Start = o1_d2[1][int(elementsCountAroundOesophagus * 0.5)] - - xOesoToDuodLC, d2OesoToDuodLC = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, 0.5, 1.0, - elementsOesoToDuodLC) - - # From oesophagus to duodenum along greater curvature (GC) - xAlongGC = [] - d2AlongGC = [] - xAlongGC.append(o1_x[1][0]) - d2AlongGC.append(o1_d2[1][0]) - - oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] - elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) - - # From oesophagus to fundus apex - arcLengthOesoApex = 0.0 - for n2 in range(elementsAlongUpstreamOfOeso): - nAlong = elementsAlongUpstreamOfOeso - n2 - v1 = xSampledAll[nAlong][int(elementsCountAroundDuodenum * 0.5)] - v2 = xSampledAll[nAlong - 1][int(elementsCountAroundDuodenum * 0.5)] - d = [v2[c] - v1[c] for c in range(3)] - arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) - arcLengthOesoApex += arcLengthAround - d2 = [c * arcLengthAround for c in vector.normalise(d)] - xAlongGC.append(v1) - d2AlongGC.append(d2) - - # From fundus apex to duodenum - for n2 in range(len(xSampledAll)): - xAlongGC.append(xSampledAll[n2][0]) - d2AlongGC.append(d2SampledAll[n2][0]) - - elementsOesoToDuodGC = elementsCountAlong + int(elementsCountAroundDuodenum * 0.5) - 2 # Check, old - elementsCountAlong + int(elementsCountAroundOesophagus * 0.5) - xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurvesSmooth(xAlongGC, d2AlongGC, elementsOesoToDuodGC, - derivativeMagnitudeStart=0.5 * vector.magnitude( - d2AlongGC[0]))[0:2] - - arcLength = 0.0 - for e in range(len(xOesoToDuodGC) - 1): - arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], - xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) - if arcLength > arcLengthOesoApex: - nodesCountFromOesoToApex = e + 2 - break - - d2OesoToDuodGC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2OesoToDuodGC) - - nodeIdentifier = nextNodeIdentifier - - # for n2 in range(len(xOesoToDuodLC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # for n2 in range(len(xOesoToDuodGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Spread out elements around for each egroup around - # Elements around oesophagus - # Decide where to put extra elements if elementsOesophagus/2 is odd number. - # Right now, extra elements go downstream of bifurcation - # For even numbers, we split elements at bifurcation - - ptsOnTrackSurfaceGC = [] - xAlongAround = [] - d1AlongAround = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) - - for idx in range(math.ceil(elementsCountAroundOesophagus * 0.25)): + if makeStomach: + # Set up gastro-oesophagal junction + GOJSettings['Number of elements around ostium'] = elementsCountAroundOesophagus + GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) + xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) + axis1 = d1Centre + + # fm = region.getFieldmodule() + mesh = fm.findMeshByDimension(3) + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + + nextNodeIdentifier = nodeIdentifier + nextElementIdentifier = elementIdentifier + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, + nextNodeIdentifier, nextElementIdentifier) + bodyStartNode = nextNodeIdentifier + + # From oesophagus to duodenum along lesser curvature (LC) + elementsOesoToDuodLC = elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) # CHECK + startProportion1, startProportion2 = trackSurfaceStomach.getProportion( + o1_Positions[int(elementsCountAroundOesophagus * 0.5)]) + d1Start = o1_d2[1][int(elementsCountAroundOesophagus * 0.5)] + + xOesoToDuodLC, d2OesoToDuodLC = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, 0.5, 1.0, + elementsOesoToDuodLC, startDerivative=d1Start, + startDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude(d1Start)) + + # From oesophagus to duodenum along greater curvature (GC) + xAlongGC = [] + d2AlongGC = [] + xAlongGC.append(o1_x[1][0]) + d2AlongGC.append(o1_d2[1][0]) + + oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] + elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) + + # From oesophagus to fundus apex + arcLengthOesoApex = 0.0 + for n2 in range(elementsAlongUpstreamOfOeso): + nAlong = elementsAlongUpstreamOfOeso - n2 + v1 = xSampledAll[nAlong][int(elementsCountAroundDuodenum * 0.5)] + v2 = xSampledAll[nAlong - 1][int(elementsCountAroundDuodenum * 0.5)] + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + arcLengthOesoApex += arcLengthAround + d2 = [c * arcLengthAround for c in vector.normalise(d)] + xAlongGC.append(v1) + d2AlongGC.append(d2) + + # From fundus apex to duodenum + for n2 in range(len(xSampledAll)): + xAlongGC.append(xSampledAll[n2][0]) + d2AlongGC.append(d2SampledAll[n2][0]) + + elementsOesoToDuodGC = elementsCountAlong + int(elementsCountAroundDuodenum * 0.5) - 2 # Check + xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurvesSmooth(xAlongGC, d2AlongGC, elementsOesoToDuodGC, + derivativeMagnitudeStart=annulusDerivativeFactor * vector.magnitude( + d2AlongGC[0]))[0:2] + # xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurves(xAlongGC, d2AlongGC, elementsOesoToDuodGC, + # addLengthStart= vector.magnitude( + # d2AlongGC[0]), lengthFractionStart=0.5)[0:2] + + d2OesoToDuodGC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2OesoToDuodGC) + # curvature - DONE + + arcLength = 0.0 + for e in range(len(xOesoToDuodGC) - 1): + arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], + xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) + if arcLength > arcLengthOesoApex: + nodesCountFromOesoToApex = e + 2 + break + + nodeIdentifier = nextNodeIdentifier + + # for n2 in range(len(xOesoToDuodLC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # for n2 in range(len(xOesoToDuodGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Spread out elements around for each egroup around + # Elements around oesophagus + # Decide where to put extra elements if elementsOesophagus/2 is odd number. + # Right now, extra elements go downstream of bifurcation + # For even numbers, we split elements at bifurcation + + ptsOnTrackSurfaceGC = [] + xAlongAround = [] + d1AlongAround = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) + + # Ring adjacent to LC # First half - ostiumIdx = int(elementsCountAroundOesophagus * 0.25) + idx - GCIdx = -(elementsCountAlong - int(elementsCountAroundOesophagus * 0.25)) + idx # 4 - elementsCountAlong - math.ceil(elementsCountAroundOesophagus * 0.25) + idx - - # Find closest position to point on GC as track surface is not a simple geometry near dome - GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) - GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) - - endPosition = o1_Positions[ostiumIdx] - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) - d2 = o1_d2[1][ostiumIdx] - d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] - # remove d1Ave when cleaning up code - xi = 0 #ostiumIdx / int(elementsCountAroundOesophagus * 0.5) - d1Ave = [d1EndOstium[c] * (1 - xi) + d1EndTrackSurface[c] * xi for c in range(3)] - - xFirstHalf, d1FirstHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, - endProportion2, int(0.5 * elementsCountAroundDuodenum + 1), - startDerivative=d1GC, endDerivative=d1Ave, - endDerivativeMagnitude= 0.5 * vector.magnitude(d1Ave)) - - # Second half - ostiumIdx2 = elementsCountAroundOesophagus - (int(elementsCountAroundOesophagus * 0.25) + idx) - startPosition = o1_Positions[ostiumIdx2] - d1StartOstium = o1_d2[1][ostiumIdx2] - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] - # Clean up - d1Ave = [d1StartOstium[c] * (1 - xi) + d1StartTrackSurface[c] * xi for c in range(3)] - - xSecondHalf, d1SecondHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, - GCProportion2, int(0.5 * elementsCountAroundDuodenum + 1), - startDerivative=d1Ave, endDerivative=d1GC, - startDerivativeMagnitude= 0.5 * vector.magnitude(d1Ave)) - - xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] - d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] - - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - - # Elements downstream of oesophagus - for idx in range(-(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5)), 0): #4 - elementsCountAlong, 0): - startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], - ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, - elementsCountAlongTrackSurface) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - - endPosition = trackSurfaceStomach.findNearestPosition(xOesoToDuodLC[idx]) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - d1End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] - - xFirstHalf, d1FirstHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, startProportion2, endProportion1, - endProportion2, int(0.5 * elementsCountAroundDuodenum), - startDerivative=d1Start, endDerivative=d1End) - - xSecondHalf, d1SecondHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, endProportion1, endProportion2, 1.0, - startProportion2, int(0.5 * elementsCountAroundDuodenum), - startDerivative=d1End, endDerivative=d1Start) - - xAround = xFirstHalf + xSecondHalf[1:-1] - d1Around = d1FirstHalf + d1SecondHalf[1:-1] - d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - - # for n2 in range(len(xAlongAround)): - # for n1 in range(len(xAlongAround[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # # Joining loops at fundus - ptsOnTrackSurfaceOesoToFundus = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][int(elementsCountAroundDuodenum * 0.5)]) - - xLoopsRight = [] - d2LoopsRight = [] - xLoopsLeft = [] - d2LoopsLeft = [] - - for n in range(int(elementsCountAroundDuodenum * 0.5 - 1)): - GCIdx = n + 1 - if GCIdx < nodesCountFromOesoToApex: - ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus - proportion1 = 0.5 - else: - ptsOnTrackSurface = ptsOnTrackSurfaceGC - proportion1 = 0.0 - d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], - ptsOnTrackSurface, - trackSurfaceStomach, proportion1, - elementsCountAlongTrackSurface)[1] - - if GCIdx < nodesCountFromOesoToApex: - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) - d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] - d2GC = d2GCRot - - d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) - n][c] - - xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - n][c] for c in range(3)] - - nx = [ xOesoToDuodGC[GCIdx], xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - n]] - nd2 = [d2GC, d2End] - xRight, d2Right = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25) + (1 if n > 0 else 0), arcLengthDerivatives=True)[0:2] - - # Calculate and append d2 for elements downstream of loop - if n == 0: - xAnnulusRight = xRight - d2AnnulusRight = d2Right - x1 = xAlongAround[1][int(elementsCountAroundDuodenum * 0.5)] - x2 = xOesoToDuodLC[1] - d2 = findDerivativeBetweenPoints(x1, x2) - xAnnulusRight += [x1, x2] - d2AnnulusRight += [d2, d2OesoToDuodLC[1]] - d2AnnulusRight = interp.smoothCubicHermiteDerivativesLine(xAnnulusRight, d2AnnulusRight, - fixStartDirection=True, - fixEndDerivative= True) - # for n2 in range(len(xAnnulusRight)): + for n2 in range(int(elementsCountAroundOesophagus * 0.25 + 1), int(elementsCountAroundOesophagus * 0.5)): + ostiumIdx = n2 + GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + n2 + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + + endPosition = o1_Positions[ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) + d2 = o1_d2[1][ostiumIdx] + d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, + endProportion2, int(0.5 * elementsCountAroundDuodenum + 1), + startDerivative=d1GC, endDerivative= d1EndOstium, + endDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1EndOstium)) + + # for n2 in range(len(xFirstHalf)): # node = nodes.createNode(nodeIdentifier, nodetemplate) # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusRight[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AnnulusRight[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - else: - for n2 in range(1, len(xAlongAround)): - x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5) - n] - x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5) - n] - d2 = findDerivativeBetweenPoints(x2, x1) - xRight.append(x1) - d2Right.append(d2) - - # for n2 in range(len(xRight)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRight[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Right[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstHalf[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1FirstHalf[n2]) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) # nodeIdentifier += 1 - d2Right = interp.smoothCubicHermiteDerivativesLine(xRight, d2Right, fixStartDirection=True) - - xLoopsRight.append(xRight) - d2LoopsRight.append(d2Right) - - # Repeat for left side - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) - d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] - d2GC = d2GCRot - - xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + n] - d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5 + 1) + n][c] - - xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + n][c] for c in range(3)] - - nx = [xOesoToDuodGC[GCIdx], xEnd] - nd2 = [d2GC, d2End] - xLeft, d2Left = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25) + (1 if n > 0 else 0), - arcLengthDerivatives=True)[0:2] - - # Calculate and append d2 for elements downstream of loop - if n == 0: - # Deal with addition of elementsAlong later - xAnnulusLeft = xLeft - d2AnnulusLeft = d2Left - x1 = xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) + 1] - x2 = xOesoToDuodLC[1] - d2 = findDerivativeBetweenPoints(x1, x2) - xAnnulusLeft += [x1, x2] - d2AnnulusLeft += [d2, d2OesoToDuodLC[1]] - d2AnnulusLeft = interp.smoothCubicHermiteDerivativesLine(xAnnulusLeft, d2AnnulusLeft, - fixStartDirection=True, - fixEndDerivative=True) - - # for n2 in range(len(xAnnulusLeft)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusLeft[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AnnulusLeft[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - else: - # Issues when elementsCountAroundOesophagus > 8 - for n2 in range(1, len(xAlongAround)): - if n2 == 1: - x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5 + 1) + n] - x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5 + 1) + n] - elif n2 == 2: - x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5) + n] - x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5 + 1) + n] + # Second half + ostiumIdx2 = -n2 + startPosition = o1_Positions[ostiumIdx2] + d1StartOstium = o1_d2[1][ostiumIdx2] + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] + + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, + GCProportion2, int(0.5 * elementsCountAroundDuodenum + 1), + startDerivative=d1StartOstium, endDerivative=d1GC, + startDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1StartOstium)) + + xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] + d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # Elements downstream of oesophagus + for idx in range(-(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1), 0): + startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], + ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + + endPosition = trackSurfaceStomach.findNearestPosition(xOesoToDuodLC[idx]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + d1End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, startProportion2, endProportion1, + endProportion2, int(0.5 * elementsCountAroundDuodenum), + startDerivative=d1Start, endDerivative=d1End) + + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, endProportion1, endProportion2, 1.0, + startProportion2, int(0.5 * elementsCountAroundDuodenum), + startDerivative=d1End, endDerivative=d1Start) + + # Average adjacent ring with first downstream ring that is not adjacent to oesophagus + if idx == -(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1): + xAve = [] + dAve = [] + xAve.append(xOesoToDuodGC[idx - 1]) + for n in range(1, int(elementsCountAroundDuodenum * 0.5)): + # nx = [xAround[n], xFirstHalf[n]] + # d = [xFirstHalf[n][c] - xAround[n][c] for c in range(3)] + # nd1 = [d, d] + # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] + # xAve.append(xSampled[1]) + + startPosition = trackSurfaceStomach.findNearestPosition(xAround[n]) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + endPosition = trackSurfaceStomach.findNearestPosition(xFirstHalf[n]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + xSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, endProportion1, endProportion2, 2)[0] + xAve.append(xSampled[1]) + + xAve.append(xOesoToDuodLC[idx - 1]) + + for n in range(1, int(elementsCountAroundDuodenum * 0.5)): + # nx = [xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1], xSecondHalf[n]] + # d = [xSecondHalf[n][c] - xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1][c] for c in range(3)] + # nd1 = [d, d] + # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] + # xAve.append(xSampled[1]) + + startPosition = trackSurfaceStomach.findNearestPosition(xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1]) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + endPosition = trackSurfaceStomach.findNearestPosition(xSecondHalf[n]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + xSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, endProportion1, endProportion2, 2)[0] + xAve.append(xSampled[1]) + + for n in range(len(xAve)): + v1 = xAve[n] + v2 = xAve[(n+1) % len(xAve)] + d1 = findDerivativeBetweenPoints(v1, v2) + dAve.append(d1) + dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) + + xAlongAround.append(xAve) + d1AlongAround.append(dAve) + + xAround = xFirstHalf + xSecondHalf[1:-1] + d1Around = d1FirstHalf + d1SecondHalf[1:-1] + d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) + # calculate curvature + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # for n2 in range(len(xAlongAround)): + # for n1 in range(len(xAlongAround[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround + ptsOnTrackSurfaceOesoToFundus = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][int(elementsCountAroundDuodenum * 0.5)]) + + xFirstTwoLoopsRight = [] + xFirstTwoLoopsLeft = [] + d2FirstTwoLoopsRight = [] #KM + d2FirstTwoLoopsLeft = [] # KM + + for nLoop in range(1, 3): + GCIdx = nLoop + 1 + if GCIdx < nodesCountFromOesoToApex: + ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus + proportion1 = 0.5 + else: + ptsOnTrackSurface = ptsOnTrackSurfaceGC + proportion1 = 0.0 + d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], + ptsOnTrackSurface, + trackSurfaceStomach, proportion1, + elementsCountAlongTrackSurface)[1] + + if GCIdx < nodesCountFromOesoToApex: + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in + range(3)] + d2GC = d2GCRot + + for nSide in range(2): + if nSide == 0: + xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop] + d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] - + xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] for c in range(3)] else: - x1 = xAlongAround[n2][int(elementsCountAroundDuodenum * 0.5 ) + n] - x2 = xAlongAround[n2 - 1][int(elementsCountAroundDuodenum * 0.5 ) + n] - d2 = findDerivativeBetweenPoints(x2, x1) - xLeft.append(x1) - d2Left.append(d2) - - # for n2 in range(len(xLeft)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLeft[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Left[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - d2Left = interp.smoothCubicHermiteDerivativesLine(xLeft, d2Left, fixStartDirection=True) - - xLoopsLeft.append(xLeft) - d2LoopsLeft.append(d2Left) - - # for n1 in range(len(xLoopsRight)): - # for n2 in range(len(xLoopsRight[n1])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsRight[n1][n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2LoopsRight[n1][n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # for n1 in range(len(xLoopsLeft)): - # for n2 in range(len(xLoopsLeft[n1])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsLeft[n1][n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2LoopsLeft[n1][n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - xBottom = [] - d2Bottom = [] - for n1 in range(-1, 2): - xAlong = [] - d2Along = [] - for n2 in range(len(xAlongAround)): - x1 = xAlongAround[n2][n1] - x2 = xAlongAround[n2 - 1][n1] - d2 = findDerivativeBetweenPoints(x2, x1) - xAlong.append(x1) - d2Along.append(d2) - d2Along = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) - xBottom.append(xAlong) - d2Bottom.append(d2Along) + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in + range(3)] + d2GC = d2GCRot + + xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + nLoop] + d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) + nLoop][c] - + xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) + (0 if elementsCountAroundOesophagus > 8 else 1) + nLoop][c] for c in range(3)] + + nx = [xOesoToDuodGC[GCIdx], xEnd] + nd2 = [d2GC, d2End] + x, d2 = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25 + 2), + arcLengthDerivatives=True)[0:2] + + # Find closest sampled points onto track surface + xProjectedPoints = [] + d2ProjectedPoints = [] + for n2 in range(len(x)): + projectedPosition = trackSurfaceStomach.findNearestPosition(x[n2]) + xProjected = trackSurfaceStomach.evaluateCoordinates(projectedPosition) + xProjectedPoints.append(xProjected) + + for n2 in range(len(xProjectedPoints) - 1): + d2 = findDerivativeBetweenPoints(xProjectedPoints[n2], xProjectedPoints[n2 + 1]) + d2ProjectedPoints.append(d2) + d2ProjectedPoints.append(d2) + + # Sample points again + xLoop, d2Loop = interp.sampleCubicHermiteCurves(xProjectedPoints, d2ProjectedPoints, + int(elementsCountAroundOesophagus * 0.25 + 2))[0:2] + + (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft).append(xLoop) + (d2FirstTwoLoopsRight if nSide == 0 else d2FirstTwoLoopsLeft).append(d2Loop) + + # for n2 in range(len(xFirstTwoLoopsRight)): + # for n1 in range(len(xFirstTwoLoopsRight[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsRight[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsRight[n2][n1]) + # nodeIdentifier += 1 + # + # for n2 in range(len(xFirstTwoLoopsLeft)): + # for n1 in range(len(xFirstTwoLoopsLeft[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsLeft[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsLeft[n2][n1]) + # nodeIdentifier += 1 + + # Find triple point + xTriplePts = [[None], [None]] # Right, left + d1TriplePts = [[None], [None]] + d2TriplePts = [[None], [None]] + d3TriplePtsNorm = [[None], [None]] + + for nSide in range(2): + ostiumIdx = int(elementsCountAroundOesophagus * 0.25) if nSide == 0 else -int(elementsCountAroundOesophagus * 0.25) + p1x = o1_x[1][ostiumIdx] + d = o1_d2[1][ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][ostiumIdx], math.pi) + p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + p1d = [annulusDerivativeFactor * c for c in p1d] + + xFirstTwoLoops = xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft + p2x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)] # downstream bifurcation + p2d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)], + xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25 + 1)]) + + p3x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)] + p3d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)], + xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25)]) + + xTriplePts[nSide], d1TriplePts[nSide], d2TriplePts[nSide] = get_bifurcation_triple_point(p1x, p1d, p2x, p2d, p3x, p3d) + d3TriplePtsNorm[nSide] = vector.normalise( + vector.crossproduct3(vector.normalise(d1TriplePts[nSide]), vector.normalise(d2TriplePts[nSide]))) + + # Make sure triple point is on track surface + triplePointPosition = trackSurfaceStomach.findNearestPosition(xTriplePts[nSide]) + xTriplePts[nSide] = trackSurfaceStomach.evaluateCoordinates(triplePointPosition) + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p1x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p1d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p2x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p2d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p3x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p3d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3TriplePtsNorm[nSide]) + # nodeIdentifier += 1 + + # Use track surface to sample point on GC to loop 1 (includes bifurcation rings and additional upstream rings) + xBifurcationRings = [] + d1BifurcationRings = [] + xUp = [] + d1Up = [] + for n2 in range(int(elementsCountAroundOesophagus * 0.25)): + xAround = [] + d1Around = [] + loopIdx = n2 + 2 + ostiumIdx = loopIdx + (0 if n2 < int(elementsCountAroundOesophagus * 0.25 - 1) else -1) + GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + 1 + n2 + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + + if loopIdx < int(elementsCountAroundOesophagus * 0.25): # additional elements upstream of triple point + for nSide in range(2): + if nSide == 0: + xLoop = xFirstTwoLoopsRight[0][loopIdx] + xOstium = o1_x[1][ostiumIdx] + ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xLoop, xOstium) + endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, + GCProportion2, ostiumProportion1, ostiumProportion2, + int(elementsCountAroundDuodenum * 0.5 + 1), + startDerivative=d1GC, endDerivative=d, + endDerivativeMagnitude=endDerivativeMag)[0:2] - # for n1 in range(len(xBottom)): - # for n2 in range(len(xBottom[n1])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBottom[n1][n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Bottom[n1][n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Join row running along next to GC to oesophagus - # Find point between second row coming down fundus and second row running along the bottom - nx = [xLoopsLeft[-1][1], xBottom[0][0]] - nd1 = [[xLoopsLeft[-1][1][c] - xLoopsLeft[-2][1][c] for c in range(3)], d2Bottom[0][0]] - x, d = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] - xBifurcationBottomLeft = x[1] - - xAround2Left = [] - d1Around2Left = [] - xAround2Left.append(xAnnulusLeft[1]) - for i in range(len(xLoopsLeft)): - xAround2Left.append(xLoopsLeft[i][1]) - xAround2Left.append(xBifurcationBottomLeft) - for i in range(len(xBottom[0])): - xAround2Left.append(xBottom[0][i]) - - for n1 in range(len(xAround2Left) - 1): - x1 = xAround2Left[n1] - x2 = xAround2Left[n1 + 1] - d1 = findDerivativeBetweenPoints(x1, x2) - d1Around2Left.append(d1) - d1Around2Left.append(d1) - d1Around2Left = interp.smoothCubicHermiteDerivativesLine(xAround2Left, d1Around2Left) - - # for n1 in range(len(xAround2Left)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround2Left[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1Around2Left[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Right - # Find point between second row coming down fundus and second row running along the bottom - xAround2Right = [] - d1Around2Right = [] - - nx = [xLoopsRight[-1][1], xBottom[2][0]] - nd1 = [[xLoopsRight[-1][1][c] - xLoopsRight[-2][1][c] for c in range(3)], d2Bottom[2][0]] - x, d = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] - xBifurcationBottomRight = x[1] - - xAround = [] - d1Around = [] - xAround.append(xAnnulusRight[1]) - for i in range(len(xLoopsRight)): - xAround.append(xLoopsRight[i][1]) - xAround.append(xBifurcationBottomRight) - for i in range(len(xBottom[2])): - xAround.append(xBottom[2][i]) - - for n1 in range(len(xAround) - 1): - x1 = xAround[n1] - x2 = xAround[n1 + 1] - d1 = findDerivativeBetweenPoints(x1, x2) - d1Around.append(d1) - d1Around.append(d1) - d1Around = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around) - xAround2Right += xAround - d1Around2Right += d1Around - - # Calculate d in opposite direction to get d1 in correct direction going towards oesophagus - xAround.reverse() - d1AroundReverse = [] - for n1 in range(len(xAround) - 1): - x1 = xAround[n1] - x2 = xAround[n1 + 1] - d1 = findDerivativeBetweenPoints(x1, x2) - d1AroundReverse.append(d1) - d1AroundReverse.append(d1) - d1AroundReverse = interp.smoothCubicHermiteDerivativesLine(xAround, d1AroundReverse) - - for i in range(int(elementsCountAroundDuodenum * 0.5) - 1): - d1Around2Right[i] = d1AroundReverse[-1 - i] - - xAround.reverse() - - # for n2 in range(len(xAround2Right)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround2Right[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1Around2Right[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Calculate d1 for loop joining to bifurcation - xAroundBifurcationLoop = [] - xAroundBifurcationLoop.append(xAnnulusLeft[int(elementsCountAroundOesophagus * 0.25)]) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): - xAroundBifurcationLoop.append(xLoopsLeft[n1][int(elementsCountAroundOesophagus * 0.25)]) - xAroundBifurcationLoop.append(xBifurcationBottomLeft) - xAroundBifurcationLoop.append(xOesoToDuodGC[int(elementsCountAroundDuodenum * 0.5)]) - xAroundBifurcationLoop.append(xBifurcationBottomRight) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 3, -1, -1): - xAroundBifurcationLoop.append(xLoopsRight[-int(elementsCountAroundDuodenum * 0.5 - 2) + n1][int(elementsCountAroundOesophagus * 0.25)]) - xAroundBifurcationLoop.append(xAnnulusRight[int(elementsCountAroundOesophagus * 0.25)]) - - d1AroundBifurcationLoop = [] - for n1 in range(len(xAroundBifurcationLoop) - 1): - x1 = xAroundBifurcationLoop[n1] - x2 = xAroundBifurcationLoop[n1 + 1] - d = findDerivativeBetweenPoints(x1, x2) - d1AroundBifurcationLoop.append(d) - d1AroundBifurcationLoop.append(d) - d1AroundBifurcationLoop = interp.smoothCubicHermiteDerivativesLine(xAroundBifurcationLoop, - d1AroundBifurcationLoop, - fixStartDirection=True, fixEndDirection=True) - - # nodeIdentifier = 10000 - # for n1 in range(len(xAroundBifurcationLoop)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundBifurcationLoop[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundBifurcationLoop[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Annulus to LC - # xAnnulusToDuodLC = xOesoToDuodLC #[1:] - # d2AnnulusToDuodLC = [] - # for n2 in range(len(xAnnulusToDuodLC) - 1): - # x1 = xAnnulusToDuodLC[n2] - # x2 = xAnnulusToDuodLC[n2 + 1] - # d2 = findDerivativeBetweenPoints(x1, x2) - # d2AnnulusToDuodLC.append(d2) - # d2AnnulusToDuodLC.append(d2) - # - # d2AnnulusToDuodLC = interp.smoothCubicHermiteDerivativesLine(xAnnulusToDuodLC, d2AnnulusToDuodLC) - - xLC = xOesoToDuodLC # [1:] - d2LC = [] - for n2 in range(len(xLC) - 1): - x1 = xLC[n2] - x2 = xLC[n2 + 1] - d2 = findDerivativeBetweenPoints(x1, x2) - d2LC.append(d2) - d2LC.append(d2) - - d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC) - xAnnulusToDuodLC = xLC[1:] - d2AnnulusToDuodLC = d2LC[1:] - # for n2 in range(len(xAnnulusToDuodLC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AnnulusToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Arrange nodes - xOuter = [] - d1Outer = [] - d2Outer = [] - - for n2 in range(elementsCountAlong + 1): - xAround = [] - d1Around = [] - d2Around = [] - if n2 == 0: - for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): - xAround.append(xOesoToDuodGC[i+1]) - d1Around.append(d2OesoToDuodGC[i + 1]) - d2Around.append(d2AnnulusLeft[0] if i == 0 else d2LoopsLeft[i-1][0]) - - elif n2 == 1: - xAround.append(xOesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) - 1]) - d1Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) - 1]) - d2Around.append(d2LoopsLeft[int(elementsCountAroundDuodenum * 0.5) - 3][0]) - # Right - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, - 1, -1): - xAround.append(xAround2Right[n1]) - d1Around.append(d1Around2Right[n1]) - d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusRight[n2]) - # Left - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): - xAround.append(xAround2Left[n1]) - d1Around.append(d1Around2Left[n1]) - d2Around.append(d2LoopsLeft[n1 - 1][n2] if n1 > 0 else d2AnnulusLeft[n2]) - - elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25): - pass # Handle later - - elif n2 == int(elementsCountAroundOesophagus * 0.25): # Upstream bifurcation row - xAround = xAroundBifurcationLoop[int(elementsCountAroundDuodenum * 0.5):] - d1Around = d1AroundBifurcationLoop[int(elementsCountAroundDuodenum * 0.5): - 1] - d1Around.append(d1AlongAround[0][int(elementsCountAroundDuodenum * 0.5)]) # Annulus right - d1Around.append(d1AlongAround[0][int(elementsCountAroundDuodenum * 0.5) + 1]) # Annulus left - xAround += xAroundBifurcationLoop[: int(elementsCountAroundDuodenum * 0.5)] - d1Around += d1AroundBifurcationLoop[1 : int(elementsCountAroundDuodenum * 0.5)] - - d2Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5)]) # on GC - d2Around.append(d1Around2Right[int(elementsCountAroundDuodenum * 0.5) - 1]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): - d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusRight[int(elementsCountAroundOesophagus * 0.25)]) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): - d2Around.append(d2LoopsLeft[n1 - 1][n2] if n1 > 0 else d2AnnulusLeft[int(elementsCountAroundOesophagus * 0.25)]) - d2Around.append(d1Around2Left[int(elementsCountAroundDuodenum * 0.5) - 1]) # next to GC - - elif n2 == int(elementsCountAroundOesophagus * 0.25) + 1: # Downstream bifurcation row: - xAround = xAlongAround[0][: int(elementsCountAroundDuodenum * 0.5)] + \ - xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) + 2:] - d1Around = d1AlongAround[0][: int(elementsCountAroundDuodenum * 0.5)] + \ - d1AlongAround[0][int(elementsCountAroundDuodenum * 0.5) + 2:] - d2Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) + 1]) # on GC - d2Around.append(d1Around2Right[int(elementsCountAroundDuodenum * 0.5)]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, 0, -1): - d2Around.append(d2LoopsRight[n1 - 1][n2]) - for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): - d2Around.append(d2LoopsLeft[n1 - 1][n2]) - d2Around.append(d1Around2Left[int(elementsCountAroundDuodenum * 0.5)]) # next to GC - - elif n2 > int(elementsCountAroundOesophagus * 0.25) + 1 and n2 <= int(elementsCountAroundOesophagus * 0.5): # n2 == 4 - idx = n2 - (int(elementsCountAroundOesophagus * 0.25) + 1) - xAround = xAlongAround[idx][: int(elementsCountAroundDuodenum * 0.5) + 1] + \ - xAlongAround[idx][int(elementsCountAroundDuodenum * 0.5) + 1:] - d1Around = d1AlongAround[idx][: int(elementsCountAroundDuodenum * 0.5) + 1] + \ - d1AlongAround[idx][int(elementsCountAroundDuodenum * 0.5) + 1:] - d2Around.append(d2OesoToDuodGC[int(elementsCountAroundDuodenum * 0.5) + 1 + idx]) # on GC - d2Around.append(d1Around2Right[int(elementsCountAroundDuodenum * 0.5) + idx]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): - d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusRight[int(elementsCountAroundOesophagus * 0.25) + 1]) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): - d2Around.append(d2LoopsLeft[n1 - 1][n2] if n1 > 0 else d2AnnulusLeft[int(elementsCountAroundOesophagus * 0.25) + 1]) - d2Around.append(d1Around2Left[int(elementsCountAroundDuodenum * 0.5) + 1]) # next to GC - - elif n2 > int(elementsCountAroundOesophagus * 0.5): # n2 > 4 - idx = n2 - (int(elementsCountAroundOesophagus * 0.25) + 1) - GCIdx = int(elementsCountAroundDuodenum * 0.5) + n2 - 2 - xAround = xAlongAround[idx] - d1Around = d1AlongAround[idx] - d2Around.append(d2OesoToDuodGC[GCIdx]) # on GC - d2Around.append(d1Around2Right[GCIdx - 1]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): - d2Around.append(d2LoopsRight[n1 - 1][n2] if n1 > 0 else d2AnnulusToDuodLC[n2 - 5]) - for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): - d2Around.append(d2LoopsLeft[n1 - 1][n2]) - d2Around.append(d1Around2Left[GCIdx - 1]) # next to GC - - # for n1 in range(len(xAround)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Around[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Around[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + else: + xLoop = xFirstTwoLoopsLeft[0][loopIdx] + xOstium = o1_x[1][-ostiumIdx] + ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xOstium, xLoop) + startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, + 1.0, GCProportion2, + int(elementsCountAroundDuodenum * 0.5 + 1), + startDerivative= d, endDerivative=d1GC, + startDerivativeMagnitude=startDerivativeMag)[0:2] + + xAround += xSampled[:-1] if nSide == 0 else xSampled[1:-1] + d1Around += dSampled[:-1] if nSide == 0 else dSampled[1:-1] + + # for n1 in range(len(xAround)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Around[n1]) + # nodeIdentifier += 1 + + # xBifurcationRings.append(xAround) + # d1BifurcationRings.append(d1Around) + xUp.append(xAround) + d1Up.append(d1Around) + + else: # connected to triple point + for nSide in range(2): + xLoop = (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft)[0][loopIdx] + loopPosition = trackSurfaceStomach.findNearestPosition(xLoop) + loopProportion1, loopProportion2 = trackSurfaceStomach.getProportion(loopPosition) + + if nSide == 0: + d = findDerivativeBetweenPoints(xLoop, o1_x[1][ostiumIdx]) + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, + GCProportion2, loopProportion1, loopProportion2, + int(elementsCountAroundDuodenum * 0.5) - 1, + startDerivative=d1GC, endDerivative = d)[0:2] + xSampled.append(xTriplePts[0]) + dSampled.append(d1TriplePts[0]) - xOuter.append(xAround) - d1Outer.append(d1Around) - d2Outer.append(d2Around) - - d3UnitOuter = [] - for n2 in range(elementsCountAlong + 1): - d3Around = [] - for n1 in range(len(xOuter[n2])): - d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) - d3UnitOuter.append(d3Around) - - # Calculate curvatures - # Curvatures along GC - xGC = [] - dGC = [] - norms = [] - for n1 in range(len(xOuter[0])): - xGC.append(xOuter[0][n1]) - dGC.append(d1Outer[0][n1]) - norms.append(d3UnitOuter[0][n1]) - for n2 in range(1, elementsCountAlong + 1): - xGC.append(xOuter[n2][0]) - dGC.append(d1Outer[n2][0] if n2 == 1 else d2Outer[n2][0]) - norms.append(d3UnitOuter[n2][0]) - curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 - - # for m1 in range(len(xGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + else: + d = findDerivativeBetweenPoints(o1_x[1][-ostiumIdx], xLoop) + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, loopProportion1, + loopProportion2, 1.0, GCProportion2, + int(elementsCountAroundDuodenum * 0.5) - 1, + startDerivative = d, endDerivative=d1GC)[0:2] + xSampled.insert(0, xTriplePts[1]) + dSampled.insert(0, d1TriplePts[1]) + + xAround += xSampled if nSide == 0 else xSampled[:-1] + d1Around += dSampled if nSide == 0 else dSampled[:-1] + + xUp.append(xAround) + d1Up.append(d1Around) + xBifurcationRings.append(xAround) + d1BifurcationRings.append(d1Around) + + # for n2 in range(len(xBifurcationRings)): + # for n1 in range(len(xBifurcationRings[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBifurcationRings[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1BifurcationRings[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Row 2 + for nSide in range(2): + if nSide == 0: + xStart = xUp[0][1] + dStart = findDerivativeBetweenPoints(xUp[1][1], xUp[0][1]) + startDerivativeMag = None + xEnd = o1_x[1][1] + dEnd = findDerivativeBetweenPoints(xFirstTwoLoopsRight[0][1], o1_x[1][1]) + endDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) - # Curvature along left row next to GC and apply same to right side - norms = [] - xTest = [] - for n in range(int(len(xOuter[1]) * 0.5)): # d1s - xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM - norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) - for n2 in range(2, elementsCountAlong + 1): # d2s - xTest.append(xOuter[n2][-1]) # KM - norms.append(d3UnitOuter[n2][-1]) - curvatureAlong2Left = findCurvatureAlongLine(xAround2Left, d1Around2Left, norms) - - # Curvature at GC around loops - excluding annulus points - curvatureLoopsRight = [] - curvatureLoopsLeft = [] - curvaturesOnGC = [] - for n1 in range(len(xLoopsRight)): - normsRight = [] - normsLeft = [] - for n2 in range(len(xLoopsRight[n1])): + else: + xStart = o1_x[1][-1] + dStart = findDerivativeBetweenPoints(o1_x[1][-1], xFirstTwoLoopsLeft[0][1]) + startDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) + xEnd = xUp[0][-1] + dEnd = findDerivativeBetweenPoints(xUp[0][-1], xUp[1][-1]) + endDerivativeMag = None + + startPosition = trackSurfaceStomach.findNearestPosition(xStart) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + endPosition = trackSurfaceStomach.findNearestPosition(xEnd) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, + endProportion1, endProportion2, + int(elementsCountAroundDuodenum * 0.5), + startDerivative=dStart, endDerivative=dEnd, + startDerivativeMagnitude=startDerivativeMag, + endDerivativeMagnitude=endDerivativeMag)[0:2] + + if nSide == 0: + xRow2Right = xSampled[:-1] + d1Row2Right = dSampled[:-1] + else: + xRow2Left = xSampled[1:] + d1Row2Left = dSampled[1:] + + # for n1 in range(len(xRow2Right)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Right[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Right[n1]) + # nodeIdentifier += 1 + + # for n1 in range(len(xRow2Left)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Left[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Left[n1]) + # nodeIdentifier += 1 + + # Smooth derivatives from triple point to 6 point junction + # Start from GC at upstream bifurcation ring to annulus to 6 point junction ring on right then left + xLoopTripleTo6Pt = [] + dLoopTripleTo6Pt = [] + + xLoopTripleTo6Pt += xBifurcationRings[0][0:int(len(xBifurcationRings[0]) * 0.5) + 1] + for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): + xLoopTripleTo6Pt.append(xAlongAround[n2][int(len(xAlongAround[n2]) * 0.5)]) + junctionIdx = n2 + 1 + xLoopTripleTo6Pt += xAlongAround[junctionIdx][int(len(xAlongAround[junctionIdx]) * 0.5):] + \ + xAlongAround[junctionIdx][0: int(len(xAlongAround[junctionIdx]) * 0.5 + 1)] + for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): # Note order here - going upstream + idx = junctionIdx - 1 - n2 + xLoopTripleTo6Pt.append(xAlongAround[idx][int(len(xAlongAround[idx]) * 0.5) + 1]) + xLoopTripleTo6Pt += xBifurcationRings[0][int(len(xBifurcationRings[0]) * 0.5 + 1):] + + for n in range(len(xLoopTripleTo6Pt)): + d = findDerivativeBetweenPoints(xLoopTripleTo6Pt[n], xLoopTripleTo6Pt[(n+1) % len(xLoopTripleTo6Pt)]) + dLoopTripleTo6Pt.append(d) + dSmoothLoopTripleTo6Pt = interp.smoothCubicHermiteDerivativesLoop(xLoopTripleTo6Pt, dLoopTripleTo6Pt) + # curvature - DONE + + # for n1 in range(len(xLoopTripleTo6Pt)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopTripleTo6Pt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopTripleTo6Pt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) + # nodeIdentifier += 1 + + # Smooth derivatives around top loop + # Starts from GC at downstream bifurcation ring to annulus and back + xLoopGCTriplePt = [] + dLoopGCTriplePt = [] + + xLoopGCTriplePt += xBifurcationRings[1][:int(len(xBifurcationRings[1]) * 0.5) + 1] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): + idx = -(3 + n2) + xLoopGCTriplePt.append(xUp[idx][int(len(xUp[idx]) * 0.5)]) + + xLoopGCTriplePt += [xRow2Right[-1]] + [xOesoToDuodGC[1]] + [xRow2Left[0]] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): + xLoopGCTriplePt.append(xUp[n2][int(len(xUp[n2]) * 0.5) + 1]) + + xLoopGCTriplePt += xBifurcationRings[1][int(len(xBifurcationRings[1]) * 0.5) + 1:] + + for n in range(len(xLoopGCTriplePt)): + d = findDerivativeBetweenPoints(xLoopGCTriplePt[n], xLoopGCTriplePt[(n+1) % len(xLoopGCTriplePt)]) + dLoopGCTriplePt.append(d) + dSmoothLoopGCTriplePt = interp.smoothCubicHermiteDerivativesLoop(xLoopGCTriplePt, dLoopGCTriplePt) + # curvature - DONE + + # for n1 in range(len(xLoopGCTriplePt)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopGCTriplePt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopGCTriplePt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) + # nodeIdentifier += 1 + + # Assemble nodes and d1 + xOuter = [] + d1Outer = [] + countUp = 0 + countDown = 0 + for n2 in range(elementsCountAlong + 1): + xAround = [] + d1Around = [] + d2Around = [] + if n2 == 0: + # print(n2, 'GC') + for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xAround.append(xOesoToDuodGC[i + 1]) + d1Around.append(d2OesoToDuodGC[i + 1]) + + elif n2 == 1: + # print(n2, 'Row 2') + xAround = [xOesoToDuodGC[i + n2 + 1]] + xRow2Right[1:] + xRow2Left[:-1] + d1Around = [d2OesoToDuodGC[i + n2 + 1]] + d1Row2Right[1:] + d1Row2Left[:-1] # need to replace d1Row2 after smoothing - DONE + + elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): + # print(n2, 'Before triple point + triple point') + xAround = xUp[countUp] + if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt + # smooth d1 around - Make into function? + d1Around = d1Up[countUp] + 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)] + d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, + fixEndDerivative=True) + # Need to do curvature and rearrange to correct order + d1Around = [] + d1Around = d1LoopSmooth[int(len(xAround) * 0.5) : ] + d1LoopSmooth[: int(len(xAround) * 0.5) : ] + + elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation + # take smoothed d1 from dSmoothTripleTo6Pt + d1Around = dSmoothLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ + dSmoothLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5) : ] + + elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation + # take smoothed d1 from dSmoothGCToTriplePt + d1Around = dSmoothLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ + dSmoothLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5) : ] + countUp += 1 + + elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): + # print(n2, 'Downstream of triple point') + xAround = xAlongAround[countDown] + d1Around = d1AlongAround[countDown] + + # smooth d1 around - Make into function? + if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): + 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)] + d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, + fixEndDerivative=True) + # Need to do curvature and rearrange to correct order + d1Around = [] + d1Around = d1LoopSmooth[int(len(xAround) * 0.5):] + d1LoopSmooth[: int(len(xAround) * 0.5):] + + elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring + # take smoothed d1 from dSmoothedTripleTo6Pt + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len(xAlongAround[junctionIdx]) * 0.5) + endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + d1Around = dSmoothLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ + dSmoothLoopTripleTo6Pt[startLeftIdx : startRightIdx] + countDown += 1 + + xOuter.append(xAround) + d1Outer.append(d1Around) + + # for m2 in range(len(xOuter)): + # for m1 in range(len(xOuter[m2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Calculate d2 + xRegularLoops = [] + d2RegularLoops = [] + d2RegularOrderedLoops = [] + + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xRegularLoop = [] + d1RegularRightLoop = [] + d2RegularLoop = [] + for n2 in range(elementsCountAlong): + idx = -(1 + n2) + xRegularLoop.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + d1RegularRightLoop.append(d1Outer[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + xRegularLoop.append(xOesoToDuodGC[n1 + 2]) + for n2 in range(elementsCountAlong): + xRegularLoop.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) + + for n in range(len(xRegularLoop) - 1): + d = findDerivativeBetweenPoints(xRegularLoop[n], xRegularLoop[n+1]) + d2RegularLoop.append(d) + d2RegularLoop.append(d) + + d2SmoothRegularLoop = interp.smoothCubicHermiteDerivativesLine(xRegularLoop, d2RegularLoop) + d2SmoothRegularOrderedLoop = copy.deepcopy(d2SmoothRegularLoop) + # curvature - DONE + + # Switch direction on right side + for n2 in range(elementsCountAlong): + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1RegularRightLoop[n2]), d2SmoothRegularLoop[n2])) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d = d2SmoothRegularLoop[n2] + d2SmoothRegularLoop[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + + xRegularLoops.append(xRegularLoop) + d2RegularLoops.append(d2SmoothRegularLoop) + d2RegularOrderedLoops.append(d2SmoothRegularOrderedLoop) + + # for m1 in range(len(xRegularLoops)): + # for m2 in range(len(xRegularLoops[m1])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRegularLoops[m1][m2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2RegularOrderedLoops[m1][m2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #d2RegularLoops[m1][m2]) + # nodeIdentifier += 1 + + # Smooth d2 along row 2 + xLoop2Right = [] + d1Loop2Right = [] + d2Loop2Right = [] + + for n2 in range(len(xAlongAround) + len(xUp) - 1): + idx = -(1 + n2) + xLoop2Right.append(xOuter[idx][1]) + d1Loop2Right.append(d1Outer[idx][1]) + xLoop2Right += xRow2Right + d1Loop2Right += d1Row2Right + + for n in range(len(xLoop2Right) - 1): + d = findDerivativeBetweenPoints(xLoop2Right[n], xLoop2Right[n + 1]) + d2Loop2Right.append(d) + d2Loop2Right.append(d1Row2Right[-1]) + + d2Loop2Right = interp.smoothCubicHermiteDerivativesLine(xLoop2Right, d2Loop2Right, fixEndDirection=True) + # curvature - USING LEFT SIDE - DONE + + # Switch direction of d2 for downstream nodes + for n2 in range(len(xAlongAround) + len(xUp)): + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1Loop2Right[n2]), d2Loop2Right[n2])) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d = d2Loop2Right[n2] + d2Loop2Right[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + idxSwitchToD1 = n2 + + # for m in range(len(xLoop2Right)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Right[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) #d2Loop2Right[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Loop2Right[m]) + # nodeIdentifier += 1 + + # Left + xLoop2Left = [] + d2Loop2Left = [] + + xLoop2Left += xRow2Left + for n2 in range(3, len(xOuter)): + xLoop2Left.append(xOuter[n2][-1]) + + d2Loop2Left.append(d1Row2Left[0]) + for n in range(1, len(xLoop2Left) - 1): + d = findDerivativeBetweenPoints(xLoop2Left[n], xLoop2Left[n + 1]) + d2Loop2Left.append(d) + d2Loop2Left.append(d) + + d2Loop2Left = interp.smoothCubicHermiteDerivativesLine(xLoop2Left, d2Loop2Left, fixStartDirection=True) + # curvature - DONE + + # for m in range(len(xLoop2Left)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Left[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Loop2Left[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Smooth lower curvature + xLC = [] + d2LC = [] + for n2 in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): + xLC.append(xOuter[n2][int(len(xOuter[n2]) * 0.5)]) + + for n in range(len(xLC) - 1): + d = findDerivativeBetweenPoints(xLC[n], xLC[n + 1]) + d2LC.append(d) + d2LC.append(d) + + d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC, fixStartDirection=True) + # curvature - DONE + + # for m in range(len(xLC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLC[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LC[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Update d1 for upstream nodes + for n1 in range(1, len(xRow2Right)): + d1Outer[1][n1] = d2Loop2Right[idxSwitchToD1 + n1] + for n1 in range(1, len(xRow2Left)): + d1Outer[1][int(len(d1Outer[1]) * 0.5) + n1] = d2Loop2Left[n1 - 1] + + # Assemble d2 + d2Outer = [] + for n2 in range(elementsCountAlong + 1): + d2Around = [] + xAround = [] # KM if n2 == 0: - norm = d3UnitOuter[0][n1 + 1] if n1 < len(xOuter[0]) - 1 else d3UnitOuter[n1 + 2 - len(xOuter[0])][0] - normsRight.append(norm) - normsLeft.append(norm) - elif n2 == int(elementsCountAroundOesophagus * 0.25) + 1: # bifurcation downstream - normsRight.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) - n1]) - normsLeft.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1 + n1]) + # print(n2, 'GC') + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5)]) #KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(dSmoothLoopGCTriplePt) * 0.5)]) + + for n1 in range(len(xOuter[0]) - 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) + d2Around.append(d2RegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) + nextIdx = n1 + 1 + + elif n2 == 1: + # print(n2, 'Row 2') + xAround.append(xRegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) + d2Around.append(d2RegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) + + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + # right point on annulus + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2]) # KM + d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2] + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append([rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) + + # left point on annulus + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) # KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) + + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + + elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): + # print(n2, 'Before triple point + triple point') + # GC + xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) + + # Row 2 right + xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) + d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) + + # Regular up right + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + # Annulus right + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM + d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)] + if n2 <= int(elementsCountAroundOesophagus * 0.25): # Rotate to point towards duodenum + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), + vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append( + [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) + else: # just take d2 as-is cos we are going to remove this point later + d2Around.append(d2) + + # Annulus left + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + + # Regular down left + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + + # Row 2 left + xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) + d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) + + # for m1 in range(len(d2Around)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Around[m1]) + # nodeIdentifier += 1 + + elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): + # print(n2, 'Downstream of triple point') + # GC + xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) + + # Row 2 right + xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) + d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) + + # Regular up right + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: + # Annulus right + # print('between triple and 6 pt') + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) + xAround.append(xLoopTripleTo6Pt[idx]) + if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: + d1 = dSmoothLoopTripleTo6Pt[idx] + d1Outer[n2][int(len(d1Outer[n2]) * 0.5)] = d1 + else: + d2Around.append(dSmoothLoopTripleTo6Pt[idx]) + + # Annulus left - need to rotate to point towards duodenum + xAround.append(xLoopTripleTo6Pt[-idx]) + # d2Around.append(dSmoothLoopTripleTo6Pt[-idx]) + d2 = dSmoothLoopTripleTo6Pt[-idx] + if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5 + 1)]), + vector.normalise(d2))) + else: # use d2 on previous overlapping point to rotate + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append( + [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in + range(3)]) + + elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: + # print('beyond 6 pt') + # LC + xAround.append(xLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) + d2Around.append(d2LC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) + + # Regular down left + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + + # Row 2 left + xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) + d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) + + d2Outer.append(d2Around) + + # remove triple point on both sides from downstream ring + n2Idx = int(elementsCountAroundOesophagus * 0.25 + 1) + n1Idx = int(len(xOuter[n2Idx]) * 0.5) + del xOuter[n2Idx][n1Idx: n1Idx + 2], d1Outer[n2Idx][n1Idx: n1Idx + 2], d2Outer[n2Idx][n1Idx: n1Idx + 2] + + d3UnitOuter = [] + for n2 in range(elementsCountAlong + 1): + d3Around = [] + for n1 in range(len(xOuter[n2])): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) + d3UnitOuter.append(d3Around) + + # for m2 in range(len(xOuter)): + # for m1 in range(len(xOuter[m2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[m2][m1]) + # nodeIdentifier += 1 + + # Calculate curvatures + # Curvatures along GC + xGC = [] + dGC = [] + norms = [] + for n1 in range(len(xOuter[0])): + xGC.append(xOuter[0][n1]) + dGC.append(d1Outer[0][n1]) + norms.append(d3UnitOuter[0][n1]) + for n2 in range(1, elementsCountAlong + 1): + xGC.append(xOuter[n2][0]) + dGC.append(d1Outer[n2][0] if n2 == 1 else d2Outer[n2][0]) + norms.append(d3UnitOuter[n2][0]) + curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 + + # for m1 in range(len(xGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Curvature along rows adjacent to GC - calculate with left and use the same for right + norms = [] + xTest = [] + for n in range(int(len(xOuter[1]) * 0.5)): # d1s + xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM + norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) + for n2 in range(2, elementsCountAlong + 1): # d2s + xTest.append(xOuter[n2][-1]) # KM + norms.append(d3UnitOuter[n2][-1]) + curvatureAlong2Left = findCurvatureAlongLine(xLoop2Left, d2Loop2Left, norms) + + # for m1 in range(len(xTest)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTest[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, norms[m1]) + # nodeIdentifier += 1 + + # Curvature along LC + xTest = [] # KM + norms = [] + for n in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): + xTest.append(xOuter[n][int(len(xOuter[n]) * 0.5)]) + norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) + curvatureAlongLC = findCurvatureAlongLine(xLC[1:], d2LC[1:], norms) + + # Curvature along path from triple point to 6 point junction + xTest = [] # KM + norms = [] + idxToAnnulus = int(elementsCountAroundDuodenum * 0.5 + 1) + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][: idxToAnnulus] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][:idxToAnnulus] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25)): + idx = int(elementsCountAroundOesophagus * 0.25) + 2 + n2 + if idx < (elementsCountAroundOesophagus * 0.5) + 1: + xTest.append(xOuter[idx][idxToAnnulus - 1]) + norms.append(d3UnitOuter[idx][idxToAnnulus - 1]) + xTest += xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ + xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ + d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): + idx = int(elementsCountAroundOesophagus * 0.5) - n2 + xTest.append(xOuter[idx][idxToAnnulus]) + norms.append(d3UnitOuter[idx][idxToAnnulus]) + + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] + + curvatureLoopTripleTo6Pt = findCurvatureAroundLoop(xLoopTripleTo6Pt, dSmoothLoopTripleTo6Pt, norms) + + # Curvature along path from GC to triple point + xTest = [] # KM + norms = [] + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25)): + idx = int(elementsCountAroundOesophagus * 0.25 - n2) + xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5)]) + norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5)]) + xTest.append(xOuter[0][0]) + norms.append(d3UnitOuter[0][0]) + for n2 in range(1, int(elementsCountAroundOesophagus * 0.25) + 1): + xTest.append(xOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + norms.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] + curvatureLoopGCTriplePt = findCurvatureAroundLoop(xLoopGCTriplePt, dSmoothLoopGCTriplePt, norms) + + # Curvature around regular loops + curvatureRegularLoops = [] + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xTest = [] + norms = [] + for n2 in range(elementsCountAlong): + idx = -(1 + n2) + xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + if n1 < int(elementsCountAroundDuodenum * 0.5) - 3: + xTest.append(xOuter[0][(n1 + 1)]) + norms.append(d3UnitOuter[0][n1 + 1]) else: - normsRight.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) - 1 - n1]) - normsLeft.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + n1 + (2 if n2 <= elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) else 1)]) - - curvatureRight = findCurvatureAlongLine(xLoopsRight[n1], d2LoopsRight[n1], normsRight) - curvatureLoopsRight.append(curvatureRight) - curvatureLeft = findCurvatureAlongLine(xLoopsLeft[n1], d2LoopsLeft[n1], normsLeft) - curvatureLoopsLeft.append(curvatureLeft) - - curvatureGC = 0.5 * (curvatureRight[0] + curvatureLeft[0]) - curvaturesOnGC.append(curvatureGC) - - # Curvature around annulus - normsRight = [] - normsLeft = [] - for n2 in range(len(xAnnulusRight)): - if n2 == 0: - normsRight.append(d3UnitOuter[0][0]) - normsLeft.append(d3UnitOuter[0][0]) - elif n2 > int(elementsCountAroundOesophagus * 0.25): - normsRight.append(d3UnitOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5)]) - normsLeft.append(d3UnitOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5) + (1 if n2 < elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) else 0)]) - else: - normsRight.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5)]) - normsLeft.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) - d2AnnulusRight[-1] = d2Outer[elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) + 1][int(elementsCountAroundDuodenum * 0.5)] - d2AnnulusLeft[-1] = d2Outer[elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) + 1][int(elementsCountAroundDuodenum * 0.5)] - curvatureAnnulusRight = findCurvatureAlongLine(xAnnulusRight, d2AnnulusRight, normsRight) - curvatureAnnulusLeft = findCurvatureAlongLine(xAnnulusLeft, d2AnnulusLeft, normsLeft) - curvatureAnnulusGC = (curvatureAnnulusRight[0] + curvatureAnnulusLeft[0]) * 0.5 - - # Curvature along LC - norms = [] - for n in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): - norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) - curvatureAlongLC = findCurvatureAlongLine(xOesoToDuodLC[1:], d2OesoToDuodLC[1:], norms) - - # Assemble curvatures into matrix - d1CurvatureOuter = [] - d2CurvatureOuter = [] - xCheck = [] - # GC -> n2 == 0 - d1CurvatureOuter.append(curvatureAlongGC[: len(xOuter[0])]) - d2CurvatureOuter.append([curvatureAnnulusGC] + curvaturesOnGC[:-1]) - xCheck.append(xGC[: len(xOuter[0])]) # KM - - # n2 == 1 - n2 = 1 - curvature = [] - xAround = [] - curvature.append(curvatureAlongGC[len(xOuter[0])]) - xAround.append(xGC[len(xOuter[0])]) # KM - for n1 in range(int(len(xOuter[1]) * 0.5)): - xAround.append(xOuter[1][-(1 + n1)]) # KM - curvature.append(curvatureAlong2Left[-(1 + n1)]) - for n1 in range(int(len(xOuter[1]) * 0.5)): - xAround.append(xOuter[1][int(len(xOuter[1]) * 0.5) + n1]) # KM - curvature.append(curvatureAlong2Left[n1]) - xCheck.append(xAround) # KM - d1CurvatureOuter.append(curvature) - - d2Curvature = [] - d2Curvature.append(curvatureAlongGC[-1]) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, - 1, -1): - d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAnnulusRight[n2]) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): - d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2] if n1 > 0 else curvatureAnnulusLeft[n2]) - d2CurvatureOuter.append(d2Curvature) - - # Deal with additional elementsAroundOesophagus later - - # n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25) - - # Downstream of second column - for n2 in range(int(elementsCountAroundOesophagus * 0.25), elementsCountAlong + 1): #int(elementsCountAroundOesophagus * 0.5) + 1): + xTest.append(xOuter[idx][0]) + norms.append(d3UnitOuter[idx][0]) + for n2 in range(elementsCountAlong): + xTest.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) + norms.append(d3UnitOuter[n2 + 1][int( + len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) + curvatureLoop = findCurvatureAlongLine(xRegularLoops[n1], d2RegularOrderedLoops[n1], norms) + curvatureRegularLoops.append(curvatureLoop) + + # Assemble curvatures + d1Curvature = [] d2Curvature = [] - elementsCountAround = len(xOuter[n2]) - GCIdx = len(curvatureAlongGC) - (elementsCountAlong - n2 + 1) - if n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation - ignore bifurcation - # re-arrange nodes to calculate curvature - xAround = xOuter[n2][int(elementsCountAround * 0.5) + 2:] + xOuter[n2][: int(elementsCountAround * 0.5)] - d1Around = d1Outer[n2][int(elementsCountAround * 0.5) + 2:] + d1Outer[n2][:int(elementsCountAround * 0.5)] - norms = d3UnitOuter[n2][int(elementsCountAround * 0.5) + 2:] + d3UnitOuter[n2][:int(elementsCountAround * 0.5)] - curvature = findCurvatureAlongLine(xAround, d1Around, norms) - # Arrange curvatures to match original order - x = xAround[int(elementsCountAround * 0.5) - 1: ] + [[0.0, 0.0, 0.0]] + [[0.0, 0.0, 0.0]] + xAround[:int(elementsCountAround * 0.5) - 1] # KM - xCheck.append(x) # KM - curvatureArranged = curvature[int(elementsCountAround * 0.5) - 1: ] + [0.0] + [0.0] + curvature[:int(elementsCountAround * 0.5) - 1] - d1CurvatureOuter.append(curvatureArranged) - - d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC - d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): - d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAnnulusRight[int(elementsCountAroundOesophagus * 0.25)]) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): - d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2] if n1 > 0 else curvatureAnnulusLeft[int(elementsCountAroundOesophagus * 0.25)]) - d2Curvature.append(curvatureAlong2Left[int(elementsCountAroundDuodenum * 0.5) - 1]) # next to GC - d2CurvatureOuter.append(d2Curvature) - - elif n2 == int(elementsCountAroundOesophagus * 0.25) + 1: # downstream bifurcation - include bifurcation - elementsCountAroundUpStreamBifurcation = len(xOuter[int(elementsCountAroundOesophagus * 0.25)]) - xAround = [xOuter[n2-1][int(elementsCountAround * 0.5) + 2]] + xOuter[n2][int(elementsCountAround * 0.5) + 1:] + xOuter[n2][: int(elementsCountAround * 0.5) + 1] + [xOuter[n2-1][int(elementsCountAround * 0.5) + 1]] - d1Around = [d1Outer[n2-1][int(elementsCountAround * 0.5) + 2]] + d1Outer[n2][int(elementsCountAround * 0.5) + 1:] + d1Outer[n2][:int(elementsCountAround * 0.5) + 1] + [d1Outer[n2-1][int(elementsCountAround * 0.5) + 1]] - norms = [d3UnitOuter[n2-1][int(elementsCountAround * 0.5) + 2]] + d3UnitOuter[n2][int(elementsCountAround * 0.5) + 1:] + d3UnitOuter[n2][:int(elementsCountAround * 0.5) + 1] + [d3UnitOuter[n2-1][int(elementsCountAround * 0.5) + 1]] - curvature = findCurvatureAlongLine(xAround, d1Around, norms) - # replace curvature at bifurcation in previous group of elements around - xCheck[len(xCheck) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5)] = xAround[-1] - xCheck[len(xCheck) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5) + 1] = xAround[0] - d1CurvatureOuter[len(d1CurvatureOuter) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5)] = curvature[-1] - d1CurvatureOuter[len(d1CurvatureOuter) - 1][int(elementsCountAroundUpStreamBifurcation * 0.5) + 1] = curvature[0] - # rearrange the rest - x = xAround[int(elementsCountAround * 0.5) + 1: - 1] + xAround[1:int(elementsCountAround * 0.5)+ 1] #KM - xCheck.append(x) # KM - curvatureArranged = curvature[int(elementsCountAround * 0.5) + 1: - 1] + curvature[1:int(elementsCountAround * 0.5) + 1] - d1CurvatureOuter.append(curvatureArranged) - - d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC - d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, 0, -1): - d2Curvature.append(curvatureLoopsRight[n1 - 1][n2]) - for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): - d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2]) - d2Curvature.append(curvatureAlong2Left[int(elementsCountAroundDuodenum * 0.5)]) # next to GC - d2CurvatureOuter.append(d2Curvature) - - elif n2 > int(elementsCountAroundOesophagus * 0.25) + 1 and n2 <= int(elementsCountAroundOesophagus * 0.5): - xAround = xOuter[n2][int(elementsCountAround * 0.5) + 1:] + xOuter[n2][: int(elementsCountAround * 0.5) + 1] - d1Around = d1Outer[n2][int(elementsCountAround * 0.5) + 1:] + d1Outer[n2][: int(elementsCountAround * 0.5) + 1] - norms = d3UnitOuter[n2][int(elementsCountAround * 0.5) + 1:] + d3UnitOuter[n2][: int(elementsCountAround * 0.5) + 1] - curvature = findCurvatureAlongLine(xAround, d1Around, norms) - x = xAround[int(elementsCountAround * 0.5): ] + xAround[:int(elementsCountAround * 0.5)] # KM - curvatureArranged = curvature[int(elementsCountAround * 0.5):] + curvature[:int(elementsCountAround * 0.5)] - d1CurvatureOuter.append(curvatureArranged) - xCheck.append(x) # KM - - d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC - d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): - d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAnnulusRight[int(elementsCountAroundOesophagus * 0.25) + 1]) - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 1): - d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2] if n1 > 0 else curvatureAnnulusLeft[int(elementsCountAroundOesophagus * 0.25) + 1]) - d2Curvature.append(curvatureAlong2Left[int(elementsCountAroundDuodenum * 0.5) + 1]) # next to GC - d2CurvatureOuter.append(d2Curvature) - - elif n2 > int(elementsCountAroundOesophagus * 0.5): # Downstream of oesophagus - d1CurvatureOuter.append(findCurvatureAroundLoop(xOuter[n2], d1Outer[n2], d3UnitOuter[n2])) - - d2Curvature.append(curvatureAlongGC[GCIdx]) # on GC - d2Curvature.append(curvatureAlong2Left[GCIdx]) # next to GC - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2, -1, -1): - d2Curvature.append(curvatureLoopsRight[n1 - 1][n2] if n1 > 0 else curvatureAlongLC[n2 - (elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) + 1)]) - for n1 in range(1, int(elementsCountAroundDuodenum * 0.5) - 1): - d2Curvature.append(curvatureLoopsLeft[n1 - 1][n2]) - d2Curvature.append(curvatureAlong2Left[GCIdx - 1]) # next to GC - d2CurvatureOuter.append(d2Curvature) - - # Create inner nodes - xList = [] - d1List = [] - d2List = [] - d3List = [] - nodeIdx = bodyStartNode - - idxMat = [] - - for n2 in range(elementsCountAlong + 1): - idxThroughWall = [] - for n3 in range(elementsCountThroughWall + 1): - xi3 = 1 / elementsCountThroughWall * n3 - idxAround = [] - for n1 in range(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 * xi3 * d1CurvatureOuter[n2][n1] - d1 = [factor * c for c in d1Outer[n2][n1]] - d1List.append(d1) - - # d2 - factor = 1.0 - wallThickness * xi3 * d2CurvatureOuter[n2][n1] - d2 = [factor * c for c in d2Outer[n2][n1]] - d2List.append(d2) - - # d3 - d3 = [c * wallThickness / elementsCountThroughWall for c in norm] - d3List.append(d3) - - idxAround.append(nodeIdx) - nodeIdx += 1 - - idxThroughWall.append(idxAround) - idxMat.append(idxThroughWall) - - # Assemble endPoints for annulus - endPoints_x = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endPoints_d1 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endPoints_d2 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endNode_Id = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endDerivativesMap = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - - thicknessIdx = [0, -1] - for nAround in range(elementsCountAroundOesophagus): - for n3 in range(len(thicknessIdx)): - if nAround == 0: - idx = idxMat[nAround][thicknessIdx[n3]][0] - elif nAround <= int(elementsCountAroundOesophagus * 0.25): - idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] - elif int(elementsCountAroundOesophagus * 0.25) < nAround < int(elementsCountAroundOesophagus * 0.5): - idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] - elif nAround == int(elementsCountAroundOesophagus * 0.5): - idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] - elif nAround > int(elementsCountAroundOesophagus * 0.5): - idx = endNode_Id[n3][int(elementsCountAroundOesophagus * 0.5) - (nAround - int(elementsCountAroundOesophagus * 0.5))] + 1 - - endPoints_x[n3][nAround] = xList[idx] - endPoints_d1[n3][nAround] = d1List[idx] - endPoints_d2[n3][nAround] = d2List[idx] - endNode_Id[n3][nAround] = idx - - for nAround in range(elementsCountAroundOesophagus): - if nAround == 0: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) - elif 0 < nAround < int(elementsCountAroundOesophagus * 0.5): - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == int(elementsCountAroundOesophagus * 0.5): - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = (None, None, None) - elif int(elementsCountAroundOesophagus * 0.5) < nAround < elementsCountAroundOesophagus: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) - - 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 - - # for n2 in range(len(xOuter)): - # for n1 in range(len(xOuter[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[n2][n1]) - # nodeIdentifier += 1 - - # Create element - mesh = fm.findMeshByDimension(3) - - 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) - result = elementtemplateStandard.defineField(coordinates, -1, eftStandard) - - elementtemplateX = mesh.createElementtemplate() - elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) - - elementIdentifier = nextElementIdentifier - - # Row 1 - e2 = 0 - startNode = bodyStartNode - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(int(elementsCountAround1) * 2 + 1): - if e1 != elementsCountAround1: - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - if e1 < elementsCountAround1: - scaleFactors = [-1.0] - if e1 == 0: - bni11 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + e1 - bni12 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - 1 - else: - bni11 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - bni12 = bni11 - 1 - bni21 = startNode + elementsAroundThroughWall + 1 + e1 + e3 * elementsCountAround2 - bni22 = bni21 + 1 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + (elementsCountAround2 if e1 == 0 else elementsCountAround1), - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS1DS3, - Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) - scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], [Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS2DS3, - Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > elementsCountAround1: - if e1 < elementsCountAround1 * 2: - bni11 = startNode + e1 - elementsCountAround1 - 1 + elementsCountAround1 * e3 - bni12 = bni11 + 1 + countUp = 0 + countDown = 0 + for n2 in range(elementsCountAlong + 1): + d1CurvatureAround = [] + d2CurvatureAround = [] + if n2 == 0: + # print(n2, 'GC') + for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): + d1CurvatureAround.append(curvatureAlongGC[i]) + + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5)]) + for n1 in range(len(xOuter[0]) - 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5)]) + nextIdx = n1 + 1 + + elif n2 == 1: + # print(n2, 'Row 2') + d1CurvatureAround.append(curvatureAlongGC[i + n2]) + xTest = [] + dTest = [] + for n in range(int(len(xOuter[1]) * 0.5) - 1, -1, -1): + d1CurvatureAround.append(curvatureAlong2Left[n]) + d1CurvatureAround += curvatureAlong2Left[:int(len(xOuter[1]) * 0.5)] + xTest = xLoop2Left[:int(len(xOuter[1]) * 0.5)] + dTest = d2Loop2Left[:int(len(xOuter[1]) * 0.5)] + + d2CurvatureAround.append(curvatureRegularLoops[nextIdx][int(len(curvatureRegularLoops[nextIdx]) * 0.5)]) + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + # right point on annulus + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) - n2]) + # left point on annulus + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2]) + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + + elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): + # print(n2, 'Before triple point + triple point') + xAround = xOuter[n2] + if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt + # smooth d1 around - Make into function? + d1Around = d1Outer[n2] + norms = d3UnitOuter[n2] + 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 = norms[int(len(d1Around) * 0.5 + 1):] + norms[: 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):] + + elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation + # take smoothed d1 from dSmoothTripleTo6Pt + d1CurvatureAround = curvatureLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ + curvatureLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5):] + + elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation + # take smoothed d1 from dSmoothGCToTriplePt + d1CurvatureAround = curvatureLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ + curvatureLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5):] + + # GC + d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) + # Row 2 right + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + # Regular up right + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + # Annulus right + d2CurvatureAround.append(curvatureLoopGCTriplePt[ + int(len(curvatureLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + # Annulus left + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2 - ( + 1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + # Regular down left + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + # Row 2 left + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + + elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): + # print(n2, 'Downstream of triple point') + xAround = xOuter[n2] + d1Around = d1Outer[n2] + normsAround = d3UnitOuter[n2] + + # smooth d1 around - Make into function? + if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): + 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(normsAround) * 0.5 + 1):] + normsAround[: int(len(normsAround) * 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):] + + elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring + # take smoothed d1 from dSmoothedTripleTo6Pt + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len( + xAlongAround[junctionIdx]) * 0.5) + endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + d1CurvatureAround = curvatureLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ + curvatureLoopTripleTo6Pt[startLeftIdx: startRightIdx] + + if n2 > int(elementsCountAroundOesophagus * 0.5 + 1): # closed rings beyond 6 point junction + 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(normsAround) * 0.5 + 1):] + normsAround[ : int(len(normsAround) * 0.5 + 1)] + curvature = findCurvatureAroundLoop(xLoop, d1Loop, normsLoop) + # Rearrange to correct order + d1CurvatureAround = curvature[int(len(xLoop) * 0.5) - 1:] + curvature[: int(len(xAround) * 0.5) - 1] + + # GC + d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) + # Row 2 right + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + # Regular up right + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: + # Annulus right + # print('between triple and 6 pt') + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) + if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: + d1CurvatureAround[int(len(d1Outer[n2]) * 0.5)] = curvatureLoopTripleTo6Pt[idx] else: - bni11 = startNode + elementsCountAround1 + e3 * elementsCountAround1 - 1 - bni12 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 - bni22 = bni21 + 1 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, - bni12 + (elementsCountAround1 if e1 < elementsCountAround1 * 2 else elementsCountAround2), - bni21 + elementsCountAround2, bni22 + elementsCountAround2] + d2CurvatureAround.append(curvatureLoopTripleTo6Pt[idx]) + # Annulus left + d2CurvatureAround.append(curvatureLoopTripleTo6Pt[-idx]) + elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: + # print('beyond 6 pt') + # LC + d2CurvatureAround.append(curvatureAlongLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1) - 1]) + # Regular down left + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + # Row 2 left + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + + d1Curvature.append(d1CurvatureAround) + d2Curvature.append(d2CurvatureAround) + + # Create inner nodes + xList = [] + d1List = [] + d2List = [] + d3List = [] + nodeIdx = bodyStartNode + + idxMat = [] + + for n2 in range(elementsCountAlong + 1): + idxThroughWall = [] + for n3 in range(elementsCountThroughWall + 1): + xi3 = 1 / elementsCountThroughWall * n3 + idxAround = [] + for n1 in range(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 * xi3 * d1Curvature[n2][n1] + d1 = [factor * c for c in d1Outer[n2][n1]] + d1List.append(d1) + + # d2 + factor = 1.0 - wallThickness * xi3 * d2Curvature[n2][n1] + d2 = [factor * c for c in d2Outer[n2][n1]] + d2List.append(d2) + + # d3 + d3 = [c * wallThickness / elementsCountThroughWall for c in norm] + d3List.append(d3) + + idxAround.append(nodeIdx) + nodeIdx += 1 + + idxThroughWall.append(idxAround) + idxMat.append(idxThroughWall) + + 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 + + # Create element + mesh = fm.findMeshByDimension(3) + + 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) + result = elementtemplateStandard.defineField(coordinates, -1, eftStandard) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + elementIdentifier = nextElementIdentifier + + for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2): + # Row 1 + if e2 == 0: + startNode = bodyStartNode + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(int(elementsCountAround1) * 2 + 1): + if e1 != elementsCountAround1: + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < elementsCountAround1: + # scaleFactors = [-1.0] + if e1 == 0: + bni11 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + e1 + bni12 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - 1 + else: + bni11 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 + bni12 = bni11 - 1 + bni21 = startNode + elementsAroundThroughWall + 1 + e1 + e3 * elementsCountAround2 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + ( + elementsCountAround2 if e1 == 0 else elementsCountAround1), + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + scaleFactors = [-1.0] + setEftScaleFactorIds(eft1, [1], []) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], + [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS1DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], + [Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS2DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > elementsCountAround1: + if e1 < elementsCountAround1 * 2: + bni11 = startNode + e1 - elementsCountAround1 - 1 + elementsCountAround1 * e3 + bni12 = bni11 + 1 + else: + bni11 = startNode + elementsCountAround1 + e3 * elementsCountAround1 - 1 + bni12 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + ( + elementsCountAround1 if e1 < elementsCountAround1 * 2 else elementsCountAround2), + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Row 2 + elif e2 == 1: + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 2): + if e1 != int(elementsCountAround1 * 0.5 + 1): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + + if e1 < 2: + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + ( + e1 + 1) # % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + e1 + bni22 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + ( + e1 + 1) # % elementsCountAround2 + if e1 == 0: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], 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, [])]) + 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_DS2, [])]) + elif e1 == 1: # Bottom right wedge + nodeIdentifiers = [bni11, bni21, bni22, + bni11 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > 1 and e1 < elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + elif e1 >= elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 2 + bni12 = startNode + e3 * elementsCountAround1 + (e1 - 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + if e1 == elementsCountAround1: # Bottom left wedge + nodeIdentifiers = [bni12, bni21, bni22, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([2, 6]) + elif e1 == elementsCountAround1 + 1: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Additional elements between second and upstream bifurcation ring + elif e2 > 1 and e2 < int(elementsCountAroundOesophagus * 0.25): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1): + if e1 != int(elementsCountAround1 * 0.5): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Upstream bifurcation + elif e2 == int(elementsCountAroundOesophagus * 0.25): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1): + if e1 != int(elementsCountAround1 * 0.5): + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + + if e1 < int(elementsCountAround1 * 0.5) - 1: + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + elif e1 == int(elementsCountAround1 * 0.5) - 1: # right wedge + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == int(elementsCountAround1 * 0.5) + 1: # left wedge + bni21 = bni21 - 1 + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni21 = bni21 - 2 + bni22 = startNode + elementsAroundThroughWall + ( + e1 - 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Downstream bifurcation + elif e2 == int(elementsCountAroundOesophagus * 0.25) + 1: + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 1): + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 + elif e1 == int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( + xOuter[e2 - 1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + + if e1 < int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + elif e1 == int(elementsCountAround1 * 0.5): + bni12 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( + xOuter[e2 - 1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + + if e1 > int(elementsCountAround1 * 0.5): + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 2) % elementsCountAround2 + elementsCountAround2 * e3 + else: + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Row 2 - e2 = 1 - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 + 2): - if e1 != int(elementsCountAround1 * 0.5 + 1): - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - - if e1 < 2: - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) # % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + e1 - bni22 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + (e1 + 1) # % elementsCountAround2 - if e1 == 0: # Remap derivatives of element adjacent to GC - scaleFactors = [-1.0] nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 5], 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, [])]) - 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_DS2, [])]) - elif e1 == 1: # Bottom right wedge - nodeIdentifiers = [bni11, bni21, bni22, - bni11 + elementsCountAround1, + bni11 + (len(xOuter[e2 - 1]) if e1 == int( + elementsCountAround1 * 0.5) + 1 else elementsCountAround1), + bni12 + (len(xOuter[e2 - 1]) if e1 == int( + elementsCountAround1 * 0.5) else elementsCountAround1), bni21 + elementsCountAround2, bni22 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - elif e1 > 1 and e1 < elementsCountAround1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 - bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + if e1 == int(elementsCountAround1 * 0.5): + 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, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == int(elementsCountAround1 * 0.5) + 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, [ ])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Rows between downstream and penultimate ring + for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2, + int(elementsCountAroundOesophagus * 0.5)): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 - 1): + bni11 = startNode + e3 * elementsCountAround1 + e1 + ( + 0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni12 = startNode + e3 * elementsCountAround1 + ( + e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + ( + 0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni22 = startNode + elementsAroundThroughWall + (e1 + (1 if e1 < int( + elementsCountAround1 * 0.5) else 2)) % elementsCountAround2 + elementsCountAround2 * e3 nodeIdentifiers = [bni11, bni12, bni21, bni22, bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2, bni22 + elementsCountAround2] - elif e1 >= elementsCountAround1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 2 - bni12 = startNode + e3 * elementsCountAround1 + (e1 - 1) % elementsCountAround1 + element = mesh.createElement(elementIdentifier, elementtemplateStandard) + result = element.setNodesByIdentifier(eftStandard, nodeIdentifiers) + elementIdentifier = elementIdentifier + 1 + + # Penultimate row connecting to annulus and beyond + for e2 in range(int(elementsCountAroundOesophagus * 0.5), elementsCountAlong): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range( + elementsCountAround1 - (1 if e2 == int(elementsCountAroundOesophagus * 0.5) else 0)): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e2 == int(elementsCountAroundOesophagus * 0.5): + bni11 = startNode + e3 * elementsCountAround1 + e1 + ( + 0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni12 = startNode + e3 * elementsCountAround1 + (e1 + ( + 1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 + # Remap elements next to annulus + if e1 == int(elementsCountAround1 * 0.5) - 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + 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 + else: + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - if e1 == elementsCountAround1: # Bottom left wedge - nodeIdentifiers = [bni12, bni21, bni22, - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([2, 6]) - elif e1 == elementsCountAround1 + 1: # Remap derivatives of element adjacent to GC - scaleFactors = [-1.0] - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Upstream bifurcation - e2 = int(elementsCountAroundOesophagus * 0.25) - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1): - if e1 != int(elementsCountAround1 * 0.5): - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - - if e1 < int(elementsCountAround1 * 0.5) - 1: - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - elif e1 == int(elementsCountAround1 * 0.5) - 1: # right wedge - nodeIdentifiers = [bni11, bni12, bni21, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(elementsCountAround1 * 0.5) + 1: # left wedge - bni21 = bni21 - 1 - nodeIdentifiers = [bni11, bni12, bni21, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2] - eft1 = eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > int(elementsCountAround1 * 0.5) + 1: - bni21 = bni21 - 2 - bni22 = startNode + elementsAroundThroughWall + (e1 - 1) % elementsCountAround2 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 nodeIdentifiers = [bni11, bni12, bni21, bni22, bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2, bni22 + elementsCountAround2] - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Downstream bifurcation - e2 = int(elementsCountAroundOesophagus * 0.25) + 1 - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 + 1): - if e1 < int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - elif e1 == int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode - len(xOuter[e2-1]) * (elementsCountThroughWall + 1) + e3 * len(xOuter[e2 - 1]) + e1 + 1 - elif e1 > int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 - - if e1 < int(elementsCountAround1 * 0.5): - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - elif e1 == int(elementsCountAround1 * 0.5): - bni12 = startNode - len(xOuter[e2-1]) * (elementsCountThroughWall + 1) + e3 * len(xOuter[e2-1]) + e1 + 1 - elif e1 > int(elementsCountAround1 * 0.5): - bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 - - if e1 > int(elementsCountAround1 * 0.5): - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 - bni22 = startNode + elementsAroundThroughWall + (e1 + 2) % elementsCountAround2 + elementsCountAround2 * e3 - else: - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + (len(xOuter[e2 - 1]) if e1 == int(elementsCountAround1 * 0.5) + 1 else elementsCountAround1), - bni12 + (len(xOuter[e2 - 1]) if e1 == int(elementsCountAround1 * 0.5) else elementsCountAround1), - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - element = mesh.createElement(elementIdentifier, elementtemplateStandard) - result = element.setNodesByIdentifier(eftStandard, nodeIdentifiers) - elementIdentifier = elementIdentifier + 1 - - # Penultimate row connecting to annulus and beyond - for e2 in range(int(elementsCountAroundOesophagus * 0.5), elementsCountAlong): - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 - (1 if e2 == int(elementsCountAroundOesophagus * 0.5) else 0)): - scaleFactors = [] # check if needed - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - if e2 == int(elementsCountAroundOesophagus * 0.5): - bni11 = startNode + e3 * elementsCountAround1 + e1 + (0 if e1 < int(elementsCountAround1 * 0.5) else 1) - bni12 = startNode + e3 * elementsCountAround1 + (e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 - # Remap elements next to annulus - if e1 == int(elementsCountAround1 * 0.5) - 1: - scaleFactors = [-1.0] # check if needed - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(elementsCountAround1 * 0.5): - scaleFactors = [-1.0] # check if needed - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - else: - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Annulus - 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) - - for n2 in range(len(xTrackSurface)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - nodeIdentifier += 1 + if e2 == int(elementsCountAroundOesophagus * 0.5) + 1: + if e1 == int(elementsCountAround1 * 0.5) - 1: + 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 == int(elementsCountAround1 * 0.5): + 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) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Annulus + # Assemble endPoints for annulus + endPoints_x = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endPoints_d1 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endPoints_d2 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endNode_Id = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endDerivativesMap = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endProportions = [] + + thicknessIdx = [0, -1] + for nAround in range(elementsCountAroundOesophagus): + for n3 in range(len(thicknessIdx)): + if nAround == 0: + idx = idxMat[nAround][thicknessIdx[n3]][0] + elif nAround <= int(elementsCountAroundOesophagus * 0.25): + idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] + elif int(elementsCountAroundOesophagus * 0.25) < nAround < int(elementsCountAroundOesophagus * 0.5): + idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] + elif nAround == int(elementsCountAroundOesophagus * 0.5): + idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] + elif nAround > int(elementsCountAroundOesophagus * 0.5): + idx = endNode_Id[n3][int(elementsCountAroundOesophagus * 0.5) - (nAround - int(elementsCountAroundOesophagus * 0.5))] + 1 + + endPoints_x[n3][nAround] = xList[idx - bodyStartNode] + endPoints_d1[n3][nAround] = d1List[idx - bodyStartNode] + endPoints_d2[n3][nAround] = d2List[idx - bodyStartNode] + endNode_Id[n3][nAround] = idx + + if n3 == len(thicknessIdx) - 1: # outer layer + endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) + # xCheck = trackSurfaceStomach.evaluateCoordinates(endPosition) # KM + # print(xCheck, endPoints_x[n3][nAround]) # KM + endProportions.append(trackSurfaceStomach.getProportion(endPosition)) + + for nAround in range(elementsCountAroundOesophagus): + if nAround == 0: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + elif nAround == int(elementsCountAroundOesophagus * 0.25): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) + elif 0 < nAround < int(elementsCountAroundOesophagus * 0.5): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) + elif nAround == int(elementsCountAroundOesophagus * 0.5): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) + elif nAround == int(elementsCountAroundOesophagus * 0.75): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) + elif int(elementsCountAroundOesophagus * 0.5) < nAround < elementsCountAroundOesophagus: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + + startProportions = [] + for n in range(elementsCountAroundOesophagus): + startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) + + 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 = elementsCountAnnulus, tracksurface=trackSurfaceStomach, + startProportions = startProportions, endProportions = endProportions, + rescaleStartDerivatives = True, rescaleEndDerivatives = True) + + if trackSurface: + for n2 in range(len(xTrackSurface)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + nodeIdentifier += 1 + + if showCentralPath: + for n2 in range(len(sx)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd2[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd1[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, sd3[n2]) + nodeIdentifier += 1 fm.endChange() @@ -1813,8 +2475,9 @@ def findClosestPositionAndDerivativeOnTrackSurface(x, nx, trackSurface, nxPropor def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, startProportion2, endProportion1, endProportion2, elementsOut, startDerivative = None, endDerivative = None, - startDerivativeMagnitude = None, endDerivativeMagnitude = None): + startDerivativeMagnitude = None, endDerivativeMagnitude = None, curveMode = 1): """ + EDIT Create smoothly spaced out hermite curve points between two points a and b on the surface, each defined by their proportions over the surface in directions 1 and 2. :param trackSurface: track surface @@ -1831,7 +2494,7 @@ def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, start mx, md2, md1, md3, mProportions = \ trackSurface.createHermiteCurvePoints(startProportion1, startProportion2, endProportion1, endProportion2, - elementsOut, startDerivative, endDerivative) + elementsOut, startDerivative, endDerivative, curveMode) xSampled, dSampled = trackSurface.resampleHermiteCurvePointsSmooth(mx, md2, md1, md3, mProportions, startDerivativeMagnitude, diff --git a/src/scaffoldmaker/scaffolds.py b/src/scaffoldmaker/scaffolds.py index c421b029..99542422 100644 --- a/src/scaffoldmaker/scaffolds.py +++ b/src/scaffoldmaker/scaffolds.py @@ -38,6 +38,7 @@ from scaffoldmaker.meshtypes.meshtype_3d_sphereshellseptum1 import MeshType_3d_sphereshellseptum1 from scaffoldmaker.meshtypes.meshtype_3d_stellate1 import MeshType_3d_stellate1 from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1 +from scaffoldmaker.meshtypes.meshtype_3d_stomach2 import MeshType_3d_stomach2 from scaffoldmaker.meshtypes.meshtype_3d_stomachhuman1 import MeshType_3d_stomachhuman1 from scaffoldmaker.meshtypes.meshtype_3d_tube1 import MeshType_3d_tube1 from scaffoldmaker.meshtypes.meshtype_3d_tubeseptum1 import MeshType_3d_tubeseptum1 @@ -83,6 +84,7 @@ def __init__(self): MeshType_3d_sphereshellseptum1, MeshType_3d_stellate1, MeshType_3d_stomach1, + MeshType_3d_stomach2, MeshType_3d_stomachhuman1, MeshType_3d_tube1, MeshType_3d_tubeseptum1, diff --git a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py index 2abb705f..0d9e1c37 100644 --- a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py +++ b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py @@ -1667,13 +1667,16 @@ def createEftWedgeCollapseXi2(self, collapseNodes): eft = self.createEftBasic() if collapseNodes in [[4, 8]]: + setEftScaleFactorIds(eft, [1], []) nodes = [2, 4, 6, 8] + remapEftNodeValueLabel(eft, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) ln_map = [1, 2, 3, 2, 4, 5, 6, 5] elif collapseNodes in [[3, 7]]: nodes = [1, 3, 5, 7] remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + remapEftNodeValueLabel(eft, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) ln_map = [1, 2, 1, 3, 4, 5, 4, 6] remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) From a782aab07fdbeaf998e8029b2a89bc95d5f19686 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 2 Apr 2021 13:23:57 +1300 Subject: [PATCH 03/38] Create parameter sets for rat and human --- .../meshtypes/meshtype_3d_stomach1.py | 104 +- .../meshtypes/meshtype_3d_stomach2.py | 2563 +++++++++++++++++ 2 files changed, 2619 insertions(+), 48 deletions(-) create mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 412952ed..2aa8994d 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -65,43 +65,28 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 4 + 'Number of elements': 7 }, 'meshEdits': exnodeStringFromNodeValues( [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], [ - [[17.0, 14.0, 0.0], [-17.9, -22.1, 0.0], [7.0, -5.7, 0.0], [-3.3, -6.2, 0.0], [0.0, 0.0, 9.0], + [[54.2, 76.2, 0.0], [9.4, -43.5, 0.0], [29.0, 0.8, 0.0], [15.9, -22.3, 0.0], [0.0, 0.0, 40.7], [0.0, 0.0, 1.4]], - [[0.0, 0.0, 0.0], [-15.4, -5.0, 0.0], [2.8, -8.5, 0.0], [-5.2, 0.6, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, -1.4]], - [[-9.7, 0.7, 0.0], [-8.6, 3.8, 0.0], [-2.8, -6.4, 0.0], [-2.1, 3.7, 0.0], [0.0, 0.0, 7.0], - [0.0, 0.0, -3.3]], - [[-15.9, 6.6, 0.0], [-4.8, 6.8, 0.0], [-2.0, -1.4, 0.0], [-0.3, 2.7, 0.0], [0.0, 0.0, 2.5], - [0.0, 0.0, -1.6]], - [[-19.2, 13.9, 0.0], [-1.7, 7.6, 0.0], [-3.4, -0.8, 0.0], [-2.5, -1.4, 0.0], [0.0, 0.0, 3.5], - [0.0, 0.0, 3.6]]]) - }), - 'Human straight 1': ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 4 - }, - 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.0, 1.2], [0.0, -0.7, 9.0], - [0.0, 1.2, 1.2]], - [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -8.9, -0.1], [0.0, 1.2, 0.0], [0.0, -0.1, 9.0], - [0.0, 0.0, -1.3]], - [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -7.0, -0.4], [0.0, 3.4, 0.0], [0.0, -0.4, 7.0], - [0.0, 0.0, -3.4]], - [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.7, 0.2], [0.0, -0.1, 2.5], - [0.0, 0.2, -1.7]], - [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.1, 0.2], [0.0, 0.1, 3.5], - [0.0, 0.2, 3.7]]]) + [[51.1, 30.7, 0.0], [-18.5, -35.9, 0.0], [33.9, -17.5, 0.0], [-6.1, -14.3, 0.0], [0.0, 0.0, 41.4], + [0.0, 0.0, 0.0]], + [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [19.0, -28.6, 0.0], [-16.3, -6.6, 0.0], [0.0, 0.0, 40.9], + [0.0, 0.0, -5.0]], + [[-0.3, -5.8, 0.0], [-29.4, -1.4, 0.0], [1.5, -31.5, 0.0], [-13.5, 4.5, 0.0], [0.0, 0.0, 32.3], + [0.0, 0.0, -9.4]], + [[-26.5, -2.9, 0.0], [-22.4, 9.4, 0.0], [-8.5, -20.3, 0.0], [-8.1, 10.9, 0.0], [0.0, 0.0, 22.1], + [0.0, 0.0, -6.8]], + [[-40.6, 7.4, 0.0], [-9.9, 11.2, 0.0], [-15.3, -9.6, 0.0], [-0.1, 8.5, 0.0], [0.0, 0.0, 17.6], + [0.0, 0.0, -5.9]], + [[-48.1, 21.0, 0.0], [-5.7, 14.7, 0.0], [-9.4, -3.0, 0.2], [2.3, 3.1, 0.0], [0.0, 0.0, 10.5], + [0.0, 0.0, -3.1]], + [[-52.9, 38.6, 0.0], [-5.0, 19.8, 0.0], [-11.3, -4.0, 0.0], [-6.1, -5.1, 0.0], [0.0, 0.0, 12.0], + [0.0, 0.0, 6.1]]]) + }), 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { @@ -129,6 +114,28 @@ class MeshType_3d_stomach1(Scaffold_base): [[-11.3, 14.8, 0.0], [-1.2, 4.1, 0.0], [-3.5, -0.3, 0.0], [-2.3, -1.9, 0.0], [0.0, 0.0, 3.4], [0.0, 0.0, 3.0]]]) }), + 'Stomach coordinates': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 4 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.0, 1.2], [0.0, -0.7, 9.0], + [0.0, 1.2, 1.2]], + [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -8.9, -0.1], [0.0, 1.2, 0.0], [0.0, -0.1, 9.0], + [0.0, 0.0, -1.3]], + [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -7.0, -0.4], [0.0, 3.4, 0.0], [0.0, -0.4, 7.0], + [0.0, 0.0, -3.4]], + [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.7, 0.2], [0.0, -0.1, 2.5], + [0.0, 0.2, -1.7]], + [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.1, 0.2], [0.0, 0.1, 3.5], + [0.0, 0.2, 3.7]]]) + }), } ostiumDefaultScaffoldPackages = { @@ -141,15 +148,15 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of elements through wall': 1, # not implemented for > 1 'Unit scale': 1.0, 'Outlet': False, - 'Ostium diameter': 5.0, - 'Ostium length': 5.0, - 'Ostium wall thickness': 0.5, + 'Ostium diameter': 25.0, + 'Ostium length': 10.0, + 'Ostium wall thickness': 5.0, 'Ostium inter-vessel distance': 0.0, 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 1.25, - 'Vessel wall thickness': 0.5, + 'Vessel inner diameter': 5.0, + 'Vessel wall thickness': 5.0, 'Vessel angle 1 degrees': 0.0, 'Vessel angle 1 spread degrees': 0.0, 'Vessel angle 2 degrees': 0.0, @@ -202,8 +209,8 @@ def getParameterSetNames(): 'Default', 'Generic 1', 'Human 1', - 'Human straight 1', - 'Rat 1'] + 'Rat 1', + 'Stomach coordinates',] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): @@ -212,10 +219,10 @@ def getDefaultOptions(cls, parameterSetName='Default'): ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] elif 'Generic 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Generic 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - elif 'Human straight 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human straight 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] + elif 'Stomach coordinates' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Stomach coordinates'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] else: centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] @@ -226,9 +233,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements around duodenum': 12, 'Number of elements along': 8, 'Number of elements through wall': 1, - 'Wall thickness': 0.5, + 'Wall thickness': 5.0, 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), - 'Gastro-oesophagal junction position along factor': 0.35, + 'Gastro-oesophagal junction position along factor': 0.25, 'Annulus derivative factor': 1.0, 'Number of radial elements in annulus': 1, # KM 'Show track surface': False, # KM @@ -241,7 +248,8 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } - if 'Rat 1' in parameterSetName: + if ('Generic 1' or 'Rat 1' or 'Stomach coordinates') in parameterSetName: + options['Wall thickness'] = 0.5 options['Gastro-oesophagal junction position along factor'] = 0.55 cls.updateSubScaffoldOptions(options) @@ -422,8 +430,8 @@ def generateBaseMesh(cls, region, options): Node.VALUE_LABEL_D2_DS1DS3]) del tmpRegion # for i in range(len(cx)): - # # print(vector.magnitude(cd2[i]), vector.magnitude(cd3[i])) - # cd3[i] = vector.setMagnitude(cd3[i], vector.magnitude(cd2[i])) + # cd3New = vector.setMagnitude(cd3[i], vector.magnitude(cd2[i])) + # print(i, vector.magnitude(cd2[i]), vector.magnitude(cd3[i]), cd3New) # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongTrackSurface) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py new file mode 100644 index 00000000..13a15908 --- /dev/null +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py @@ -0,0 +1,2563 @@ +""" +Generates a 3-D stomach mesh along the central line, with variable +numbers of elements around oesophagus and duodenum, along and through +wall, with variable radius and thickness along. +""" + +from __future__ import division +import math +import copy +from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates +from opencmiss.zinc.element import Element +from opencmiss.zinc.field import Field +from opencmiss.zinc.node import Node +from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1, extractPathParametersFromRegion +from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1, generateOstiumMesh +from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base +from scaffoldmaker.scaffoldpackage import ScaffoldPackage +from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d +from scaffoldmaker.utils.bifurcation import get_bifurcation_triple_point +from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear +from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite +from scaffoldmaker.utils.eft_utils import scaleEftNodeValueLabels, setEftScaleFactorIds, remapEftNodeValueLabel +from scaffoldmaker.utils.geometry import createEllipsePoints +from scaffoldmaker.utils.tracksurface import TrackSurface +from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues +from scaffoldmaker.utils import interpolation as interp +from scaffoldmaker.utils import matrix +from scaffoldmaker.utils import vector + + +class MeshType_3d_stomach2(Scaffold_base): + """ + Generates a 3-D stomach mesh with variable numbers of elements around the oesophagus and duodenum, + along the central line, and through wall. The stomach is created by a function that generates a bean + volume defined by a central path as its longitudinal axis. D2 of the central path points to the greater + curvature of the stomach and magnitude of D2 and D3 are the radii of the stomach in the respective + direction. + """ + centralPathDefaultScaffoldPackages = { + 'Generic 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 4 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[17.0, 14.0, 0.0], [-17.9, -22.1, 0.0], [7.0, -5.7, 0.0], [-3.3, -6.2, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, 1.4]], + [[0.0, 0.0, 0.0], [-15.4, -5.0, 0.0], [2.8, -8.5, 0.0], [-5.2, 0.6, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, -1.4]], + [[-9.7, 0.7, 0.0], [-8.6, 3.8, 0.0], [-2.8, -6.4, 0.0], [-2.1, 3.7, 0.0], [0.0, 0.0, 7.0], + [0.0, 0.0, -3.3]], + [[-15.9, 6.6, 0.0], [-4.8, 6.8, 0.0], [-2.0, -1.4, 0.0], [-0.3, 2.7, 0.0], [0.0, 0.0, 2.5], + [0.0, 0.0, -1.6]], + [[-19.2, 13.9, 0.0], [-1.7, 7.6, 0.0], [-3.4, -0.8, 0.0], [-2.5, -1.4, 0.0], [0.0, 0.0, 3.5], + [0.0, 0.0, 3.6]]]) + }), + 'Human 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 7 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[54.2, 76.2, 0.0], [9.4, -43.5, 0.0], [29.0, 0.8, 0.0], [15.9, -22.3, 0.0], [0.0, 0.0, 40.7], + [0.0, 0.0, 1.4]], + [[51.1, 30.7, 0.0], [-18.5, -35.9, 0.0], [33.9, -17.5, 0.0], [-6.1, -14.3, 0.0], [0.0, 0.0, 41.4], + [0.0, 0.0, 0.0]], + [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [19.0, -28.6, 0.0], [-16.3, -6.6, 0.0], [0.0, 0.0, 40.9], + [0.0, 0.0, -5.0]], + [[-0.3, -5.8, 0.0], [-29.4, -1.4, 0.0], [1.5, -31.5, 0.0], [-13.5, 4.5, 0.0], [0.0, 0.0, 32.3], + [0.0, 0.0, -9.4]], + [[-26.5, -2.9, 0.0], [-22.4, 9.4, 0.0], [-8.5, -20.3, 0.0], [-8.1, 10.9, 0.0], [0.0, 0.0, 22.1], + [0.0, 0.0, -6.8]], + [[-40.6, 7.4, 0.0], [-9.9, 11.2, 0.0], [-15.3, -9.6, 0.0], [-0.1, 8.5, 0.0], [0.0, 0.0, 17.6], + [0.0, 0.0, -5.9]], + [[-48.1, 21.0, 0.0], [-5.7, 14.7, 0.0], [-9.4, -3.0, 0.2], [2.3, 3.1, 0.0], [0.0, 0.0, 10.5], + [0.0, 0.0, -3.1]], + [[-52.9, 38.6, 0.0], [-5.0, 19.8, 0.0], [-11.3, -4.0, 0.0], [-6.1, -5.1, 0.0], [0.0, 0.0, 12.0], + [0.0, 0.0, 6.1]]]) + + }), + 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 6 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[10.7, 13.3, 0.0], [3.3, -16.0, 0.0], [8.7, -1.4, 0.0], [0.5, -3.7, 0.0], [0.0, 0.0, 7.4], + [0.0, 0.0, 1.6]], + [[9.5, -0.2, 0.0], [-6.0, -9.6, 0.0], [6.6, -5.1, 0.0], [-3.9, -4.3, 0.0], [0.0, 0.0, 8.5], + [0.0, 0.0, 0.7]], + [[2.3, -5.2, 0.0], [-9.3, -2.2, 0.0], [2.1, -9.1, -0.0], [-6.4, -1.6, 0.0], [0.0, 0.0, 9.0], + [0.0, 0.0, -0.1]], + [[-7.8, -3.9, 0.0], [-7.5, 4.2, 0.0], [-6.0, -8.0, 0.0], [-3.4, 3.4, 0.0], [0.0, 0.0, 8.1], + [0.0, 0.0, -1.5]], + [[-11.7, 1.7, 0.0], [-1.7, 7.2, 0.0], [-6.4, -3.5, 0.0], [1.4, 4.0, 0.0], [0.0, 0.0, 6.2], + [0.0, 0.0, -2.8]], + [[-10.7, 9.4, 0.0], [0.1, 6.6, 0.0], [-2.9, 0.0, 0.0], [1.1, 1.3, 0.0], [0.0, 0.0, 2.4], + [0.0, 0.0, -1.0]], + [[-11.3, 14.8, 0.0], [-1.2, 4.1, 0.0], [-3.5, -0.3, 0.0], [-2.3, -1.9, 0.0], [0.0, 0.0, 3.4], + [0.0, 0.0, 3.0]]]) + }), + 'Stomach coordinates': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 4 + }, + 'meshEdits': exnodeStringFromNodeValues( + [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], [ + [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.0, 1.2], [0.0, -0.7, 9.0], + [0.0, 1.2, 1.2]], + [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -8.9, -0.1], [0.0, 1.2, 0.0], [0.0, -0.1, 9.0], + [0.0, 0.0, -1.3]], + [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -7.0, -0.4], [0.0, 3.4, 0.0], [0.0, -0.4, 7.0], + [0.0, 0.0, -3.4]], + [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.7, 0.2], [0.0, -0.1, 2.5], + [0.0, 0.2, -1.7]], + [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.1, 0.2], [0.0, 0.1, 3.5], + [0.0, 0.2, 3.7]]]) + }), + } + + ostiumDefaultScaffoldPackages = { + 'Human 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'scaffoldSettings': { + 'Number of vessels': 1, + 'Number of elements across common': 2, + 'Number of elements around ostium': 8, + 'Number of elements along': 2, + 'Number of elements through wall': 1, # not implemented for > 1 + 'Unit scale': 1.0, + 'Outlet': False, + 'Ostium diameter': 25.0, + 'Ostium length': 10.0, + 'Ostium wall thickness': 5.0, + 'Ostium inter-vessel distance': 0.0, + 'Ostium inter-vessel height': 0.0, + 'Use linear through ostium wall': True, + 'Vessel end length factor': 1.0, + 'Vessel inner diameter': 5.0, + 'Vessel wall thickness': 5.0, + 'Vessel angle 1 degrees': 0.0, + 'Vessel angle 1 spread degrees': 0.0, + 'Vessel angle 2 degrees': 0.0, + 'Use linear through vessel wall': True, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + }, + }), + 'Rat 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'scaffoldSettings': { + 'Number of vessels': 1, + 'Number of elements across common': 2, + 'Number of elements around ostium': 8, + 'Number of elements along': 2, + 'Number of elements through wall': 1, # not implemented for > 1 + 'Unit scale': 1.0, + 'Outlet': False, + 'Ostium diameter': 5.0, + 'Ostium length': 5.0, + 'Ostium wall thickness': 0.5, + 'Ostium inter-vessel distance': 0.0, + 'Ostium inter-vessel height': 0.0, + 'Use linear through ostium wall': True, + 'Vessel end length factor': 1.0, + 'Vessel inner diameter': 1.25, + 'Vessel wall thickness': 0.5, + 'Vessel angle 1 degrees': 0.0, + 'Vessel angle 1 spread degrees': 0.0, + 'Vessel angle 2 degrees': 0.0, + 'Use linear through vessel wall': True, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + }, + }), + } + + @staticmethod + def getName(): + return '3D Stomach 2' + + @staticmethod + def getParameterSetNames(): + return [ + 'Default', + 'Generic 1', + 'Human 1', + 'Rat 1', + 'Stomach coordinates',] + + @classmethod + def getDefaultOptions(cls, parameterSetName='Default'): + if 'Rat 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] + elif 'Generic 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Generic 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] + elif 'Stomach coordinates' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Stomach coordinates'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] + else: + centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + + options = { + 'Central path': copy.deepcopy(centralPathOption), + 'Number of elements around oesophagus': 8, + 'Number of elements around duodenum': 12, + 'Number of elements along': 8, + 'Number of elements through wall': 1, + 'Wall thickness': 5.0, + 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), + 'Gastro-oesophagal junction position along factor': 0.25, + 'Annulus derivative factor': 1.0, + 'Number of radial elements in annulus': 1, # KM + 'Show track surface': False, # KM + 'Make stomach': True, # KM + 'Show central path': False, # KM + 'Use cross derivatives': False, + 'Use linear through wall' : False, # need to deal with wedge not available in bicubichermite + 'Refine': False, + 'Refine number of elements around': 1, + 'Refine number of elements along': 1, + 'Refine number of elements through wall': 1 + } + if ('Generic 1' or 'Rat 1' or 'Stomach coordinates') in parameterSetName: + options['Wall thickness'] = 0.5 + options['Gastro-oesophagal junction position along factor'] = 0.55 + + cls.updateSubScaffoldOptions(options) + return options + + @staticmethod + def getOrderedOptionNames(): + return [ + 'Central path', + 'Number of elements around oesophagus', + 'Number of elements around duodenum', + 'Number of elements along', + 'Number of elements through wall', + 'Wall thickness', + 'Gastro-oesophagal junction', + 'Gastro-oesophagal junction position along factor', + 'Annulus derivative factor', + 'Number of radial elements in annulus', + 'Show track surface', + 'Make stomach', + 'Show central path', + 'Use cross derivatives', + 'Use linear through wall', + 'Refine', + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall'] + + @classmethod + def getOptionValidScaffoldTypes(cls, optionName): + if optionName == 'Central path': + return [MeshType_1d_path1] + if optionName == 'Gastro-oesophagal junction': + return [MeshType_3d_ostium1] + return [] + + @classmethod + def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): + if optionName == 'Central path': + return list(cls.centralPathDefaultScaffoldPackages.keys()) + if optionName == 'Gastro-oesophagal junction': + return list(cls.ostiumDefaultScaffoldPackages.keys()) + assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ + cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ + 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() + return scaffoldType.getParameterSetNames() + + @classmethod + def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): + ''' + :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. + :return: ScaffoldPackage. + ''' + if parameterSetName: + assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ + 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() + if optionName == 'Central path': + if not parameterSetName: + parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] + return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + if optionName == 'Gastro-oesophagal junction': + if not parameterSetName: + parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] + return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) + assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' + + @classmethod + 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-oesophagal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( + 'Gastro-oesophagal junction'): + options['Gastro-oesophagal junction'] = cls.getOptionScaffoldPackage('Gastro-oesophagal junction', + MeshType_3d_ostium1) + if options['Number of elements around oesophagus'] < 8: + options['Number of elements around oesophagus'] = 8 + if options['Number of elements around oesophagus'] % 4 > 0: + options['Number of elements around oesophagus'] = options['Number of elements around oesophagus'] // 4 * 4 + if options['Number of elements around duodenum'] < 12: + options['Number of elements around duodenum'] = 12 + for key in [ + 'Number of elements around oesophagus', + 'Number of elements around duodenum']: + if options[key] % 2: + options[key] += 1 + if options['Number of elements along'] < 8: + options['Number of elements along'] = 8 + if options['Annulus derivative factor'] < 0: + options['Annulus derivative factor'] = 0.0 + for key in [ + 'Number of elements through wall', + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall']: + if options[key] < 1: + options[key] = 1 + + cls.updateSubScaffoldOptions(options) + + @classmethod + def updateSubScaffoldOptions(cls, options): + ''' + Update ostium sub-scaffold options which depend on parent options. + ''' + wallThickness = options['Wall thickness'] + ostiumOptions = options['Gastro-oesophagal junction'] + ostiumSettings = ostiumOptions.getScaffoldSettings() + ostiumSettings['Ostium wall thickness'] = wallThickness + + @classmethod + def generateBaseMesh(cls, region, options): + """ + Generate the base tricubic Hermite mesh. See also generateMesh(). + :param region: Zinc region to define model in. Must be empty. + :param options: Dict containing options. See getDefaultOptions(). + :return: None + """ + cls.updateSubScaffoldOptions(options) + centralPath = options['Central path'] + elementsCountAroundOesophagus = options['Number of elements around oesophagus'] + elementsCountAroundDuodenum = options['Number of elements around duodenum'] + elementsCountAlong = options['Number of elements along'] + elementsCountThroughWall = options['Number of elements through wall'] + wallThickness = options['Wall thickness'] + useCrossDerivatives = options['Use cross derivatives'] + useCubicHermiteThroughWall = not (options['Use linear through wall']) + + GOJPositionAlongFactor = options['Gastro-oesophagal junction position along factor'] + GOJOptions = options['Gastro-oesophagal junction'] + GOJSettings = GOJOptions.getScaffoldSettings() + oesophagusDiameter = GOJSettings['Ostium diameter'] + annulusDerivativeFactor = options['Annulus derivative factor'] + elementsCountAnnulus = options['Number of radial elements in annulus'] + + trackSurface = options['Show track surface'] + makeStomach = options['Make stomach'] + showCentralPath = options['Show central path'] + + elementsCountAlongTrackSurface = 20 + + ############################################################################################ + zero = [0.0, 0.0, 0.0] + + fm = region.getFieldmodule() + fm.beginChange() + + coordinates = findOrCreateFieldCoordinates(fm) + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) + if useCubicHermiteThroughWall: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) + + cache = fm.createFieldcache() + ########################################################################################### + + firstNodeIdentifier = 1 + firstElementIdentifier = 1 + + # Central path + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + cx, cd1, cd2, cd3, cd12, cd13 = extractPathParametersFromRegion(tmpRegion, + [Node.VALUE_LABEL_VALUE, + Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, + Node.VALUE_LABEL_D_DS3, + Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS1DS3]) + del tmpRegion + # for i in range(len(cx)): + # cd3New = vector.setMagnitude(cd3[i], vector.magnitude(cd2[i])) + # print(i, vector.magnitude(cd2[i]), vector.magnitude(cd3[i]), cd3New) + # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') + + sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongTrackSurface) + sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) + sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) + + # Make sampled d2 and d3 normal to central path + # d2Check = [] + # for c in range(len(sx)): + # td2 = vector.vectorRejection(sd2[c], sd1[c]) + # sd2[c] = vector.setMagnitude(td2, vector.magnitude(sd2[c])) + # d2Check.append(matrix.rotateAboutZAxis(sd2[c], math.pi)) + # td3 = vector.vectorRejection(sd3[c], sd1[c]) + # sd3[c] = vector.setMagnitude(td3, vector.magnitude(sd3[c])) + + # Calculate length of central path + stomachCentralPathLength = 0.0 + for e in range(len(sx) - 1): + arcLength = interp.getCubicHermiteArcLength(sx[e], sd1[e], sx[e + 1], sd1[e + 1]) + # print(e+1, arcLength) + stomachCentralPathLength += arcLength + lengthElementAlong = stomachCentralPathLength / elementsCountAlongTrackSurface + + nodeIdentifier = firstNodeIdentifier + elementIdentifier = firstElementIdentifier + + # Fundus diameter + fundusRadius = vector.magnitude(sd2[0]) + elementsAlongFundus = int(fundusRadius / lengthElementAlong) + + d2Apex = [] + d2 = sd2[0] + for n1 in range(elementsCountAroundDuodenum): + rotAngle = n1 * 2.0 * math.pi / elementsCountAroundDuodenum + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) # vector.normalise(sd1[0]) + 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)] + d2Apex.append(d2Rot) + + xEllipses = [] + d1Ellipses = [] + for n in range(elementsAlongFundus + 1, len(sx)): + px, pd1 = createEllipsePoints(sx[n], 2 * math.pi, sd2[n], sd3[n], elementsCountAroundDuodenum, + startRadians=0.0) + xEllipses.append(px) + d1Ellipses.append(pd1) + + # Find d2 + d2Raw = [] + for n1 in range(elementsCountAroundDuodenum): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses) - 1): + v1 = xEllipses[n2][n1] + v2 = xEllipses[n2 + 1][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v1) + d2Along.append(d2) + xAlong.append(xEllipses[-1][n1]) + d2Along.append(d2) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Raw.append(d2Smoothed) + + # Rearrange d2 + d2Ellipses = [] + for n2 in range(len(xEllipses)): + d2Around = [] + for n1 in range(elementsCountAroundDuodenum): + d2 = d2Raw[n1][n2] + d2Around.append(d2) + d2Ellipses.append(d2Around) + + # for n2 in range(len(xEllipses)): + # for n1 in range(elementsCountAroundDuodenum): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xEllipses[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Ellipses[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Ellipses[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # for n1 in range(len(sx)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd1[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd2[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Check[n1]) + # nodeIdentifier += 1 + + # Merge fundus and body + xAll = [[sx[0]] * elementsCountAroundDuodenum] + xEllipses + d2All = [d2Apex] + d2Ellipses + + # for n2 in range(len(xAll)): + # for n1 in range(elementsCountAroundDuodenum): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2All[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Spread out elements + xRaw = [] + d2Raw = [] + for n1 in range(elementsCountAroundDuodenum): + xAlong = [] + d2Along = [] + for n2 in range(len(xAll)): + xAlong.append(xAll[n2][n1]) + d2Along.append(d2All[n2][n1]) + xSampledAlong, d2SampledAlong = interp.sampleCubicHermiteCurves(xAlong, d2Along, + elementsCountAlongTrackSurface, + arcLengthDerivatives=True)[0:2] + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlong, d2SampledAlong) + xRaw.append(xSampledAlong) + d2Raw.append(d2Smoothed) + + # Rearrange x and d2 + xSampledAll = [] + d1SampledAll = [] + d2SampledAll = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + xAround = [] + d1Around = [] + d2Around = [] + for n1 in range(elementsCountAroundDuodenum): + x = xRaw[n1][n2] + d2 = d2Raw[n1][n2] + xAround.append(x) + d2Around.append(d2) + + # Calculate d1 + if n2 > 0: + v1 = xRaw[n1][n2] + v2 = xRaw[n1 + 1 if n1 < elementsCountAroundDuodenum - 2 else 0][n2] + d1 = findDerivativeBetweenPoints(v1, v2) + d1Around.append(d1) + else: + d1Around.append(d2Raw[int(elementsCountAroundDuodenum * 0.75)][0]) + + if n2 > 0: + d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) + else: + d1Smoothed = d1Around + + xSampledAll.append(xAround) + d1SampledAll.append(d1Smoothed) + d2SampledAll.append(d2Around) + + # for n2 in range(elementsCountAlongTrackSurface + 1): + # for n1 in range(elementsCountAroundDuodenum): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Create tracksurface + xTrackSurface = [] + d1TrackSurface = [] + d2TrackSurface = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + for n1 in range(elementsCountAroundDuodenum): + xTrackSurface.append(xSampledAll[n2][n1]) + d1TrackSurface.append(d1SampledAll[n2][n1]) + d2TrackSurface.append(d2SampledAll[n2][n1]) + + trackSurfaceStomach = TrackSurface(elementsCountAroundDuodenum, elementsCountAlongTrackSurface, + xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) + + if makeStomach: + # Set up gastro-oesophagal junction + GOJSettings['Number of elements around ostium'] = elementsCountAroundOesophagus + GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) + xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) + axis1 = d1Centre + + # fm = region.getFieldmodule() + mesh = fm.findMeshByDimension(3) + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + + nextNodeIdentifier = nodeIdentifier + nextElementIdentifier = elementIdentifier + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, + nextNodeIdentifier, nextElementIdentifier) + bodyStartNode = nextNodeIdentifier + + # From oesophagus to duodenum along lesser curvature (LC) + elementsOesoToDuodLC = elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) # CHECK + startProportion1, startProportion2 = trackSurfaceStomach.getProportion( + o1_Positions[int(elementsCountAroundOesophagus * 0.5)]) + d1Start = o1_d2[1][int(elementsCountAroundOesophagus * 0.5)] + + xOesoToDuodLC, d2OesoToDuodLC = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, 0.5, 1.0, + elementsOesoToDuodLC, startDerivative=d1Start, + startDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude(d1Start)) + + # From oesophagus to duodenum along greater curvature (GC) + xAlongGC = [] + d2AlongGC = [] + xAlongGC.append(o1_x[1][0]) + d2AlongGC.append(o1_d2[1][0]) + + oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] + elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) + + # From oesophagus to fundus apex + arcLengthOesoApex = 0.0 + for n2 in range(elementsAlongUpstreamOfOeso): + nAlong = elementsAlongUpstreamOfOeso - n2 + v1 = xSampledAll[nAlong][int(elementsCountAroundDuodenum * 0.5)] + v2 = xSampledAll[nAlong - 1][int(elementsCountAroundDuodenum * 0.5)] + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + arcLengthOesoApex += arcLengthAround + d2 = [c * arcLengthAround for c in vector.normalise(d)] + xAlongGC.append(v1) + d2AlongGC.append(d2) + + # From fundus apex to duodenum + for n2 in range(len(xSampledAll)): + xAlongGC.append(xSampledAll[n2][0]) + d2AlongGC.append(d2SampledAll[n2][0]) + + elementsOesoToDuodGC = elementsCountAlong + int(elementsCountAroundDuodenum * 0.5) - 2 # Check + xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurvesSmooth(xAlongGC, d2AlongGC, elementsOesoToDuodGC, + derivativeMagnitudeStart=annulusDerivativeFactor * vector.magnitude( + d2AlongGC[0]))[0:2] + # xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurves(xAlongGC, d2AlongGC, elementsOesoToDuodGC, + # addLengthStart= vector.magnitude( + # d2AlongGC[0]), lengthFractionStart=0.5)[0:2] + + d2OesoToDuodGC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2OesoToDuodGC) + # curvature - DONE + + arcLength = 0.0 + for e in range(len(xOesoToDuodGC) - 1): + arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], + xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) + if arcLength > arcLengthOesoApex: + nodesCountFromOesoToApex = e + 2 + break + + nodeIdentifier = nextNodeIdentifier + + # for n2 in range(len(xOesoToDuodLC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodLC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # for n2 in range(len(xOesoToDuodGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Spread out elements around for each egroup around + # Elements around oesophagus + # Decide where to put extra elements if elementsOesophagus/2 is odd number. + # Right now, extra elements go downstream of bifurcation + # For even numbers, we split elements at bifurcation + + ptsOnTrackSurfaceGC = [] + xAlongAround = [] + d1AlongAround = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) + + # Ring adjacent to LC + # First half + for n2 in range(int(elementsCountAroundOesophagus * 0.25 + 1), int(elementsCountAroundOesophagus * 0.5)): + ostiumIdx = n2 + GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + n2 + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + + endPosition = o1_Positions[ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) + d2 = o1_d2[1][ostiumIdx] + d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, + endProportion2, int(0.5 * elementsCountAroundDuodenum + 1), + startDerivative=d1GC, endDerivative= d1EndOstium, + endDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1EndOstium)) + + # for n2 in range(len(xFirstHalf)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstHalf[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1FirstHalf[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Second half + ostiumIdx2 = -n2 + startPosition = o1_Positions[ostiumIdx2] + d1StartOstium = o1_d2[1][ostiumIdx2] + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] + + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, + GCProportion2, int(0.5 * elementsCountAroundDuodenum + 1), + startDerivative=d1StartOstium, endDerivative=d1GC, + startDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1StartOstium)) + + xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] + d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # Elements downstream of oesophagus + for idx in range(-(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1), 0): + startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], + ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + + endPosition = trackSurfaceStomach.findNearestPosition(xOesoToDuodLC[idx]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + d1End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, startProportion2, endProportion1, + endProportion2, int(0.5 * elementsCountAroundDuodenum), + startDerivative=d1Start, endDerivative=d1End) + + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, endProportion1, endProportion2, 1.0, + startProportion2, int(0.5 * elementsCountAroundDuodenum), + startDerivative=d1End, endDerivative=d1Start) + + # Average adjacent ring with first downstream ring that is not adjacent to oesophagus + if idx == -(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1): + xAve = [] + dAve = [] + xAve.append(xOesoToDuodGC[idx - 1]) + for n in range(1, int(elementsCountAroundDuodenum * 0.5)): + # nx = [xAround[n], xFirstHalf[n]] + # d = [xFirstHalf[n][c] - xAround[n][c] for c in range(3)] + # nd1 = [d, d] + # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] + # xAve.append(xSampled[1]) + + startPosition = trackSurfaceStomach.findNearestPosition(xAround[n]) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + endPosition = trackSurfaceStomach.findNearestPosition(xFirstHalf[n]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + xSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, endProportion1, endProportion2, 2)[0] + xAve.append(xSampled[1]) + + xAve.append(xOesoToDuodLC[idx - 1]) + + for n in range(1, int(elementsCountAroundDuodenum * 0.5)): + # nx = [xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1], xSecondHalf[n]] + # d = [xSecondHalf[n][c] - xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1][c] for c in range(3)] + # nd1 = [d, d] + # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] + # xAve.append(xSampled[1]) + + startPosition = trackSurfaceStomach.findNearestPosition(xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1]) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + endPosition = trackSurfaceStomach.findNearestPosition(xSecondHalf[n]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + xSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, endProportion1, endProportion2, 2)[0] + xAve.append(xSampled[1]) + + for n in range(len(xAve)): + v1 = xAve[n] + v2 = xAve[(n+1) % len(xAve)] + d1 = findDerivativeBetweenPoints(v1, v2) + dAve.append(d1) + dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) + + xAlongAround.append(xAve) + d1AlongAround.append(dAve) + + xAround = xFirstHalf + xSecondHalf[1:-1] + d1Around = d1FirstHalf + d1SecondHalf[1:-1] + d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) + # calculate curvature + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # for n2 in range(len(xAlongAround)): + # for n1 in range(len(xAlongAround[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround + ptsOnTrackSurfaceOesoToFundus = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][int(elementsCountAroundDuodenum * 0.5)]) + + xFirstTwoLoopsRight = [] + xFirstTwoLoopsLeft = [] + d2FirstTwoLoopsRight = [] #KM + d2FirstTwoLoopsLeft = [] # KM + + for nLoop in range(1, 3): + GCIdx = nLoop + 1 + if GCIdx < nodesCountFromOesoToApex: + ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus + proportion1 = 0.5 + else: + ptsOnTrackSurface = ptsOnTrackSurfaceGC + proportion1 = 0.0 + d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], + ptsOnTrackSurface, + trackSurfaceStomach, proportion1, + elementsCountAlongTrackSurface)[1] + + if GCIdx < nodesCountFromOesoToApex: + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in + range(3)] + d2GC = d2GCRot + + for nSide in range(2): + if nSide == 0: + xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop] + d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] - + xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] for c in range(3)] + else: + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in + range(3)] + d2GC = d2GCRot + + xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + nLoop] + d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) + nLoop][c] - + xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) + (0 if elementsCountAroundOesophagus > 8 else 1) + nLoop][c] for c in range(3)] + + nx = [xOesoToDuodGC[GCIdx], xEnd] + nd2 = [d2GC, d2End] + x, d2 = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25 + 2), + arcLengthDerivatives=True)[0:2] + + # Find closest sampled points onto track surface + xProjectedPoints = [] + d2ProjectedPoints = [] + for n2 in range(len(x)): + projectedPosition = trackSurfaceStomach.findNearestPosition(x[n2]) + xProjected = trackSurfaceStomach.evaluateCoordinates(projectedPosition) + xProjectedPoints.append(xProjected) + + for n2 in range(len(xProjectedPoints) - 1): + d2 = findDerivativeBetweenPoints(xProjectedPoints[n2], xProjectedPoints[n2 + 1]) + d2ProjectedPoints.append(d2) + d2ProjectedPoints.append(d2) + + # Sample points again + xLoop, d2Loop = interp.sampleCubicHermiteCurves(xProjectedPoints, d2ProjectedPoints, + int(elementsCountAroundOesophagus * 0.25 + 2))[0:2] + + (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft).append(xLoop) + (d2FirstTwoLoopsRight if nSide == 0 else d2FirstTwoLoopsLeft).append(d2Loop) + + # for n2 in range(len(xFirstTwoLoopsRight)): + # for n1 in range(len(xFirstTwoLoopsRight[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsRight[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsRight[n2][n1]) + # nodeIdentifier += 1 + # + # for n2 in range(len(xFirstTwoLoopsLeft)): + # for n1 in range(len(xFirstTwoLoopsLeft[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsLeft[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsLeft[n2][n1]) + # nodeIdentifier += 1 + + # Find triple point + xTriplePts = [[None], [None]] # Right, left + d1TriplePts = [[None], [None]] + d2TriplePts = [[None], [None]] + d3TriplePtsNorm = [[None], [None]] + + for nSide in range(2): + ostiumIdx = int(elementsCountAroundOesophagus * 0.25) if nSide == 0 else -int(elementsCountAroundOesophagus * 0.25) + p1x = o1_x[1][ostiumIdx] + d = o1_d2[1][ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][ostiumIdx], math.pi) + p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + p1d = [annulusDerivativeFactor * c for c in p1d] + + xFirstTwoLoops = xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft + p2x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)] # downstream bifurcation + p2d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)], + xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25 + 1)]) + + p3x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)] + p3d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)], + xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25)]) + + xTriplePts[nSide], d1TriplePts[nSide], d2TriplePts[nSide] = get_bifurcation_triple_point(p1x, p1d, p2x, p2d, p3x, p3d) + d3TriplePtsNorm[nSide] = vector.normalise( + vector.crossproduct3(vector.normalise(d1TriplePts[nSide]), vector.normalise(d2TriplePts[nSide]))) + + # Make sure triple point is on track surface + triplePointPosition = trackSurfaceStomach.findNearestPosition(xTriplePts[nSide]) + xTriplePts[nSide] = trackSurfaceStomach.evaluateCoordinates(triplePointPosition) + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p1x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p1d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p2x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p2d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p3x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p3d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3TriplePtsNorm[nSide]) + # nodeIdentifier += 1 + + # Use track surface to sample point on GC to loop 1 (includes bifurcation rings and additional upstream rings) + xBifurcationRings = [] + d1BifurcationRings = [] + xUp = [] + d1Up = [] + for n2 in range(int(elementsCountAroundOesophagus * 0.25)): + xAround = [] + d1Around = [] + loopIdx = n2 + 2 + ostiumIdx = loopIdx + (0 if n2 < int(elementsCountAroundOesophagus * 0.25 - 1) else -1) + GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + 1 + n2 + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + + if loopIdx < int(elementsCountAroundOesophagus * 0.25): # additional elements upstream of triple point + for nSide in range(2): + if nSide == 0: + xLoop = xFirstTwoLoopsRight[0][loopIdx] + xOstium = o1_x[1][ostiumIdx] + ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xLoop, xOstium) + endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, + GCProportion2, ostiumProportion1, ostiumProportion2, + int(elementsCountAroundDuodenum * 0.5 + 1), + startDerivative=d1GC, endDerivative=d, + endDerivativeMagnitude=endDerivativeMag)[0:2] + + else: + xLoop = xFirstTwoLoopsLeft[0][loopIdx] + xOstium = o1_x[1][-ostiumIdx] + ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xOstium, xLoop) + startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, + 1.0, GCProportion2, + int(elementsCountAroundDuodenum * 0.5 + 1), + startDerivative= d, endDerivative=d1GC, + startDerivativeMagnitude=startDerivativeMag)[0:2] + + xAround += xSampled[:-1] if nSide == 0 else xSampled[1:-1] + d1Around += dSampled[:-1] if nSide == 0 else dSampled[1:-1] + + # for n1 in range(len(xAround)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Around[n1]) + # nodeIdentifier += 1 + + # xBifurcationRings.append(xAround) + # d1BifurcationRings.append(d1Around) + xUp.append(xAround) + d1Up.append(d1Around) + + else: # connected to triple point + for nSide in range(2): + xLoop = (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft)[0][loopIdx] + loopPosition = trackSurfaceStomach.findNearestPosition(xLoop) + loopProportion1, loopProportion2 = trackSurfaceStomach.getProportion(loopPosition) + + if nSide == 0: + d = findDerivativeBetweenPoints(xLoop, o1_x[1][ostiumIdx]) + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, + GCProportion2, loopProportion1, loopProportion2, + int(elementsCountAroundDuodenum * 0.5) - 1, + startDerivative=d1GC, endDerivative = d)[0:2] + xSampled.append(xTriplePts[0]) + dSampled.append(d1TriplePts[0]) + + else: + d = findDerivativeBetweenPoints(o1_x[1][-ostiumIdx], xLoop) + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, loopProportion1, + loopProportion2, 1.0, GCProportion2, + int(elementsCountAroundDuodenum * 0.5) - 1, + startDerivative = d, endDerivative=d1GC)[0:2] + xSampled.insert(0, xTriplePts[1]) + dSampled.insert(0, d1TriplePts[1]) + + xAround += xSampled if nSide == 0 else xSampled[:-1] + d1Around += dSampled if nSide == 0 else dSampled[:-1] + + xUp.append(xAround) + d1Up.append(d1Around) + xBifurcationRings.append(xAround) + d1BifurcationRings.append(d1Around) + + # for n2 in range(len(xBifurcationRings)): + # for n1 in range(len(xBifurcationRings[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBifurcationRings[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1BifurcationRings[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Row 2 + for nSide in range(2): + if nSide == 0: + xStart = xUp[0][1] + dStart = findDerivativeBetweenPoints(xUp[1][1], xUp[0][1]) + startDerivativeMag = None + xEnd = o1_x[1][1] + dEnd = findDerivativeBetweenPoints(xFirstTwoLoopsRight[0][1], o1_x[1][1]) + endDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) + + else: + xStart = o1_x[1][-1] + dStart = findDerivativeBetweenPoints(o1_x[1][-1], xFirstTwoLoopsLeft[0][1]) + startDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) + xEnd = xUp[0][-1] + dEnd = findDerivativeBetweenPoints(xUp[0][-1], xUp[1][-1]) + endDerivativeMag = None + + startPosition = trackSurfaceStomach.findNearestPosition(xStart) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + endPosition = trackSurfaceStomach.findNearestPosition(xEnd) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, + endProportion1, endProportion2, + int(elementsCountAroundDuodenum * 0.5), + startDerivative=dStart, endDerivative=dEnd, + startDerivativeMagnitude=startDerivativeMag, + endDerivativeMagnitude=endDerivativeMag)[0:2] + + if nSide == 0: + xRow2Right = xSampled[:-1] + d1Row2Right = dSampled[:-1] + else: + xRow2Left = xSampled[1:] + d1Row2Left = dSampled[1:] + + # for n1 in range(len(xRow2Right)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Right[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Right[n1]) + # nodeIdentifier += 1 + + # for n1 in range(len(xRow2Left)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Left[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Left[n1]) + # nodeIdentifier += 1 + + # Smooth derivatives from triple point to 6 point junction + # Start from GC at upstream bifurcation ring to annulus to 6 point junction ring on right then left + xLoopTripleTo6Pt = [] + dLoopTripleTo6Pt = [] + + xLoopTripleTo6Pt += xBifurcationRings[0][0:int(len(xBifurcationRings[0]) * 0.5) + 1] + for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): + xLoopTripleTo6Pt.append(xAlongAround[n2][int(len(xAlongAround[n2]) * 0.5)]) + junctionIdx = n2 + 1 + xLoopTripleTo6Pt += xAlongAround[junctionIdx][int(len(xAlongAround[junctionIdx]) * 0.5):] + \ + xAlongAround[junctionIdx][0: int(len(xAlongAround[junctionIdx]) * 0.5 + 1)] + for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): # Note order here - going upstream + idx = junctionIdx - 1 - n2 + xLoopTripleTo6Pt.append(xAlongAround[idx][int(len(xAlongAround[idx]) * 0.5) + 1]) + xLoopTripleTo6Pt += xBifurcationRings[0][int(len(xBifurcationRings[0]) * 0.5 + 1):] + + for n in range(len(xLoopTripleTo6Pt)): + d = findDerivativeBetweenPoints(xLoopTripleTo6Pt[n], xLoopTripleTo6Pt[(n+1) % len(xLoopTripleTo6Pt)]) + dLoopTripleTo6Pt.append(d) + dSmoothLoopTripleTo6Pt = interp.smoothCubicHermiteDerivativesLoop(xLoopTripleTo6Pt, dLoopTripleTo6Pt) + # curvature - DONE + + # for n1 in range(len(xLoopTripleTo6Pt)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopTripleTo6Pt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopTripleTo6Pt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) + # nodeIdentifier += 1 + + # Smooth derivatives around top loop + # Starts from GC at downstream bifurcation ring to annulus and back + xLoopGCTriplePt = [] + dLoopGCTriplePt = [] + + xLoopGCTriplePt += xBifurcationRings[1][:int(len(xBifurcationRings[1]) * 0.5) + 1] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): + idx = -(3 + n2) + xLoopGCTriplePt.append(xUp[idx][int(len(xUp[idx]) * 0.5)]) + + xLoopGCTriplePt += [xRow2Right[-1]] + [xOesoToDuodGC[1]] + [xRow2Left[0]] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): + xLoopGCTriplePt.append(xUp[n2][int(len(xUp[n2]) * 0.5) + 1]) + + xLoopGCTriplePt += xBifurcationRings[1][int(len(xBifurcationRings[1]) * 0.5) + 1:] + + for n in range(len(xLoopGCTriplePt)): + d = findDerivativeBetweenPoints(xLoopGCTriplePt[n], xLoopGCTriplePt[(n+1) % len(xLoopGCTriplePt)]) + dLoopGCTriplePt.append(d) + dSmoothLoopGCTriplePt = interp.smoothCubicHermiteDerivativesLoop(xLoopGCTriplePt, dLoopGCTriplePt) + # curvature - DONE + + # for n1 in range(len(xLoopGCTriplePt)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopGCTriplePt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopGCTriplePt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) + # nodeIdentifier += 1 + + # Assemble nodes and d1 + xOuter = [] + d1Outer = [] + countUp = 0 + countDown = 0 + for n2 in range(elementsCountAlong + 1): + xAround = [] + d1Around = [] + d2Around = [] + if n2 == 0: + # print(n2, 'GC') + for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xAround.append(xOesoToDuodGC[i + 1]) + d1Around.append(d2OesoToDuodGC[i + 1]) + + elif n2 == 1: + # print(n2, 'Row 2') + xAround = [xOesoToDuodGC[i + n2 + 1]] + xRow2Right[1:] + xRow2Left[:-1] + d1Around = [d2OesoToDuodGC[i + n2 + 1]] + d1Row2Right[1:] + d1Row2Left[:-1] # need to replace d1Row2 after smoothing - DONE + + elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): + # print(n2, 'Before triple point + triple point') + xAround = xUp[countUp] + if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt + # smooth d1 around - Make into function? + d1Around = d1Up[countUp] + 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)] + d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, + fixEndDerivative=True) + # Need to do curvature and rearrange to correct order + d1Around = [] + d1Around = d1LoopSmooth[int(len(xAround) * 0.5) : ] + d1LoopSmooth[: int(len(xAround) * 0.5) : ] + + elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation + # take smoothed d1 from dSmoothTripleTo6Pt + d1Around = dSmoothLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ + dSmoothLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5) : ] + + elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation + # take smoothed d1 from dSmoothGCToTriplePt + d1Around = dSmoothLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ + dSmoothLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5) : ] + countUp += 1 + + elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): + # print(n2, 'Downstream of triple point') + xAround = xAlongAround[countDown] + d1Around = d1AlongAround[countDown] + + # smooth d1 around - Make into function? + if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): + 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)] + d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, + fixEndDerivative=True) + # Need to do curvature and rearrange to correct order + d1Around = [] + d1Around = d1LoopSmooth[int(len(xAround) * 0.5):] + d1LoopSmooth[: int(len(xAround) * 0.5):] + + elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring + # take smoothed d1 from dSmoothedTripleTo6Pt + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len(xAlongAround[junctionIdx]) * 0.5) + endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + d1Around = dSmoothLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ + dSmoothLoopTripleTo6Pt[startLeftIdx : startRightIdx] + countDown += 1 + + xOuter.append(xAround) + d1Outer.append(d1Around) + + # for m2 in range(len(xOuter)): + # for m1 in range(len(xOuter[m2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Calculate d2 + xRegularLoops = [] + d2RegularLoops = [] + d2RegularOrderedLoops = [] + + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xRegularLoop = [] + d1RegularRightLoop = [] + d2RegularLoop = [] + for n2 in range(elementsCountAlong): + idx = -(1 + n2) + xRegularLoop.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + d1RegularRightLoop.append(d1Outer[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + xRegularLoop.append(xOesoToDuodGC[n1 + 2]) + for n2 in range(elementsCountAlong): + xRegularLoop.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) + + for n in range(len(xRegularLoop) - 1): + d = findDerivativeBetweenPoints(xRegularLoop[n], xRegularLoop[n+1]) + d2RegularLoop.append(d) + d2RegularLoop.append(d) + + d2SmoothRegularLoop = interp.smoothCubicHermiteDerivativesLine(xRegularLoop, d2RegularLoop) + d2SmoothRegularOrderedLoop = copy.deepcopy(d2SmoothRegularLoop) + # curvature - DONE + + # Switch direction on right side + for n2 in range(elementsCountAlong): + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1RegularRightLoop[n2]), d2SmoothRegularLoop[n2])) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d = d2SmoothRegularLoop[n2] + d2SmoothRegularLoop[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + + xRegularLoops.append(xRegularLoop) + d2RegularLoops.append(d2SmoothRegularLoop) + d2RegularOrderedLoops.append(d2SmoothRegularOrderedLoop) + + # for m1 in range(len(xRegularLoops)): + # for m2 in range(len(xRegularLoops[m1])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRegularLoops[m1][m2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2RegularOrderedLoops[m1][m2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #d2RegularLoops[m1][m2]) + # nodeIdentifier += 1 + + # Smooth d2 along row 2 + xLoop2Right = [] + d1Loop2Right = [] + d2Loop2Right = [] + + for n2 in range(len(xAlongAround) + len(xUp) - 1): + idx = -(1 + n2) + xLoop2Right.append(xOuter[idx][1]) + d1Loop2Right.append(d1Outer[idx][1]) + xLoop2Right += xRow2Right + d1Loop2Right += d1Row2Right + + for n in range(len(xLoop2Right) - 1): + d = findDerivativeBetweenPoints(xLoop2Right[n], xLoop2Right[n + 1]) + d2Loop2Right.append(d) + d2Loop2Right.append(d1Row2Right[-1]) + + d2Loop2Right = interp.smoothCubicHermiteDerivativesLine(xLoop2Right, d2Loop2Right, fixEndDirection=True) + # curvature - USING LEFT SIDE - DONE + + # Switch direction of d2 for downstream nodes + for n2 in range(len(xAlongAround) + len(xUp)): + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1Loop2Right[n2]), d2Loop2Right[n2])) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d = d2Loop2Right[n2] + d2Loop2Right[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + idxSwitchToD1 = n2 + + # for m in range(len(xLoop2Right)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Right[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) #d2Loop2Right[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Loop2Right[m]) + # nodeIdentifier += 1 + + # Left + xLoop2Left = [] + d2Loop2Left = [] + + xLoop2Left += xRow2Left + for n2 in range(3, len(xOuter)): + xLoop2Left.append(xOuter[n2][-1]) + + d2Loop2Left.append(d1Row2Left[0]) + for n in range(1, len(xLoop2Left) - 1): + d = findDerivativeBetweenPoints(xLoop2Left[n], xLoop2Left[n + 1]) + d2Loop2Left.append(d) + d2Loop2Left.append(d) + + d2Loop2Left = interp.smoothCubicHermiteDerivativesLine(xLoop2Left, d2Loop2Left, fixStartDirection=True) + # curvature - DONE + + # for m in range(len(xLoop2Left)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Left[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Loop2Left[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Smooth lower curvature + xLC = [] + d2LC = [] + for n2 in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): + xLC.append(xOuter[n2][int(len(xOuter[n2]) * 0.5)]) + + for n in range(len(xLC) - 1): + d = findDerivativeBetweenPoints(xLC[n], xLC[n + 1]) + d2LC.append(d) + d2LC.append(d) + + d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC, fixStartDirection=True) + # curvature - DONE + + # for m in range(len(xLC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLC[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LC[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Update d1 for upstream nodes + for n1 in range(1, len(xRow2Right)): + d1Outer[1][n1] = d2Loop2Right[idxSwitchToD1 + n1] + for n1 in range(1, len(xRow2Left)): + d1Outer[1][int(len(d1Outer[1]) * 0.5) + n1] = d2Loop2Left[n1 - 1] + + # Assemble d2 + d2Outer = [] + for n2 in range(elementsCountAlong + 1): + d2Around = [] + xAround = [] # KM + if n2 == 0: + # print(n2, 'GC') + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5)]) #KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(dSmoothLoopGCTriplePt) * 0.5)]) + + for n1 in range(len(xOuter[0]) - 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) + d2Around.append(d2RegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) + nextIdx = n1 + 1 + + elif n2 == 1: + # print(n2, 'Row 2') + xAround.append(xRegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) + d2Around.append(d2RegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) + + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + # right point on annulus + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2]) # KM + d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2] + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append([rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) + + # left point on annulus + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) # KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) + + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + + elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): + # print(n2, 'Before triple point + triple point') + # GC + xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) + + # Row 2 right + xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) + d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) + + # Regular up right + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + # Annulus right + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM + d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)] + if n2 <= int(elementsCountAroundOesophagus * 0.25): # Rotate to point towards duodenum + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), + vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append( + [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) + else: # just take d2 as-is cos we are going to remove this point later + d2Around.append(d2) + + # Annulus left + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + + # Regular down left + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + + # Row 2 left + xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) + d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) + + # for m1 in range(len(d2Around)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Around[m1]) + # nodeIdentifier += 1 + + elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): + # print(n2, 'Downstream of triple point') + # GC + xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) + + # Row 2 right + xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) + d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) + + # Regular up right + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: + # Annulus right + # print('between triple and 6 pt') + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) + xAround.append(xLoopTripleTo6Pt[idx]) + if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: + d1 = dSmoothLoopTripleTo6Pt[idx] + d1Outer[n2][int(len(d1Outer[n2]) * 0.5)] = d1 + else: + d2Around.append(dSmoothLoopTripleTo6Pt[idx]) + + # Annulus left - need to rotate to point towards duodenum + xAround.append(xLoopTripleTo6Pt[-idx]) + # d2Around.append(dSmoothLoopTripleTo6Pt[-idx]) + d2 = dSmoothLoopTripleTo6Pt[-idx] + if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5 + 1)]), + vector.normalise(d2))) + else: # use d2 on previous overlapping point to rotate + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append( + [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in + range(3)]) + + elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: + # print('beyond 6 pt') + # LC + xAround.append(xLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) + d2Around.append(d2LC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) + + # Regular down left + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + + # Row 2 left + xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) + d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) + + d2Outer.append(d2Around) + + # remove triple point on both sides from downstream ring + n2Idx = int(elementsCountAroundOesophagus * 0.25 + 1) + n1Idx = int(len(xOuter[n2Idx]) * 0.5) + del xOuter[n2Idx][n1Idx: n1Idx + 2], d1Outer[n2Idx][n1Idx: n1Idx + 2], d2Outer[n2Idx][n1Idx: n1Idx + 2] + + d3UnitOuter = [] + for n2 in range(elementsCountAlong + 1): + d3Around = [] + for n1 in range(len(xOuter[n2])): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) + d3UnitOuter.append(d3Around) + + # for m2 in range(len(xOuter)): + # for m1 in range(len(xOuter[m2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[m2][m1]) + # nodeIdentifier += 1 + + # Calculate curvatures + # Curvatures along GC + xGC = [] + dGC = [] + norms = [] + for n1 in range(len(xOuter[0])): + xGC.append(xOuter[0][n1]) + dGC.append(d1Outer[0][n1]) + norms.append(d3UnitOuter[0][n1]) + for n2 in range(1, elementsCountAlong + 1): + xGC.append(xOuter[n2][0]) + dGC.append(d1Outer[n2][0] if n2 == 1 else d2Outer[n2][0]) + norms.append(d3UnitOuter[n2][0]) + curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 + + # for m1 in range(len(xGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Curvature along rows adjacent to GC - calculate with left and use the same for right + norms = [] + xTest = [] + for n in range(int(len(xOuter[1]) * 0.5)): # d1s + xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM + norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) + for n2 in range(2, elementsCountAlong + 1): # d2s + xTest.append(xOuter[n2][-1]) # KM + norms.append(d3UnitOuter[n2][-1]) + curvatureAlong2Left = findCurvatureAlongLine(xLoop2Left, d2Loop2Left, norms) + + # for m1 in range(len(xTest)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTest[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, norms[m1]) + # nodeIdentifier += 1 + + # Curvature along LC + xTest = [] # KM + norms = [] + for n in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): + xTest.append(xOuter[n][int(len(xOuter[n]) * 0.5)]) + norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) + curvatureAlongLC = findCurvatureAlongLine(xLC[1:], d2LC[1:], norms) + + # Curvature along path from triple point to 6 point junction + xTest = [] # KM + norms = [] + idxToAnnulus = int(elementsCountAroundDuodenum * 0.5 + 1) + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][: idxToAnnulus] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][:idxToAnnulus] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25)): + idx = int(elementsCountAroundOesophagus * 0.25) + 2 + n2 + if idx < (elementsCountAroundOesophagus * 0.5) + 1: + xTest.append(xOuter[idx][idxToAnnulus - 1]) + norms.append(d3UnitOuter[idx][idxToAnnulus - 1]) + xTest += xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ + xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ + d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): + idx = int(elementsCountAroundOesophagus * 0.5) - n2 + xTest.append(xOuter[idx][idxToAnnulus]) + norms.append(d3UnitOuter[idx][idxToAnnulus]) + + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] + + curvatureLoopTripleTo6Pt = findCurvatureAroundLoop(xLoopTripleTo6Pt, dSmoothLoopTripleTo6Pt, norms) + + # Curvature along path from GC to triple point + xTest = [] # KM + norms = [] + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] + + for n2 in range(int(elementsCountAroundOesophagus * 0.25)): + idx = int(elementsCountAroundOesophagus * 0.25 - n2) + xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5)]) + norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5)]) + xTest.append(xOuter[0][0]) + norms.append(d3UnitOuter[0][0]) + for n2 in range(1, int(elementsCountAroundOesophagus * 0.25) + 1): + xTest.append(xOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + norms.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] + norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] + curvatureLoopGCTriplePt = findCurvatureAroundLoop(xLoopGCTriplePt, dSmoothLoopGCTriplePt, norms) + + # Curvature around regular loops + curvatureRegularLoops = [] + for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): + xTest = [] + norms = [] + for n2 in range(elementsCountAlong): + idx = -(1 + n2) + xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + if n1 < int(elementsCountAroundDuodenum * 0.5) - 3: + xTest.append(xOuter[0][(n1 + 1)]) + norms.append(d3UnitOuter[0][n1 + 1]) + else: + xTest.append(xOuter[idx][0]) + norms.append(d3UnitOuter[idx][0]) + for n2 in range(elementsCountAlong): + xTest.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) + norms.append(d3UnitOuter[n2 + 1][int( + len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) + curvatureLoop = findCurvatureAlongLine(xRegularLoops[n1], d2RegularOrderedLoops[n1], norms) + curvatureRegularLoops.append(curvatureLoop) + + # Assemble curvatures + d1Curvature = [] + d2Curvature = [] + countUp = 0 + countDown = 0 + for n2 in range(elementsCountAlong + 1): + d1CurvatureAround = [] + d2CurvatureAround = [] + if n2 == 0: + # print(n2, 'GC') + for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): + d1CurvatureAround.append(curvatureAlongGC[i]) + + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5)]) + for n1 in range(len(xOuter[0]) - 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5)]) + nextIdx = n1 + 1 + + elif n2 == 1: + # print(n2, 'Row 2') + d1CurvatureAround.append(curvatureAlongGC[i + n2]) + xTest = [] + dTest = [] + for n in range(int(len(xOuter[1]) * 0.5) - 1, -1, -1): + d1CurvatureAround.append(curvatureAlong2Left[n]) + d1CurvatureAround += curvatureAlong2Left[:int(len(xOuter[1]) * 0.5)] + xTest = xLoop2Left[:int(len(xOuter[1]) * 0.5)] + dTest = d2Loop2Left[:int(len(xOuter[1]) * 0.5)] + + d2CurvatureAround.append(curvatureRegularLoops[nextIdx][int(len(curvatureRegularLoops[nextIdx]) * 0.5)]) + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + # right point on annulus + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) - n2]) + # left point on annulus + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2]) + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + + elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): + # print(n2, 'Before triple point + triple point') + xAround = xOuter[n2] + if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt + # smooth d1 around - Make into function? + d1Around = d1Outer[n2] + norms = d3UnitOuter[n2] + 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 = norms[int(len(d1Around) * 0.5 + 1):] + norms[: 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):] + + elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation + # take smoothed d1 from dSmoothTripleTo6Pt + d1CurvatureAround = curvatureLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ + curvatureLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5):] + + elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation + # take smoothed d1 from dSmoothGCToTriplePt + d1CurvatureAround = curvatureLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ + curvatureLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5):] + + # GC + d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) + # Row 2 right + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + # Regular up right + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + # Annulus right + d2CurvatureAround.append(curvatureLoopGCTriplePt[ + int(len(curvatureLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + # Annulus left + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2 - ( + 1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + # Regular down left + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + # Row 2 left + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + + elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): + # print(n2, 'Downstream of triple point') + xAround = xOuter[n2] + d1Around = d1Outer[n2] + normsAround = d3UnitOuter[n2] + + # smooth d1 around - Make into function? + if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): + 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(normsAround) * 0.5 + 1):] + normsAround[: int(len(normsAround) * 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):] + + elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring + # take smoothed d1 from dSmoothedTripleTo6Pt + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len( + xAlongAround[junctionIdx]) * 0.5) + endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + d1CurvatureAround = curvatureLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ + curvatureLoopTripleTo6Pt[startLeftIdx: startRightIdx] + + if n2 > int(elementsCountAroundOesophagus * 0.5 + 1): # closed rings beyond 6 point junction + 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(normsAround) * 0.5 + 1):] + normsAround[ : int(len(normsAround) * 0.5 + 1)] + curvature = findCurvatureAroundLoop(xLoop, d1Loop, normsLoop) + # Rearrange to correct order + d1CurvatureAround = curvature[int(len(xLoop) * 0.5) - 1:] + curvature[: int(len(xAround) * 0.5) - 1] + + # GC + d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) + # Row 2 right + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + # Regular up right + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: + # Annulus right + # print('between triple and 6 pt') + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) + if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: + d1CurvatureAround[int(len(d1Outer[n2]) * 0.5)] = curvatureLoopTripleTo6Pt[idx] + else: + d2CurvatureAround.append(curvatureLoopTripleTo6Pt[idx]) + # Annulus left + d2CurvatureAround.append(curvatureLoopTripleTo6Pt[-idx]) + elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: + # print('beyond 6 pt') + # LC + d2CurvatureAround.append(curvatureAlongLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1) - 1]) + # Regular down left + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + # Row 2 left + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + + d1Curvature.append(d1CurvatureAround) + d2Curvature.append(d2CurvatureAround) + + # Create inner nodes + xList = [] + d1List = [] + d2List = [] + d3List = [] + nodeIdx = bodyStartNode + + idxMat = [] + + for n2 in range(elementsCountAlong + 1): + idxThroughWall = [] + for n3 in range(elementsCountThroughWall + 1): + xi3 = 1 / elementsCountThroughWall * n3 + idxAround = [] + for n1 in range(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 * xi3 * d1Curvature[n2][n1] + d1 = [factor * c for c in d1Outer[n2][n1]] + d1List.append(d1) + + # d2 + factor = 1.0 - wallThickness * xi3 * d2Curvature[n2][n1] + d2 = [factor * c for c in d2Outer[n2][n1]] + d2List.append(d2) + + # d3 + d3 = [c * wallThickness / elementsCountThroughWall for c in norm] + d3List.append(d3) + + idxAround.append(nodeIdx) + nodeIdx += 1 + + idxThroughWall.append(idxAround) + idxMat.append(idxThroughWall) + + 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 + + # Create element + mesh = fm.findMeshByDimension(3) + + 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) + result = elementtemplateStandard.defineField(coordinates, -1, eftStandard) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + elementIdentifier = nextElementIdentifier + + for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2): + # Row 1 + if e2 == 0: + startNode = bodyStartNode + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(int(elementsCountAround1) * 2 + 1): + if e1 != elementsCountAround1: + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < elementsCountAround1: + # scaleFactors = [-1.0] + if e1 == 0: + bni11 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + e1 + bni12 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - 1 + else: + bni11 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 + bni12 = bni11 - 1 + bni21 = startNode + elementsAroundThroughWall + 1 + e1 + e3 * elementsCountAround2 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + ( + elementsCountAround2 if e1 == 0 else elementsCountAround1), + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + scaleFactors = [-1.0] + setEftScaleFactorIds(eft1, [1], []) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], + [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS1DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], + [Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS2DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > elementsCountAround1: + if e1 < elementsCountAround1 * 2: + bni11 = startNode + e1 - elementsCountAround1 - 1 + elementsCountAround1 * e3 + bni12 = bni11 + 1 + else: + bni11 = startNode + elementsCountAround1 + e3 * elementsCountAround1 - 1 + bni12 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + ( + elementsCountAround1 if e1 < elementsCountAround1 * 2 else elementsCountAround2), + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Row 2 + elif e2 == 1: + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 2): + if e1 != int(elementsCountAround1 * 0.5 + 1): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + + if e1 < 2: + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + ( + e1 + 1) # % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + e1 + bni22 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + ( + e1 + 1) # % elementsCountAround2 + if e1 == 0: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], 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, [])]) + 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_DS2, [])]) + elif e1 == 1: # Bottom right wedge + nodeIdentifiers = [bni11, bni21, bni22, + bni11 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > 1 and e1 < elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + elif e1 >= elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 2 + bni12 = startNode + e3 * elementsCountAround1 + (e1 - 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + if e1 == elementsCountAround1: # Bottom left wedge + nodeIdentifiers = [bni12, bni21, bni22, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([2, 6]) + elif e1 == elementsCountAround1 + 1: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Additional elements between second and upstream bifurcation ring + elif e2 > 1 and e2 < int(elementsCountAroundOesophagus * 0.25): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1): + if e1 != int(elementsCountAround1 * 0.5): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Upstream bifurcation + elif e2 == int(elementsCountAroundOesophagus * 0.25): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1): + if e1 != int(elementsCountAround1 * 0.5): + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + + if e1 < int(elementsCountAround1 * 0.5) - 1: + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + elif e1 == int(elementsCountAround1 * 0.5) - 1: # right wedge + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == int(elementsCountAround1 * 0.5) + 1: # left wedge + bni21 = bni21 - 1 + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni21 = bni21 - 2 + bni22 = startNode + elementsAroundThroughWall + ( + e1 - 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Downstream bifurcation + elif e2 == int(elementsCountAroundOesophagus * 0.25) + 1: + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 1): + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 + elif e1 == int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( + xOuter[e2 - 1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + + if e1 < int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + elif e1 == int(elementsCountAround1 * 0.5): + bni12 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( + xOuter[e2 - 1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + + if e1 > int(elementsCountAround1 * 0.5): + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 2) % elementsCountAround2 + elementsCountAround2 * e3 + else: + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + (len(xOuter[e2 - 1]) if e1 == int( + elementsCountAround1 * 0.5) + 1 else elementsCountAround1), + bni12 + (len(xOuter[e2 - 1]) if e1 == int( + elementsCountAround1 * 0.5) else elementsCountAround1), + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + if e1 == int(elementsCountAround1 * 0.5): + 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, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == int(elementsCountAround1 * 0.5) + 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, [ ])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Rows between downstream and penultimate ring + for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2, + int(elementsCountAroundOesophagus * 0.5)): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 - 1): + bni11 = startNode + e3 * elementsCountAround1 + e1 + ( + 0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni12 = startNode + e3 * elementsCountAround1 + ( + e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + ( + 0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni22 = startNode + elementsAroundThroughWall + (e1 + (1 if e1 < int( + elementsCountAround1 * 0.5) else 2)) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + element = mesh.createElement(elementIdentifier, elementtemplateStandard) + result = element.setNodesByIdentifier(eftStandard, nodeIdentifiers) + elementIdentifier = elementIdentifier + 1 + + # Penultimate row connecting to annulus and beyond + for e2 in range(int(elementsCountAroundOesophagus * 0.5), elementsCountAlong): + startNode = bodyStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + for e3 in range(elementsCountThroughWall): + for e1 in range( + elementsCountAround1 - (1 if e2 == int(elementsCountAroundOesophagus * 0.5) else 0)): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e2 == int(elementsCountAroundOesophagus * 0.5): + bni11 = startNode + e3 * elementsCountAround1 + e1 + ( + 0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni12 = startNode + e3 * elementsCountAround1 + (e1 + ( + 1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 + # Remap elements next to annulus + if e1 == int(elementsCountAround1 * 0.5) - 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + 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 + else: + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + ( + e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + if e2 == int(elementsCountAroundOesophagus * 0.5) + 1: + if e1 == int(elementsCountAround1 * 0.5) - 1: + 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 == int(elementsCountAround1 * 0.5): + 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) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + + # Annulus + # Assemble endPoints for annulus + endPoints_x = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endPoints_d1 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endPoints_d2 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endNode_Id = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endDerivativesMap = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endProportions = [] + + thicknessIdx = [0, -1] + for nAround in range(elementsCountAroundOesophagus): + for n3 in range(len(thicknessIdx)): + if nAround == 0: + idx = idxMat[nAround][thicknessIdx[n3]][0] + elif nAround <= int(elementsCountAroundOesophagus * 0.25): + idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] + elif int(elementsCountAroundOesophagus * 0.25) < nAround < int(elementsCountAroundOesophagus * 0.5): + idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] + elif nAround == int(elementsCountAroundOesophagus * 0.5): + idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] + elif nAround > int(elementsCountAroundOesophagus * 0.5): + idx = endNode_Id[n3][int(elementsCountAroundOesophagus * 0.5) - (nAround - int(elementsCountAroundOesophagus * 0.5))] + 1 + + endPoints_x[n3][nAround] = xList[idx - bodyStartNode] + endPoints_d1[n3][nAround] = d1List[idx - bodyStartNode] + endPoints_d2[n3][nAround] = d2List[idx - bodyStartNode] + endNode_Id[n3][nAround] = idx + + if n3 == len(thicknessIdx) - 1: # outer layer + endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) + # xCheck = trackSurfaceStomach.evaluateCoordinates(endPosition) # KM + # print(xCheck, endPoints_x[n3][nAround]) # KM + endProportions.append(trackSurfaceStomach.getProportion(endPosition)) + + for nAround in range(elementsCountAroundOesophagus): + if nAround == 0: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + elif nAround == int(elementsCountAroundOesophagus * 0.25): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) + elif 0 < nAround < int(elementsCountAroundOesophagus * 0.5): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) + elif nAround == int(elementsCountAroundOesophagus * 0.5): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) + elif nAround == int(elementsCountAroundOesophagus * 0.75): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) + elif int(elementsCountAroundOesophagus * 0.5) < nAround < elementsCountAroundOesophagus: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + + startProportions = [] + for n in range(elementsCountAroundOesophagus): + startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) + + 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 = elementsCountAnnulus, tracksurface=trackSurfaceStomach, + startProportions = startProportions, endProportions = endProportions, + rescaleStartDerivatives = True, rescaleEndDerivatives = True) + + if trackSurface: + for n2 in range(len(xTrackSurface)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + nodeIdentifier += 1 + + if showCentralPath: + for n2 in range(len(sx)): + node = nodes.createNode(nodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd2[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd1[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, sd3[n2]) + nodeIdentifier += 1 + + fm.endChange() + + annotationGroup = [] + return annotationGroup + + @classmethod + def refineMesh(cls, meshrefinement, options): + """ + Refine source mesh into separate region, with change of basis. + :param meshrefinement: MeshRefinement, which knows source and target region. + :param options: Dict containing options. See getDefaultOptions(). + """ + refineElementsCountAround = options['Refine number of elements around'] + refineElementsCountAlong = options['Refine number of elements along'] + refineElementsCountThroughWall = options['Refine number of elements through wall'] + + meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, + refineElementsCountThroughWall) + return + +def findClosestPositionAndDerivativeOnTrackSurface(x, nx, trackSurface, nxProportion1, elementsCountAlongTrackSurface): + """ + Find the closest position and derivative around the tracksurface of a point sitting near the fundus of stomach. + Use a startPosition to improve the search for nearest position on the track surface as the fundus has a curved + and complex track surface. + + :param x: coordinates of point of interest + :param nx: coordinates of points along curve where point of interest lies. + :param trackSurface: track surface where point sits + :param nxProportion1: proportion around track surface of curve + :param elementsCountAlongTrackSurface: number of elements along track surface + :return: position and derivative of point around track surface + """ + closestIdxOnNx = interp.getNearestPointIndex(nx, x) + closestPositionToPoint = trackSurface.createPositionProportion(nxProportion1, closestIdxOnNx / elementsCountAlongTrackSurface) + xPosition = trackSurface.findNearestPosition(x, closestPositionToPoint) + d = trackSurface.evaluateCoordinates(xPosition, derivatives=True)[1] + + return xPosition, d + +def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, startProportion2, endProportion1, + endProportion2, elementsOut, startDerivative = None, endDerivative = None, + startDerivativeMagnitude = None, endDerivativeMagnitude = None, curveMode = 1): + """ + EDIT + Create smoothly spaced out hermite curve points between two points a and b on the surface, + each defined by their proportions over the surface in directions 1 and 2. + :param trackSurface: track surface + :param startProportion1, startProportion2: proportion of start point in direction around and along track surface + :param endProportion1, endProportion2: proportion of end point in direction around and along track surface + :param elementsOut: number of elements out + :param startDerivative, endDerivative: optional derivative vectors in 3-D world coordinates + to match at the start and end of the curves. If omitted, fits in with other derivative or is + in a straight line from a to b. + :param derivativeMagnitudeStart, derivativeMagnitudeEnd: optional magnitude of derivatives to match at the start and + end of the curves. + :return: coordinates and derivative of sampled points + """ + + mx, md2, md1, md3, mProportions = \ + trackSurface.createHermiteCurvePoints(startProportion1, startProportion2, endProportion1, endProportion2, + elementsOut, startDerivative, endDerivative, curveMode) + + xSampled, dSampled = trackSurface.resampleHermiteCurvePointsSmooth(mx, md2, md1, md3, mProportions, + startDerivativeMagnitude, + endDerivativeMagnitude)[0:2] + return xSampled, dSampled + +def findDerivativeBetweenPoints(v1, v2): + """ + + :param v1: + :param v2: + :return: + """ + 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): + """ + + :param nx: + :param nd: + :param radialVectors: + :return: + """ + curvature = [] + for n in range(len(nx)): + prevIdx = n - 1 if n > 0 else -1 + nextIdx = n + 1 if n < len(nx) - 1 else 0 + kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) + kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) + curvature.append(0.5 * (kappam + kappap)) + + return curvature + +def findCurvatureAlongLine(nx, nd, radialVectors): + """ + + :param nx: + :param nd: + :param radialVectors: + :return: + """ + curvature = [] + for n in range(len(nx)): + if n == 0: + curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) + elif n == len(nx) - 1: + curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) + else: + curvature.append(0.5 * ( + interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + + interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) + + return curvature + From db65d6f831ae32153fca9d68bafd55407f839a86 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Thu, 8 Apr 2021 10:10:38 +1200 Subject: [PATCH 04/38] Spread out elements along more evenly --- .../meshtypes/meshtype_3d_stomach1.py | 2943 +++++++++-------- 1 file changed, 1594 insertions(+), 1349 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 2aa8994d..e15b4d88 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -37,28 +37,6 @@ class MeshType_3d_stomach1(Scaffold_base): direction. """ centralPathDefaultScaffoldPackages = { - 'Generic 1': ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 4 - }, - 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[17.0, 14.0, 0.0], [-17.9, -22.1, 0.0], [7.0, -5.7, 0.0], [-3.3, -6.2, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, 1.4]], - [[0.0, 0.0, 0.0], [-15.4, -5.0, 0.0], [2.8, -8.5, 0.0], [-5.2, 0.6, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, -1.4]], - [[-9.7, 0.7, 0.0], [-8.6, 3.8, 0.0], [-2.8, -6.4, 0.0], [-2.1, 3.7, 0.0], [0.0, 0.0, 7.0], - [0.0, 0.0, -3.3]], - [[-15.9, 6.6, 0.0], [-4.8, 6.8, 0.0], [-2.0, -1.4, 0.0], [-0.3, 2.7, 0.0], [0.0, 0.0, 2.5], - [0.0, 0.0, -1.6]], - [[-19.2, 13.9, 0.0], [-1.7, 7.6, 0.0], [-3.4, -0.8, 0.0], [-2.5, -1.4, 0.0], [0.0, 0.0, 3.5], - [0.0, 0.0, 3.6]]]) - }), 'Human 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, @@ -70,21 +48,21 @@ class MeshType_3d_stomach1(Scaffold_base): 'meshEdits': exnodeStringFromNodeValues( [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], [ - [[54.2, 76.2, 0.0], [9.4, -43.5, 0.0], [29.0, 0.8, 0.0], [15.9, -22.3, 0.0], [0.0, 0.0, 40.7], - [0.0, 0.0, 1.4]], - [[51.1, 30.7, 0.0], [-18.5, -35.9, 0.0], [33.9, -17.5, 0.0], [-6.1, -14.3, 0.0], [0.0, 0.0, 41.4], - [0.0, 0.0, 0.0]], - [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [19.0, -28.6, 0.0], [-16.3, -6.6, 0.0], [0.0, 0.0, 40.9], + [[70.8, 72.3, 0.0], [-15.1, -43.8, 0.0], [37.3, -18.7, 0.0], [2.2, 7.2, 0.0], [0.0, 0.0, 38.7], + [0.0, 0.0, 4.5]], + [[51.1, 30.7, 0.0], [-21.4, -33.7, 0.0], [33.9, -17.5, 0.0], [-9.0, -4.7, 0.0], [0.0, 0.0, 41.4], + [0.0, 0.0, 0.9]], + [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [20.5, -27.0, 0.0], [-16.5, -6.7, 0.0], [0.0, 0.0, 40.9], [0.0, 0.0, -5.0]], - [[-0.3, -5.8, 0.0], [-29.4, -1.4, 0.0], [1.5, -31.5, 0.0], [-13.5, 4.5, 0.0], [0.0, 0.0, 32.3], + [[-0.3, -5.8, 0.0], [-28.0, -2.6, 0.0], [1.5, -31.5, 0.0], [-14.2, 3.8, 0.0], [0.0, 0.0, 32.3], [0.0, 0.0, -9.4]], - [[-26.5, -2.9, 0.0], [-22.4, 9.4, 0.0], [-8.5, -20.3, 0.0], [-8.1, 10.9, 0.0], [0.0, 0.0, 22.1], + [[-26.5, -2.9, 0.0], [-20.6, 8.0, 0.0], [-8.5, -20.3, 0.0], [-8.1, 10.9, 0.0], [0.0, 0.0, 22.1], [0.0, 0.0, -6.8]], - [[-40.6, 7.4, 0.0], [-9.9, 11.2, 0.0], [-15.3, -9.6, 0.0], [-0.1, 8.5, 0.0], [0.0, 0.0, 17.6], + [[-40.6, 7.4, 0.0], [-11.0, 12.5, 0.0], [-15.3, -9.6, 0.0], [-0.1, 8.5, 0.0], [0.0, 0.0, 17.6], [0.0, 0.0, -5.9]], - [[-48.1, 21.0, 0.0], [-5.7, 14.7, 0.0], [-9.4, -3.0, 0.2], [2.3, 3.1, 0.0], [0.0, 0.0, 10.5], + [[-48.1, 21.0, 0.0], [-6.4, 15.7, 0.0], [-9.4, -3.0, 0.0], [2.3, 3.1, 0.0], [0.0, 0.0, 10.5], [0.0, 0.0, -3.1]], - [[-52.9, 38.6, 0.0], [-5.0, 19.8, 0.0], [-11.3, -4.0, 0.0], [-6.1, -5.1, 0.0], [0.0, 0.0, 12.0], + [[-52.9, 38.6, 0.0], [-3.2, 19.3, 0.0], [-11.3, -4.0, 0.0], [-6.1, -5.1, 0.0], [0.0, 0.0, 12.0], [0.0, 0.0, 6.1]]]) }), @@ -99,7 +77,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'meshEdits': exnodeStringFromNodeValues( [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], [ - [[10.7, 13.3, 0.0], [3.3, -16.0, 0.0], [8.7, -1.4, 0.0], [0.5, -3.7, 0.0], [0.0, 0.0, 7.4], + [[12.4, 11.9, 0.0], [2.3, -12.3, 0.0], [8.7, -1.4, 0.0], [0.5, -3.7, 0.0], [0.0, 0.0, 7.4], [0.0, 0.0, 1.6]], [[9.5, -0.2, 0.0], [-6.0, -9.6, 0.0], [6.6, -5.1, 0.0], [-3.9, -4.3, 0.0], [0.0, 0.0, 8.5], [0.0, 0.0, 0.7]], @@ -125,16 +103,16 @@ class MeshType_3d_stomach1(Scaffold_base): 'meshEdits': exnodeStringFromNodeValues( [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], [ - [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.0, 1.2], [0.0, -0.7, 9.0], - [0.0, 1.2, 1.2]], - [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -8.9, -0.1], [0.0, 1.2, 0.0], [0.0, -0.1, 9.0], - [0.0, 0.0, -1.3]], - [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -7.0, -0.4], [0.0, 3.4, 0.0], [0.0, -0.4, 7.0], - [0.0, 0.0, -3.4]], - [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.7, 0.2], [0.0, -0.1, 2.5], - [0.0, 0.2, -1.7]], - [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.1, 0.2], [0.0, 0.1, 3.5], - [0.0, 0.2, 3.7]]]) + [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.5, 1.2], [0.0, -0.7, 9.0], + [0.0, 1.2, 1.5]], + [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -9.0, -0.1], [0.0, 1.4, 0.0], [0.0, -0.1, 9.0], + [0.0, 0.0, -1.4]], + [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -6.8, -0.4], [0.0, 3.5, 0.0], [0.0, -0.4, 6.8], + [0.0, 0.0, -3.5]], + [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.6, 0.2], [0.0, -0.1, 2.4], + [0.0, 0.2, -1.6]], + [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.0, 0.2], [0.0, 0.1, 3.6], + [0.0, 0.2, 4.0]]]) }), } @@ -149,7 +127,7 @@ class MeshType_3d_stomach1(Scaffold_base): 'Unit scale': 1.0, 'Outlet': False, 'Ostium diameter': 25.0, - 'Ostium length': 10.0, + 'Ostium length': 15.0, 'Ostium wall thickness': 5.0, 'Ostium inter-vessel distance': 0.0, 'Ostium inter-vessel height': 0.0, @@ -207,10 +185,9 @@ def getName(): def getParameterSetNames(): return [ 'Default', - 'Generic 1', 'Human 1', 'Rat 1', - 'Stomach coordinates',] + 'Stomach coordinates'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): @@ -231,13 +208,15 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Central path': copy.deepcopy(centralPathOption), 'Number of elements around oesophagus': 8, 'Number of elements around duodenum': 12, - 'Number of elements along': 8, + 'Number of elements between annulus and duodenum': 6, 'Number of elements through wall': 1, + 'Number of radial elements in annulus': 1, # KM 'Wall thickness': 5.0, + 'Limiting ridge': False, + 'Fundus end position along factor': 0.3, 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), - 'Gastro-oesophagal junction position along factor': 0.25, + 'Gastro-oesophagal junction position along factor': 0.35, 'Annulus derivative factor': 1.0, - 'Number of radial elements in annulus': 1, # KM 'Show track surface': False, # KM 'Make stomach': True, # KM 'Show central path': False, # KM @@ -248,9 +227,19 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } - if ('Generic 1' or 'Rat 1' or 'Stomach coordinates') in parameterSetName: + if 'Rat 1' in parameterSetName: + options['Number of elements around oesophagus'] = 12 + options['Number of elements around duodenum'] = 14 + options['Number of elements between annulus and duodenum'] = 2 options['Wall thickness'] = 0.5 options['Gastro-oesophagal junction position along factor'] = 0.55 + options['Annulus derivative factor'] = 0.2 + options['Limiting ridge'] = True + options['Fundus end position along factor'] = 0.5 + elif 'Stomach coordinates' in parameterSetName: + options['Wall thickness'] = 0.5 + options['Gastro-oesophagal junction position along factor'] = 0.45 + options['Fundus end position along factor'] = 0.45 cls.updateSubScaffoldOptions(options) return options @@ -261,13 +250,15 @@ def getOrderedOptionNames(): 'Central path', 'Number of elements around oesophagus', 'Number of elements around duodenum', - 'Number of elements along', + 'Number of elements between annulus and duodenum', 'Number of elements through wall', + 'Number of radial elements in annulus', 'Wall thickness', + 'Limiting ridge', + 'Fundus end position along factor', 'Gastro-oesophagal junction', 'Gastro-oesophagal junction position along factor', 'Annulus derivative factor', - 'Number of radial elements in annulus', 'Show track surface', 'Make stomach', 'Show central path', @@ -331,15 +322,20 @@ def checkOptions(cls, options): options['Number of elements around oesophagus'] = options['Number of elements around oesophagus'] // 4 * 4 if options['Number of elements around duodenum'] < 12: options['Number of elements around duodenum'] = 12 + if options['Number of elements between annulus and duodenum'] < 2: + options['Number of elements between annulus and duodenum'] = 2 for key in [ 'Number of elements around oesophagus', 'Number of elements around duodenum']: if options[key] % 2: options[key] += 1 - if options['Number of elements along'] < 8: - options['Number of elements along'] = 8 - if options['Annulus derivative factor'] < 0: - options['Annulus derivative factor'] = 0.0 + # if options['Number of elements along'] < 8: + # options['Number of elements along'] = 8 + for key in [ + 'Fundus end position along factor', + 'Annulus derivative factor']: + if options[key] < 0: + options[key] = 0.0 for key in [ 'Number of elements through wall', 'Refine number of elements around', @@ -370,9 +366,9 @@ def generateBaseMesh(cls, region, options): """ cls.updateSubScaffoldOptions(options) centralPath = options['Central path'] - elementsCountAroundOesophagus = options['Number of elements around oesophagus'] - elementsCountAroundDuodenum = options['Number of elements around duodenum'] - elementsCountAlong = options['Number of elements along'] + elementsCountAroundOeso = options['Number of elements around oesophagus'] + elementsCountAroundDuod = options['Number of elements around duodenum'] + elementsAlongAnnulusToDuod = options['Number of elements between annulus and duodenum'] elementsCountThroughWall = options['Number of elements through wall'] wallThickness = options['Wall thickness'] useCrossDerivatives = options['Use cross derivatives'] @@ -381,15 +377,24 @@ def generateBaseMesh(cls, region, options): GOJPositionAlongFactor = options['Gastro-oesophagal junction position along factor'] GOJOptions = options['Gastro-oesophagal junction'] GOJSettings = GOJOptions.getScaffoldSettings() - oesophagusDiameter = GOJSettings['Ostium diameter'] - annulusDerivativeFactor = options['Annulus derivative factor'] + useLimitingRidge = options['Limiting ridge'] + fundusEndPositionAlongFactor = options['Fundus end position along factor'] elementsCountAnnulus = options['Number of radial elements in annulus'] + annulusDerivativeFactor = options['Annulus derivative factor'] - trackSurface = options['Show track surface'] + showTrackSurface = options['Show track surface'] makeStomach = options['Make stomach'] showCentralPath = options['Show central path'] elementsCountAlongTrackSurface = 20 + elementsAroundHalfOeso = int(elementsCountAroundOeso * 0.5) + elementsAroundQuarterOeso = int(elementsCountAroundOeso * 0.25) + elementsAroundHalfDuod = int(elementsCountAroundDuod * 0.5) + + # if useLimitingRidge: # Rat / mouse + # annulusDerivativeFactor = 0.2 + # else: + # annulusDerivativeFactor = 1.0 ############################################################################################ zero = [0.0, 0.0, 0.0] @@ -464,8 +469,8 @@ def generateBaseMesh(cls, region, options): d2Apex = [] d2 = sd2[0] - for n1 in range(elementsCountAroundDuodenum): - rotAngle = n1 * 2.0 * math.pi / elementsCountAroundDuodenum + for n1 in range(elementsCountAroundDuod): + rotAngle = n1 * 2.0 * math.pi / elementsCountAroundDuod rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) # vector.normalise(sd1[0]) 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)] @@ -474,14 +479,14 @@ def generateBaseMesh(cls, region, options): xEllipses = [] d1Ellipses = [] for n in range(elementsAlongFundus + 1, len(sx)): - px, pd1 = createEllipsePoints(sx[n], 2 * math.pi, sd2[n], sd3[n], elementsCountAroundDuodenum, + px, pd1 = createEllipsePoints(sx[n], 2 * math.pi, sd2[n], sd3[n], elementsCountAroundDuod, startRadians=0.0) xEllipses.append(px) d1Ellipses.append(pd1) # Find d2 d2Raw = [] - for n1 in range(elementsCountAroundDuodenum): + for n1 in range(elementsCountAroundDuod): xAlong = [] d2Along = [] for n2 in range(len(xEllipses) - 1): @@ -499,13 +504,13 @@ def generateBaseMesh(cls, region, options): d2Ellipses = [] for n2 in range(len(xEllipses)): d2Around = [] - for n1 in range(elementsCountAroundDuodenum): + for n1 in range(elementsCountAroundDuod): d2 = d2Raw[n1][n2] d2Around.append(d2) d2Ellipses.append(d2Around) # for n2 in range(len(xEllipses)): - # for n1 in range(elementsCountAroundDuodenum): + # for n1 in range(elementsCountAroundDuod): # node = nodes.createNode(nodeIdentifier, nodetemplate) # cache.setNode(node) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xEllipses[n2][n1]) @@ -514,21 +519,12 @@ def generateBaseMesh(cls, region, options): # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) # nodeIdentifier += 1 - # for n1 in range(len(sx)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd1[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd2[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Check[n1]) - # nodeIdentifier += 1 - # Merge fundus and body - xAll = [[sx[0]] * elementsCountAroundDuodenum] + xEllipses + xAll = [[sx[0]] * elementsCountAroundDuod] + xEllipses d2All = [d2Apex] + d2Ellipses # for n2 in range(len(xAll)): - # for n1 in range(elementsCountAroundDuodenum): + # for n1 in range(elementsCountAroundDuod): # node = nodes.createNode(nodeIdentifier, nodetemplate) # cache.setNode(node) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAll[n2][n1]) @@ -540,7 +536,7 @@ def generateBaseMesh(cls, region, options): # Spread out elements xRaw = [] d2Raw = [] - for n1 in range(elementsCountAroundDuodenum): + for n1 in range(elementsCountAroundDuod): xAlong = [] d2Along = [] for n2 in range(len(xAll)): @@ -561,7 +557,7 @@ def generateBaseMesh(cls, region, options): xAround = [] d1Around = [] d2Around = [] - for n1 in range(elementsCountAroundDuodenum): + for n1 in range(elementsCountAroundDuod): x = xRaw[n1][n2] d2 = d2Raw[n1][n2] xAround.append(x) @@ -570,11 +566,11 @@ def generateBaseMesh(cls, region, options): # Calculate d1 if n2 > 0: v1 = xRaw[n1][n2] - v2 = xRaw[n1 + 1 if n1 < elementsCountAroundDuodenum - 2 else 0][n2] + v2 = xRaw[n1 + 1 if n1 < elementsCountAroundDuod - 2 else 0][n2] d1 = findDerivativeBetweenPoints(v1, v2) d1Around.append(d1) else: - d1Around.append(d2Raw[int(elementsCountAroundDuodenum * 0.75)][0]) + d1Around.append(d2Raw[int(elementsCountAroundDuod * 0.75)][0]) if n2 > 0: d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) @@ -586,7 +582,7 @@ def generateBaseMesh(cls, region, options): d2SampledAll.append(d2Around) # for n2 in range(elementsCountAlongTrackSurface + 1): - # for n1 in range(elementsCountAroundDuodenum): + # for n1 in range(elementsCountAroundDuod): # node = nodes.createNode(nodeIdentifier, nodetemplate) # cache.setNode(node) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][n1]) @@ -600,1338 +596,1567 @@ def generateBaseMesh(cls, region, options): d1TrackSurface = [] d2TrackSurface = [] for n2 in range(elementsCountAlongTrackSurface + 1): - for n1 in range(elementsCountAroundDuodenum): + for n1 in range(elementsCountAroundDuod): xTrackSurface.append(xSampledAll[n2][n1]) d1TrackSurface.append(d1SampledAll[n2][n1]) d2TrackSurface.append(d2SampledAll[n2][n1]) - trackSurfaceStomach = TrackSurface(elementsCountAroundDuodenum, elementsCountAlongTrackSurface, + trackSurfaceStomach = TrackSurface(elementsCountAroundDuod, elementsCountAlongTrackSurface, xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) - if makeStomach: - # Set up gastro-oesophagal junction - GOJSettings['Number of elements around ostium'] = elementsCountAroundOesophagus - GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) - xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) - axis1 = d1Centre + # Set up gastro-oesophagal junction + GOJSettings['Number of elements around ostium'] = elementsCountAroundOeso + GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) + xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) + axis1 = d1Centre - # fm = region.getFieldmodule() - mesh = fm.findMeshByDimension(3) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - - nextNodeIdentifier = nodeIdentifier - nextElementIdentifier = elementIdentifier - nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, - nextNodeIdentifier, nextElementIdentifier) - bodyStartNode = nextNodeIdentifier - - # From oesophagus to duodenum along lesser curvature (LC) - elementsOesoToDuodLC = elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) # CHECK - startProportion1, startProportion2 = trackSurfaceStomach.getProportion( - o1_Positions[int(elementsCountAroundOesophagus * 0.5)]) - d1Start = o1_d2[1][int(elementsCountAroundOesophagus * 0.5)] - - xOesoToDuodLC, d2OesoToDuodLC = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, 0.5, 1.0, - elementsOesoToDuodLC, startDerivative=d1Start, - startDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude(d1Start)) - - # From oesophagus to duodenum along greater curvature (GC) - xAlongGC = [] - d2AlongGC = [] - xAlongGC.append(o1_x[1][0]) - d2AlongGC.append(o1_d2[1][0]) - - oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] - elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) - - # From oesophagus to fundus apex - arcLengthOesoApex = 0.0 - for n2 in range(elementsAlongUpstreamOfOeso): - nAlong = elementsAlongUpstreamOfOeso - n2 - v1 = xSampledAll[nAlong][int(elementsCountAroundDuodenum * 0.5)] - v2 = xSampledAll[nAlong - 1][int(elementsCountAroundDuodenum * 0.5)] - d = [v2[c] - v1[c] for c in range(3)] - arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) - arcLengthOesoApex += arcLengthAround - d2 = [c * arcLengthAround for c in vector.normalise(d)] - xAlongGC.append(v1) - d2AlongGC.append(d2) - - # From fundus apex to duodenum - for n2 in range(len(xSampledAll)): - xAlongGC.append(xSampledAll[n2][0]) - d2AlongGC.append(d2SampledAll[n2][0]) - - elementsOesoToDuodGC = elementsCountAlong + int(elementsCountAroundDuodenum * 0.5) - 2 # Check - xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurvesSmooth(xAlongGC, d2AlongGC, elementsOesoToDuodGC, - derivativeMagnitudeStart=annulusDerivativeFactor * vector.magnitude( - d2AlongGC[0]))[0:2] - # xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurves(xAlongGC, d2AlongGC, elementsOesoToDuodGC, - # addLengthStart= vector.magnitude( - # d2AlongGC[0]), lengthFractionStart=0.5)[0:2] - - d2OesoToDuodGC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2OesoToDuodGC) - # curvature - DONE + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - arcLength = 0.0 - for e in range(len(xOesoToDuodGC) - 1): - arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], - xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) - if arcLength > arcLengthOesoApex: - nodesCountFromOesoToApex = e + 2 - break + nextNodeIdentifier = nodeIdentifier + nextElementIdentifier = elementIdentifier + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, + nextNodeIdentifier, nextElementIdentifier) + + bodyStartNode = nextNodeIdentifier + nodeIdentifier = nextNodeIdentifier + + fundusEndPosition = trackSurfaceStomach.createPositionProportion(0.0, fundusEndPositionAlongFactor) + xFundusEnd, d1FundusEnd, d2FundusEnd = trackSurfaceStomach.evaluateCoordinates(fundusEndPosition, derivatives=True) + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFundusEnd) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2FundusEnd) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1FundusEnd) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + elementsAlongFundus = elementsAroundQuarterOeso + (0 if useLimitingRidge else 1) + elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfOeso + 1 + + # From fundus end to duodenum + elementsAlongFundusEndToDuod = elementsCountAlong - elementsAlongFundus + xAlongDownFundus = [] + d2AlongDownFundus = [] + xAlongDownFundus.append(xFundusEnd) + d2AlongDownFundus.append(d2FundusEnd) + startIdx = fundusEndPositionAlongFactor*elementsCountAlongTrackSurface + startIdx = math.ceil(startIdx) + (1 if startIdx - math.ceil(startIdx) == 0 else 0) + for n2 in range(startIdx, len(xSampledAll)): + xAlongDownFundus.append(xSampledAll[n2][0]) + d2AlongDownFundus.append(d2SampledAll[n2][0]) + + # From oesophagus to fundus end + elementsAlongGCFromOesoToFundusEnd = elementsAroundHalfDuod - 2 + elementsAlongFundus + xAlongUpFundus = [] + d2AlongUpFundus = [] + xAlongUpFundus.append(o1_x[1][0]) + d2AlongUpFundus.append([annulusDerivativeFactor * c for c in o1_d2[1][0]]) + + # From oesophagus to fundus apex + oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] + elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) + arcLengthOesoApex = 0.0 + for n2 in range(elementsAlongUpstreamOfOeso): + nAlong = elementsAlongUpstreamOfOeso - n2 + v1 = xSampledAll[nAlong][elementsAroundHalfDuod] + v2 = xSampledAll[nAlong - 1][elementsAroundHalfDuod] + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + arcLengthOesoApex += arcLengthAround + d2 = [c * arcLengthAround for c in vector.normalise(d)] + xAlongUpFundus.append(v1) + d2AlongUpFundus.append(d2) + + # From fundus apex to end + for n2 in range(startIdx - (0 if useLimitingRidge else 1)): + xAlongUpFundus.append(xSampledAll[n2][0]) + d2AlongUpFundus.append(d2SampledAll[n2][0]) + + if useLimitingRidge: + # Sample from oesophagus to fundus end + # xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ + # interp.sampleCubicHermiteCurves(xAlongUpFundus, d2AlongUpFundus, elementsAlongGCFromOesoToFundusEnd, + # addLengthStart=0.5 * vector.magnitude(d2AlongUpFundus[0]), + # lengthFractionStart=0.5, arcLengthDerivatives=True)[0:2] + xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ + interp.sampleCubicHermiteCurvesSmooth(xAlongUpFundus, d2AlongUpFundus, + elementsAlongGCFromOesoToFundusEnd, + derivativeMagnitudeStart=vector.magnitude(d2AlongUpFundus[0]))[0:2] + + # Sample from limiting ridge to duodenum + xAlongDownFundus[0] = xAlongGCOesoToFundusEnd[-1] + d2AlongDownFundus[0] = d2AlongGCOesoToFundusEnd[-1] + xAlongGCFundusEndToDuod, d2AlongGCFundusEndToDuod = \ + interp.sampleCubicHermiteCurves(xAlongDownFundus, d2AlongDownFundus, elementsAlongFundusEndToDuod, + addLengthStart=0.5 * vector.magnitude(d2AlongDownFundus[0]), + lengthFractionStart=0.5, arcLengthDerivatives=True)[0:2] - nodeIdentifier = nextNodeIdentifier + else: + # Sample from end of fundus to duodenum + xAlongGCFundusEndToDuod, d2AlongGCFundusEndToDuod = \ + interp.sampleCubicHermiteCurves(xAlongDownFundus, d2AlongDownFundus, elementsAlongFundusEndToDuod, + arcLengthDerivatives=True)[0:2] + + # Sample from ostium to end of fundus + # Provide first element size so that we can transit + xAlongUpFundus[-1] = xAlongGCFundusEndToDuod[0] + d2AlongUpFundus[-1] = d2AlongGCFundusEndToDuod[0] + # xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ + # interp.sampleCubicHermiteCurves(xAlongUpFundus, d2AlongUpFundus, elementsAlongGCFromOesoToFundusEnd, + # addLengthStart=0.5* vector.magnitude(d2AlongUpFundus[0]), + # lengthFractionStart = 0.5, addLengthEnd=0.5 * vector.magnitude(d2AlongUpFundus[-1]), + # lengthFractionEnd=0.5, arcLengthDerivatives=True)[0:2] + xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ + interp.sampleCubicHermiteCurvesSmooth(xAlongUpFundus, d2AlongUpFundus, elementsAlongGCFromOesoToFundusEnd, + derivativeMagnitudeStart= vector.magnitude(d2AlongUpFundus[0]), + derivativeMagnitudeEnd = vector.magnitude(d2AlongUpFundus[-1]))[0:2] + + xOesoToDuodGC = xAlongGCOesoToFundusEnd[:-1] + xAlongGCFundusEndToDuod + d2OesoToDuodGC = d2AlongGCOesoToFundusEnd[:-1] + d2AlongGCFundusEndToDuod + + # for n2 in range(len(xAlongUpFundus)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongUpFundus[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2AlongUpFundus[n2]) + # nodeIdentifier += 1 + # + # for n2 in range(len(xAlongGCFundusEndToDuod)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongGCFundusEndToDuod[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AlongGCFundusEndToDuod[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 - # for n2 in range(len(xOesoToDuodLC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + # for n2 in range(len(xOesoToDuodGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 - # for n2 in range(len(xOesoToDuodGC)): + arcLength = 0.0 + for e in range(len(xOesoToDuodGC) - 1): + arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], + xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) + if arcLength > arcLengthOesoApex: + nodesCountFromOesoToApex = e + 2 + break + + ptsOnTrackSurfaceGC = [] + xAlongAround = [] + d1AlongAround = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) + + # Rings adjacent to triple point (excluding triple point rings) to 6 point junction + # First half + for n2 in range(elementsAroundQuarterOeso + 1, elementsAroundHalfOeso): + ostiumIdx = n2 + GCIdx = elementsAroundHalfDuod - 1 + n2 + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + + endPosition = o1_Positions[ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) + d2 = o1_d2[1][ostiumIdx] + d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, + endProportion2, elementsAroundHalfDuod + 1, + startDerivative=d1GC, endDerivative=d1EndOstium, + endDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude(d2)) + + # for n2 in range(len(xFirstHalf)): # node = nodes.createNode(nodeIdentifier, nodetemplate) # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstHalf[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1FirstHalf[n2]) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) # nodeIdentifier += 1 - # Spread out elements around for each egroup around - # Elements around oesophagus - # Decide where to put extra elements if elementsOesophagus/2 is odd number. - # Right now, extra elements go downstream of bifurcation - # For even numbers, we split elements at bifurcation - - ptsOnTrackSurfaceGC = [] - xAlongAround = [] - d1AlongAround = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) - - # Ring adjacent to LC - # First half - for n2 in range(int(elementsCountAroundOesophagus * 0.25 + 1), int(elementsCountAroundOesophagus * 0.5)): - ostiumIdx = n2 - GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + n2 - GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) - GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) - - endPosition = o1_Positions[ostiumIdx] - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) - d2 = o1_d2[1][ostiumIdx] - d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] - - xFirstHalf, d1FirstHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, - endProportion2, int(0.5 * elementsCountAroundDuodenum + 1), - startDerivative=d1GC, endDerivative= d1EndOstium, - endDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1EndOstium)) - - # for n2 in range(len(xFirstHalf)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstHalf[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1FirstHalf[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + # Second half + ostiumIdx2 = -n2 + startPosition = o1_Positions[ostiumIdx2] + d1StartOstium = o1_d2[1][ostiumIdx2] + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] + + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, + GCProportion2, elementsAroundHalfDuod + 1, startDerivative=d1StartOstium, + endDerivative=d1GC, + startDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude( + d1StartOstium)) + + xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] + d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # Elements downstream of 6 pt junction + xTests = [] # KM + for idx in range(-(elementsCountAlong - elementsAroundHalfOeso - 1), 0): + # Search for point on central path and use that to make ellipse + xStart = xOesoToDuodGC[idx] + startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], + ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + startProportion2 = trackSurfaceStomach.getProportion(startPosition)[1] + if 0.0 < startProportion2 < 1.0: + closestIdxOnCentralPath = interp.getNearestPointIndex(sx, xStart) + if 0 < closestIdxOnCentralPath < len(sx) - 1: + # Check if xStart is closer to upstream or downstream of closestIdx + xOnGCPrevElem = [sx[closestIdxOnCentralPath - 1][c] + sd2[closestIdxOnCentralPath - 1][c] for c in range(3)] + distBetweenXOnGCPrevElem = vector.magnitude([xStart[c] - xOnGCPrevElem[c] for c in range(3)]) + xOnGCNextElem = [sx[closestIdxOnCentralPath + 1][c] + sd2[closestIdxOnCentralPath + 1][c] for c in range(3)] + distBetweenXOnGCNextElem = vector.magnitude([xStart[c] - xOnGCNextElem[c] for c in range(3)]) + eiLowerLimit = closestIdxOnCentralPath - (1 if distBetweenXOnGCNextElem > distBetweenXOnGCPrevElem else 0) + + elif closestIdxOnCentralPath == len(sx) - 1: + eiLowerLimit = closestIdxOnCentralPath - 1 + + elif closestIdxOnCentralPath == 0: + eiLowerLimit = closestIdxOnCentralPath + + xiLowerLimit = 0.0 + xiUpperLimit = 1.0 + xOnGCLowerLimit = [sx[eiLowerLimit][c] + sd2[eiLowerLimit][c] for c in range(3)] + xOnGCUpperLimit = [sx[eiLowerLimit + 1][c] + sd2[eiLowerLimit + 1][c] for c in range(3)] + distBetweenXAndXStartPrev = vector.magnitude([xStart[c] - xOnGCLowerLimit[c] for c in range(3)]) + + # Search for point on central path which is orthogonal to xStart + tol = 1e-8 + xLowerLimit = sx[eiLowerLimit] + d1LowerLimit = sd1[eiLowerLimit] + d2LowerLimit = sd2[eiLowerLimit] + d12LowerLimit = sd12[eiLowerLimit] + xUpperLimit = sx[eiLowerLimit + 1] + d1UpperLimit = sd1[eiLowerLimit + 1] + d2UpperLimit = sd2[eiLowerLimit + 1] + d12UpperLimit = sd12[eiLowerLimit + 1] + + for iter in range(100): + xiGuess = 0.5 * (xiLowerLimit + xiUpperLimit) + x = interp.interpolateCubicHermite(xLowerLimit, d1LowerLimit, xUpperLimit, d1UpperLimit, xiGuess) + d2 = interp.interpolateCubicHermite(d2LowerLimit, d12LowerLimit, d2UpperLimit, d12UpperLimit, xiGuess) + xGuess = [x[c] + d2[c] for c in range(3)] + distBetweenXAndXStart = vector.magnitude([xStart[c] - xGuess[c] for c in range(3)]) + distBetweenXOnGCLowerLimitAndXStart = vector.magnitude([xStart[c] - xOnGCLowerLimit[c] for c in range(3)]) + distBetweenXOnGCUpperLimitAndXStart = vector.magnitude([xStart[c] - xOnGCUpperLimit[c] for c in range(3)]) + + if abs(distBetweenXAndXStart - distBetweenXAndXStartPrev) < tol: + xProjection = x + xiProjection = xiGuess + break + elif distBetweenXOnGCLowerLimitAndXStart < distBetweenXOnGCUpperLimitAndXStart: + xiUpperLimit = xiGuess + xOnGCUpperLimit = xGuess + distBetweenXAndXStartPrev = distBetweenXAndXStart + else: + xiLowerLimit = xiGuess + xOnGCLowerLimit = xGuess + distBetweenXAndXStartPrev = distBetweenXAndXStart + + if iter > 98: + print('Search for projection on central path - Max iters reached:', iter) + + axis1 = interp.interpolateCubicHermite(sd2[eiLowerLimit], sd12[eiLowerLimit], + sd2[eiLowerLimit + 1], sd12[eiLowerLimit + 1], xiProjection) + axis2 = interp.interpolateCubicHermite(sd3[eiLowerLimit], sd13[eiLowerLimit], + sd3[eiLowerLimit + 1], sd13[eiLowerLimit + 1], xiProjection) + xAround, d1Around = createEllipsePoints(xProjection, 2 * math.pi, axis1, axis2, elementsCountAroundDuod, startRadians=0.0) + + elif startProportion2 == 0: + xAround, d1Around = createEllipsePoints(sx[0], 2 * math.pi, sd2[0], sd3[0], + elementsCountAroundDuod, startRadians=0.0) + elif startProportion2 == 1.0: + xAround, d1Around = createEllipsePoints(sx[-1], 2 * math.pi, sd2[-1], sd3[-1], + elementsCountAroundDuod, startRadians=0.0) + + d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) + + # Average adjacent ring with first downstream ring that is not adjacent to oesophagus + if idx == -(elementsCountAlong - elementsAroundHalfOeso - 1): + xAve = [] + dAve = [] + xAve.append(xOesoToDuodGC[idx - 1]) + + for n in range(1, elementsCountAroundDuod): + startPosition = trackSurfaceStomach.findNearestPosition(xAround[n]) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + if n == elementsAroundHalfDuod: # Point to search for 6 point junction - Work here if need to move 6pt junction closer to annulus + endPosition = o1_Positions[elementsAroundHalfOeso] + else: + endPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[-1][n + (0 if n < elementsAroundHalfDuod else 1)]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + xSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, endProportion1, endProportion2, 2)[0] + #endDerivativeMagnitude = annulusDerivativeFactor * vector.magnitude(o1_d2[1][elementsAroundHalfOeso]))[0] + + xAve.append(xSampled[1]) + + for n in range(len(xAve)): + v1 = xAve[n] + v2 = xAve[(n + 1) % len(xAve)] + d1 = findDerivativeBetweenPoints(v1, v2) + dAve.append(d1) + dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) - # Second half - ostiumIdx2 = -n2 - startPosition = o1_Positions[ostiumIdx2] - d1StartOstium = o1_d2[1][ostiumIdx2] - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] - - xSecondHalf, d1SecondHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, - GCProportion2, int(0.5 * elementsCountAroundDuodenum + 1), - startDerivative=d1StartOstium, endDerivative=d1GC, - startDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1StartOstium)) - - xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] - d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] - - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - - # Elements downstream of oesophagus - for idx in range(-(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1), 0): - startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], - ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, - elementsCountAlongTrackSurface) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - - endPosition = trackSurfaceStomach.findNearestPosition(xOesoToDuodLC[idx]) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - d1End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] - - xFirstHalf, d1FirstHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, startProportion2, endProportion1, - endProportion2, int(0.5 * elementsCountAroundDuodenum), - startDerivative=d1Start, endDerivative=d1End) - - xSecondHalf, d1SecondHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, endProportion1, endProportion2, 1.0, - startProportion2, int(0.5 * elementsCountAroundDuodenum), - startDerivative=d1End, endDerivative=d1Start) - - # Average adjacent ring with first downstream ring that is not adjacent to oesophagus - if idx == -(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1): - xAve = [] - dAve = [] - xAve.append(xOesoToDuodGC[idx - 1]) - for n in range(1, int(elementsCountAroundDuodenum * 0.5)): - # nx = [xAround[n], xFirstHalf[n]] - # d = [xFirstHalf[n][c] - xAround[n][c] for c in range(3)] - # nd1 = [d, d] - # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] - # xAve.append(xSampled[1]) - - startPosition = trackSurfaceStomach.findNearestPosition(xAround[n]) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - endPosition = trackSurfaceStomach.findNearestPosition(xFirstHalf[n]) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - xSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, endProportion1, endProportion2, 2)[0] - xAve.append(xSampled[1]) - - xAve.append(xOesoToDuodLC[idx - 1]) - - for n in range(1, int(elementsCountAroundDuodenum * 0.5)): - # nx = [xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1], xSecondHalf[n]] - # d = [xSecondHalf[n][c] - xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1][c] for c in range(3)] - # nd1 = [d, d] - # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] - # xAve.append(xSampled[1]) - - startPosition = trackSurfaceStomach.findNearestPosition(xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1]) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - endPosition = trackSurfaceStomach.findNearestPosition(xSecondHalf[n]) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - xSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, endProportion1, endProportion2, 2)[0] - xAve.append(xSampled[1]) - - for n in range(len(xAve)): - v1 = xAve[n] - v2 = xAve[(n+1) % len(xAve)] - d1 = findDerivativeBetweenPoints(v1, v2) - dAve.append(d1) - dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) - - xAlongAround.append(xAve) - d1AlongAround.append(dAve) - - xAround = xFirstHalf + xSecondHalf[1:-1] - d1Around = d1FirstHalf + d1SecondHalf[1:-1] - d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - # calculate curvature - - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - - # for n2 in range(len(xAlongAround)): - # for n1 in range(len(xAlongAround[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround - ptsOnTrackSurfaceOesoToFundus = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][int(elementsCountAroundDuodenum * 0.5)]) - - xFirstTwoLoopsRight = [] - xFirstTwoLoopsLeft = [] - d2FirstTwoLoopsRight = [] #KM - d2FirstTwoLoopsLeft = [] # KM - - for nLoop in range(1, 3): - GCIdx = nLoop + 1 - if GCIdx < nodesCountFromOesoToApex: - ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus - proportion1 = 0.5 + xAlongAround.append(xAve) + d1AlongAround.append(dAve) + + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) + + # for n2 in range(len(xAlongAround)): + # for n1 in range(len(xAlongAround[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround + ptsOnTrackSurfaceOesoToFundus = [] + for n2 in range(elementsCountAlongTrackSurface + 1): + ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][elementsAroundHalfDuod]) + + xLoopsRight = [] + xLoopsLeft = [] + d2LoopsRight = [] # KM + d2LoopsLeft = [] # KM + + for nLoop in range(1, elementsAroundHalfDuod - 1): #3): + GCIdx = nLoop + 1 + if GCIdx < nodesCountFromOesoToApex: + ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus + proportion1 = 0.5 + else: + ptsOnTrackSurface = ptsOnTrackSurfaceGC + proportion1 = 0.0 + d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], + ptsOnTrackSurface, + trackSurfaceStomach, proportion1, + elementsCountAlongTrackSurface)[1] + + if GCIdx < nodesCountFromOesoToApex: + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] + d2GC = d2GCRot + + for nSide in range(2): + if nSide == 0: + xEnd = xAlongAround[0][elementsAroundHalfDuod - nLoop] + d2End = [xAlongAround[1][elementsAroundHalfDuod - nLoop][c] - + xAlongAround[0][elementsAroundHalfDuod - nLoop][c] for c in range(3)] else: - ptsOnTrackSurface = ptsOnTrackSurfaceGC - proportion1 = 0.0 - d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], - ptsOnTrackSurface, - trackSurfaceStomach, proportion1, - elementsCountAlongTrackSurface)[1] - - if GCIdx < nodesCountFromOesoToApex: rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) - d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in - range(3)] + d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] d2GC = d2GCRot - for nSide in range(2): - if nSide == 0: - xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop] - d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] - - xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] for c in range(3)] + xEnd = xAlongAround[0][elementsAroundHalfDuod + 1 + nLoop] + d2End = [xAlongAround[1][elementsAroundHalfDuod + nLoop][c] - + xAlongAround[0][elementsAroundHalfDuod + (0 if elementsCountAroundOeso > 8 else 1) + nLoop][c] for c in range(3)] + + nx = [xOesoToDuodGC[GCIdx], xEnd] + nd2 = [d2GC, d2End] + x, d2 = interp.sampleCubicHermiteCurves(nx, nd2, elementsAroundQuarterOeso + 2, arcLengthDerivatives=True)[0:2] + + # Find closest sampled points onto track surface + xProjectedPoints = [] + d2ProjectedPoints = [] + xProjectedPoints.append(xOesoToDuodGC[GCIdx]) + d2ProjectedPoints.append(d2GC) + for n2 in range(1, len(x)): + projectedPosition = trackSurfaceStomach.findNearestPosition(x[n2]) + xProjected = trackSurfaceStomach.evaluateCoordinates(projectedPosition) + xProjectedPoints.append(xProjected) + + for n2 in range(1, len(xProjectedPoints) - 1): + d2 = findDerivativeBetweenPoints(xProjectedPoints[n2], xProjectedPoints[n2 + 1]) + d2ProjectedPoints.append(d2) + d2ProjectedPoints.append(d2End) + + # Sample points again + xLoop, d2Loop = interp.sampleCubicHermiteCurves(xProjectedPoints, d2ProjectedPoints, + elementsAroundQuarterOeso + 2, + addLengthEnd=0.5 * vector.magnitude( + d2ProjectedPoints[-1]), + lengthFractionEnd=0.5, + arcLengthDerivatives=True)[0:2] + (xLoopsRight if nSide == 0 else xLoopsLeft).append(xLoop) + (d2LoopsRight if nSide == 0 else d2LoopsLeft).append(d2Loop) + + # for n2 in range(len(xLoopsRight)): + # for n1 in range(len(xLoopsRight[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsRight[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LoopsRight[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # for n2 in range(len(xLoopsLeft)): + # for n1 in range(len(xLoopsLeft[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsLeft[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LoopsLeft[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Find triple point + xTriplePts = [[None], [None]] # Right, left + d1TriplePts = [[None], [None]] + d2TriplePts = [[None], [None]] + d3TriplePtsNorm = [[None], [None]] + + for nSide in range(2): + ostiumIdx = elementsAroundQuarterOeso if nSide == 0 else -elementsAroundQuarterOeso + p1x = o1_x[1][ostiumIdx] + d = o1_d2[1][ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][ostiumIdx], math.pi) + p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + p1d = [annulusDerivativeFactor * c for c in p1d] + + xLoops = xLoopsRight if nSide == 0 else xLoopsLeft + p2x = xLoops[0][elementsAroundQuarterOeso + 1] # downstream bifurcation + p2d = findDerivativeBetweenPoints(xLoops[0][elementsAroundQuarterOeso + 1], + xLoops[1][elementsAroundQuarterOeso + 1]) + + p3x = xLoops[0][elementsAroundQuarterOeso] + p3d = findDerivativeBetweenPoints(xLoops[0][elementsAroundQuarterOeso], + xLoops[1][elementsAroundQuarterOeso]) + + xTriplePts[nSide], d1TriplePts[nSide], d2TriplePts[nSide] = get_bifurcation_triple_point(p1x, p1d, + p2x, p2d, + p3x, p3d) + d3TriplePtsNorm[nSide] = vector.normalise( + vector.crossproduct3(vector.normalise(d1TriplePts[nSide]), + vector.normalise(d2TriplePts[nSide]))) + + # Make sure triple point is on track surface + triplePointPosition = trackSurfaceStomach.findNearestPosition(xTriplePts[nSide]) + xTriplePts[nSide] = trackSurfaceStomach.evaluateCoordinates(triplePointPosition) + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p1x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p1d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p2x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p2d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p3x) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p3d) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TriplePts[nSide]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3TriplePtsNorm[nSide]) + # nodeIdentifier += 1 + + # Plan A - Sample points from GC to bottom of loops to create nodes running on row 2 + xBifurcationRings = [] + d1BifurcationRings = [] + xUp = [] + d1Up = [] + for n2 in range(elementsAroundQuarterOeso): + xAround = [] + d1Around = [] + xAroundRight = [] + d1AroundRight = [] + xAroundLeft = [] + d1AroundLeft = [] + loopIdx = n2 + 2 + ostiumIdx = loopIdx + (0 if n2 < elementsAroundQuarterOeso - 1 else -1) + GCIdx = elementsAlongGCFromOesoToFundusEnd - elementsAroundQuarterOeso + n2 + (2 if useLimitingRidge else 1) + d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface)[1] + for nSide in range(2): + if nSide == 0: # Right side + xAroundRight.append(xOesoToDuodGC[GCIdx]) + d1AroundRight.append(d1GC) + xOnLastLoopRight = xLoopsRight[-1][loopIdx] + d1OnLastLoopRight = findDerivativeBetweenPoints(xLoopsRight[-1][loopIdx], xLoopsRight[-2][loopIdx]) + + nx = [xOesoToDuodGC[GCIdx], xOnLastLoopRight] + nd1 = [d1GC, d1OnLastLoopRight] + x, d1 = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] + + # Find closest sampled points onto track surface + projectedPosition = trackSurfaceStomach.findNearestPosition(x[1]) + x[1] = trackSurfaceStomach.evaluateCoordinates(projectedPosition) + d1[1] = findDerivativeBetweenPoints(x[1], x[2]) + + # Sample points again + x, d1 = interp.sampleCubicHermiteCurves(x, d1, 2, arcLengthDerivatives=True)[0:2] + + xAroundRight.append(x[1]) + d1AroundRight.append(d1[1]) + + for n in range(len(xLoopsRight) - 1): + xAroundRight.append(xLoopsRight[-(1 + n)][loopIdx]) + d1AroundRight.append(findDerivativeBetweenPoints(xLoopsRight[-(1 + n)][loopIdx], xLoopsRight[-(1 + n + 1)][loopIdx])) + + if loopIdx < elementsAroundQuarterOeso: # additional elements upstream of triple point + xLoop = xLoopsRight[0][loopIdx] + xLoopPosition = trackSurfaceStomach.findNearestPosition(xLoop) + xLoopProportion1, xLoopProportion2 = trackSurfaceStomach.getProportion(xLoopPosition) + xOstium = o1_x[1][ostiumIdx] + ostiumPosition = o1_Positions[ostiumIdx] + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xLoop, xOstium) + endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, xLoopProportion1, + xLoopProportion2, ostiumProportion1, + ostiumProportion2, 2, # startDerivative=d, + endDerivativeMagnitude=endDerivativeMag)[0:2] + xAroundRight += xSampled[:2] + d1AroundRight += dSampled[:2] + + else: # connected to triple point + xAroundRight += [xLoopsRight[0][loopIdx]] + [xTriplePts[0]] + d1AroundRight += [findDerivativeBetweenPoints(xLoopsRight[0][loopIdx], xTriplePts[0])] + \ + [d1TriplePts[0]] + + # for n1 in range(len(xAroundRight)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundRight[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1AroundRight[n1]) + # nodeIdentifier += 1 + + else: # left side + if loopIdx < elementsAroundQuarterOeso: # additional elements upstream of triple point + xLoop = xLoopsLeft[0][loopIdx] + xLoopPosition = trackSurfaceStomach.findNearestPosition(xLoop) + xLoopProportion1, xLoopProportion2 = trackSurfaceStomach.getProportion(xLoopPosition) + xOstium = o1_x[1][-ostiumIdx] + ostiumPosition = o1_Positions[-ostiumIdx] + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xOstium, xLoop) + startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, + xLoopProportion1, xLoopProportion2, 2, # endDerivative=d, + startDerivativeMagnitude=startDerivativeMag)[0:2] + xAroundLeft.append(xSampled[1]) + d1AroundLeft.append(dSampled[1]) else: - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) - d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in - range(3)] - d2GC = d2GCRot + xAroundLeft.append(xTriplePts[1]) + d1AroundLeft.append(d1TriplePts[1]) + + for n in range(len(xLoopsLeft) - 1): + xAroundLeft.append(xLoopsLeft[n][loopIdx]) + d1AroundLeft.append(findDerivativeBetweenPoints(xLoopsLeft[n][loopIdx], xLoopsLeft[n + 1][loopIdx])) - xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + nLoop] - d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) + nLoop][c] - - xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) + (0 if elementsCountAroundOesophagus > 8 else 1) + nLoop][c] for c in range(3)] + xOnLastLoopLeft = xLoopsLeft[-1][loopIdx] + d1OnLastLoopLeft = findDerivativeBetweenPoints(xLoopsLeft[-2][loopIdx], xLoopsLeft[-1][loopIdx]) - nx = [xOesoToDuodGC[GCIdx], xEnd] - nd2 = [d2GC, d2End] - x, d2 = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25 + 2), - arcLengthDerivatives=True)[0:2] + nx = [xOnLastLoopLeft, xOesoToDuodGC[GCIdx]] + nd1 = [d1OnLastLoopLeft, d1GC] + x, d1 = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] # Find closest sampled points onto track surface - xProjectedPoints = [] - d2ProjectedPoints = [] - for n2 in range(len(x)): - projectedPosition = trackSurfaceStomach.findNearestPosition(x[n2]) - xProjected = trackSurfaceStomach.evaluateCoordinates(projectedPosition) - xProjectedPoints.append(xProjected) - - for n2 in range(len(xProjectedPoints) - 1): - d2 = findDerivativeBetweenPoints(xProjectedPoints[n2], xProjectedPoints[n2 + 1]) - d2ProjectedPoints.append(d2) - d2ProjectedPoints.append(d2) + projectedPosition = trackSurfaceStomach.findNearestPosition(x[1]) + x[1] = trackSurfaceStomach.evaluateCoordinates(projectedPosition) + d1[1] = findDerivativeBetweenPoints(x[1], x[2]) # Sample points again - xLoop, d2Loop = interp.sampleCubicHermiteCurves(xProjectedPoints, d2ProjectedPoints, - int(elementsCountAroundOesophagus * 0.25 + 2))[0:2] - - (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft).append(xLoop) - (d2FirstTwoLoopsRight if nSide == 0 else d2FirstTwoLoopsLeft).append(d2Loop) - - # for n2 in range(len(xFirstTwoLoopsRight)): - # for n1 in range(len(xFirstTwoLoopsRight[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsRight[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsRight[n2][n1]) - # nodeIdentifier += 1 - # - # for n2 in range(len(xFirstTwoLoopsLeft)): - # for n1 in range(len(xFirstTwoLoopsLeft[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsLeft[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsLeft[n2][n1]) - # nodeIdentifier += 1 - - # Find triple point - xTriplePts = [[None], [None]] # Right, left - d1TriplePts = [[None], [None]] - d2TriplePts = [[None], [None]] - d3TriplePtsNorm = [[None], [None]] + x, d1 = interp.sampleCubicHermiteCurves(x, d1, 2, arcLengthDerivatives=True)[0:2] - for nSide in range(2): - ostiumIdx = int(elementsCountAroundOesophagus * 0.25) if nSide == 0 else -int(elementsCountAroundOesophagus * 0.25) - p1x = o1_x[1][ostiumIdx] - d = o1_d2[1][ostiumIdx] - rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][ostiumIdx], math.pi) - p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - p1d = [annulusDerivativeFactor * c for c in p1d] - - xFirstTwoLoops = xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft - p2x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)] # downstream bifurcation - p2d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)], - xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25 + 1)]) - - p3x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)] - p3d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)], - xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25)]) - - xTriplePts[nSide], d1TriplePts[nSide], d2TriplePts[nSide] = get_bifurcation_triple_point(p1x, p1d, p2x, p2d, p3x, p3d) - d3TriplePtsNorm[nSide] = vector.normalise( - vector.crossproduct3(vector.normalise(d1TriplePts[nSide]), vector.normalise(d2TriplePts[nSide]))) - - # Make sure triple point is on track surface - triplePointPosition = trackSurfaceStomach.findNearestPosition(xTriplePts[nSide]) - xTriplePts[nSide] = trackSurfaceStomach.evaluateCoordinates(triplePointPosition) - - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p1x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p1d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p2x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p2d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p3x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p3d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3TriplePtsNorm[nSide]) - # nodeIdentifier += 1 - - # Use track surface to sample point on GC to loop 1 (includes bifurcation rings and additional upstream rings) - xBifurcationRings = [] - d1BifurcationRings = [] - xUp = [] - d1Up = [] - for n2 in range(int(elementsCountAroundOesophagus * 0.25)): - xAround = [] - d1Around = [] - loopIdx = n2 + 2 - ostiumIdx = loopIdx + (0 if n2 < int(elementsCountAroundOesophagus * 0.25 - 1) else -1) - GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + 1 + n2 - GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, - elementsCountAlongTrackSurface) - GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) - - if loopIdx < int(elementsCountAroundOesophagus * 0.25): # additional elements upstream of triple point - for nSide in range(2): - if nSide == 0: - xLoop = xFirstTwoLoopsRight[0][loopIdx] - xOstium = o1_x[1][ostiumIdx] - ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) - ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) - d = findDerivativeBetweenPoints(xLoop, xOstium) - endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, - GCProportion2, ostiumProportion1, ostiumProportion2, - int(elementsCountAroundDuodenum * 0.5 + 1), - startDerivative=d1GC, endDerivative=d, - endDerivativeMagnitude=endDerivativeMag)[0:2] + xAroundLeft += [xOnLastLoopLeft] + [x[1]] + [xOesoToDuodGC[GCIdx]] + d1AroundLeft += [findDerivativeBetweenPoints(xOnLastLoopLeft, x[1])] + [d1[1]] + [d1GC] - else: - xLoop = xFirstTwoLoopsLeft[0][loopIdx] - xOstium = o1_x[1][-ostiumIdx] - ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) - ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) - d = findDerivativeBetweenPoints(xOstium, xLoop) - startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, - 1.0, GCProportion2, - int(elementsCountAroundDuodenum * 0.5 + 1), - startDerivative= d, endDerivative=d1GC, - startDerivativeMagnitude=startDerivativeMag)[0:2] - - xAround += xSampled[:-1] if nSide == 0 else xSampled[1:-1] - d1Around += dSampled[:-1] if nSide == 0 else dSampled[1:-1] - - # for n1 in range(len(xAround)): + # for n1 in range(len(xAroundLeft)): # node = nodes.createNode(nodeIdentifier, nodetemplate) # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundLeft[n1]) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Around[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1AroundLeft[n1]) # nodeIdentifier += 1 - # xBifurcationRings.append(xAround) - # d1BifurcationRings.append(d1Around) - xUp.append(xAround) - d1Up.append(d1Around) - - else: # connected to triple point - for nSide in range(2): - xLoop = (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft)[0][loopIdx] - loopPosition = trackSurfaceStomach.findNearestPosition(xLoop) - loopProportion1, loopProportion2 = trackSurfaceStomach.getProportion(loopPosition) - - if nSide == 0: - d = findDerivativeBetweenPoints(xLoop, o1_x[1][ostiumIdx]) - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, - GCProportion2, loopProportion1, loopProportion2, - int(elementsCountAroundDuodenum * 0.5) - 1, - startDerivative=d1GC, endDerivative = d)[0:2] - xSampled.append(xTriplePts[0]) - dSampled.append(d1TriplePts[0]) + xAround = xAroundRight + xAroundLeft[:-1] + d1Around = d1AroundRight + d1AroundLeft[:-1] - else: - d = findDerivativeBetweenPoints(o1_x[1][-ostiumIdx], xLoop) - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, loopProportion1, - loopProportion2, 1.0, GCProportion2, - int(elementsCountAroundDuodenum * 0.5) - 1, - startDerivative = d, endDerivative=d1GC)[0:2] - xSampled.insert(0, xTriplePts[1]) - dSampled.insert(0, d1TriplePts[1]) - - xAround += xSampled if nSide == 0 else xSampled[:-1] - d1Around += dSampled if nSide == 0 else dSampled[:-1] - - xUp.append(xAround) - d1Up.append(d1Around) - xBifurcationRings.append(xAround) - d1BifurcationRings.append(d1Around) - - # for n2 in range(len(xBifurcationRings)): - # for n1 in range(len(xBifurcationRings[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBifurcationRings[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1BifurcationRings[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Row 2 - for nSide in range(2): - if nSide == 0: - xStart = xUp[0][1] - dStart = findDerivativeBetweenPoints(xUp[1][1], xUp[0][1]) - startDerivativeMag = None - xEnd = o1_x[1][1] - dEnd = findDerivativeBetweenPoints(xFirstTwoLoopsRight[0][1], o1_x[1][1]) - endDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) + xUp.append(xAround) + d1Up.append(d1Around) - else: - xStart = o1_x[1][-1] - dStart = findDerivativeBetweenPoints(o1_x[1][-1], xFirstTwoLoopsLeft[0][1]) - startDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) - xEnd = xUp[0][-1] - dEnd = findDerivativeBetweenPoints(xUp[0][-1], xUp[1][-1]) - endDerivativeMag = None + if loopIdx >= elementsAroundQuarterOeso: + xBifurcationRings.append(xAround) + d1BifurcationRings.append(d1Around) - startPosition = trackSurfaceStomach.findNearestPosition(xStart) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - endPosition = trackSurfaceStomach.findNearestPosition(xEnd) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + # for n2 in range(len(xBifurcationRings)): + # for n1 in range(len(xBifurcationRings[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBifurcationRings[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1BifurcationRings[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # for n2 in range(len(xUp)): + # for n1 in range(len(xUp[n2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xUp[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Up[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Row 2 + xRow2Right = [] + d1Row2Right = [] + xRow2Left = [] + d1Row2Left = [] + + for nSide in range(2): + loopIdx = 1 + ostiumIdx = 1 + if nSide == 0: + xRow2Right.append(xUp[0][1]) + d1Row2Right.append(findDerivativeBetweenPoints(xUp[0][1], xLoopsRight[-1][1])) + # Append rows upwards in loops + for n in range(len(xLoopsRight) - 1): + xRow2Right.append(xLoopsRight[-(1 + n)][1]) + d1Row2Right.append( + findDerivativeBetweenPoints(xLoopsRight[-(1 + n)][1], xLoopsRight[-(1 + n + 1)][1])) + + xLoop = xLoopsRight[0][loopIdx] + xLoopPosition = trackSurfaceStomach.findNearestPosition(xLoop) + xLoopProportion1, xLoopProportion2 = trackSurfaceStomach.getProportion(xLoopPosition) + xOstium = o1_x[1][ostiumIdx] + ostiumPosition = o1_Positions[ostiumIdx] + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xLoop, xOstium) + endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, - endProportion1, endProportion2, - int(elementsCountAroundDuodenum * 0.5), - startDerivative=dStart, endDerivative=dEnd, - startDerivativeMagnitude=startDerivativeMag, + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, xLoopProportion1, + xLoopProportion2, ostiumProportion1, + ostiumProportion2, 2, # startDerivative=d, endDerivativeMagnitude=endDerivativeMag)[0:2] + xRow2Right += xSampled[0:2] + d1Row2Right += [findDerivativeBetweenPoints(xSampled[0], xSampled[1])] + [dSampled[1]] # dSampled[0:2] - if nSide == 0: - xRow2Right = xSampled[:-1] - d1Row2Right = dSampled[:-1] - else: - xRow2Left = xSampled[1:] - d1Row2Left = dSampled[1:] + else: + xLoop = xLoopsLeft[0][loopIdx] + xLoopPosition = trackSurfaceStomach.findNearestPosition(xLoop) + xLoopProportion1, xLoopProportion2 = trackSurfaceStomach.getProportion(xLoopPosition) + xOstium = o1_x[1][-ostiumIdx] + ostiumPosition = o1_Positions[-ostiumIdx] + ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) + d = findDerivativeBetweenPoints(xOstium, xLoop) + startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor - # for n1 in range(len(xRow2Right)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Right[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Right[n1]) - # nodeIdentifier += 1 + xSampled, dSampled = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, + xLoopProportion1, xLoopProportion2, 2, # endDerivative=d, + startDerivativeMagnitude=startDerivativeMag)[0:2] + xRow2Left += xSampled[1:] + d1Row2Left += [dSampled[1]] + [findDerivativeBetweenPoints(xSampled[1], xSampled[2])] - # for n1 in range(len(xRow2Left)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Left[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Left[n1]) - # nodeIdentifier += 1 + for n in range(1, len(xLoopsLeft)): + xRow2Left.append(xLoopsLeft[n][loopIdx]) + d1Row2Left.append(findDerivativeBetweenPoints(xLoopsLeft[n-1][loopIdx], xLoopsLeft[n][loopIdx])) - # Smooth derivatives from triple point to 6 point junction - # Start from GC at upstream bifurcation ring to annulus to 6 point junction ring on right then left - xLoopTripleTo6Pt = [] - dLoopTripleTo6Pt = [] - - xLoopTripleTo6Pt += xBifurcationRings[0][0:int(len(xBifurcationRings[0]) * 0.5) + 1] - for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): - xLoopTripleTo6Pt.append(xAlongAround[n2][int(len(xAlongAround[n2]) * 0.5)]) - junctionIdx = n2 + 1 - xLoopTripleTo6Pt += xAlongAround[junctionIdx][int(len(xAlongAround[junctionIdx]) * 0.5):] + \ - xAlongAround[junctionIdx][0: int(len(xAlongAround[junctionIdx]) * 0.5 + 1)] - for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): # Note order here - going upstream - idx = junctionIdx - 1 - n2 - xLoopTripleTo6Pt.append(xAlongAround[idx][int(len(xAlongAround[idx]) * 0.5) + 1]) - xLoopTripleTo6Pt += xBifurcationRings[0][int(len(xBifurcationRings[0]) * 0.5 + 1):] - - for n in range(len(xLoopTripleTo6Pt)): - d = findDerivativeBetweenPoints(xLoopTripleTo6Pt[n], xLoopTripleTo6Pt[(n+1) % len(xLoopTripleTo6Pt)]) - dLoopTripleTo6Pt.append(d) - dSmoothLoopTripleTo6Pt = interp.smoothCubicHermiteDerivativesLoop(xLoopTripleTo6Pt, dLoopTripleTo6Pt) - # curvature - DONE + xRow2Left.append(xUp[0][-1]) + d1Row2Left.append(findDerivativeBetweenPoints(xLoopsLeft[-1][1], xUp[0][-1])) - # for n1 in range(len(xLoopTripleTo6Pt)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopTripleTo6Pt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopTripleTo6Pt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) - # nodeIdentifier += 1 + # for n1 in range(len(xRow2Right)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Right[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Right[n1]) + # # print(vector.magnitude(d1Row2Right[n1]), vector.magnitude(d1Row2Left[-(1+n1)])) + # nodeIdentifier += 1 + # + # for n1 in range(len(xRow2Left)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Left[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Left[n1]) + # nodeIdentifier += 1 - # Smooth derivatives around top loop - # Starts from GC at downstream bifurcation ring to annulus and back - xLoopGCTriplePt = [] - dLoopGCTriplePt = [] + # Smooth derivatives from triple point to 6 point junction + # Start from GC at upstream bifurcation ring to annulus to 6 point junction ring on right then left + xLoopTripleTo6Pt = [] + dLoopTripleTo6Pt = [] + + xLoopTripleTo6Pt += xBifurcationRings[0][0:int(len(xBifurcationRings[0]) * 0.5) + 1] + for n2 in range(elementsAroundQuarterOeso - 1): + xLoopTripleTo6Pt.append(xAlongAround[n2][int(len(xAlongAround[n2]) * 0.5)]) + junctionIdx = n2 + 1 + xLoopTripleTo6Pt += xAlongAround[junctionIdx][int(len(xAlongAround[junctionIdx]) * 0.5):] + \ + xAlongAround[junctionIdx][0: int(len(xAlongAround[junctionIdx]) * 0.5 + 1)] + for n2 in range(elementsAroundQuarterOeso - 1): # Note order here - going upstream + idx = junctionIdx - 1 - n2 + xLoopTripleTo6Pt.append(xAlongAround[idx][int(len(xAlongAround[idx]) * 0.5) + 1]) + xLoopTripleTo6Pt += xBifurcationRings[0][int(len(xBifurcationRings[0]) * 0.5 + 1):] + + for n in range(len(xLoopTripleTo6Pt)): + d = findDerivativeBetweenPoints(xLoopTripleTo6Pt[n], xLoopTripleTo6Pt[(n+1) % len(xLoopTripleTo6Pt)]) + dLoopTripleTo6Pt.append(d) + dSmoothLoopTripleTo6Pt = interp.smoothCubicHermiteDerivativesLoop(xLoopTripleTo6Pt, dLoopTripleTo6Pt) + # curvature - DONE + + # for n1 in range(len(xLoopTripleTo6Pt)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopTripleTo6Pt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopTripleTo6Pt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) + # nodeIdentifier += 1 - xLoopGCTriplePt += xBifurcationRings[1][:int(len(xBifurcationRings[1]) * 0.5) + 1] + # Smooth derivatives around top loop + # Starts from GC at downstream bifurcation ring to annulus and back + xLoopGCTriplePt = [] + dLoopGCTriplePt = [] - for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): - idx = -(3 + n2) - xLoopGCTriplePt.append(xUp[idx][int(len(xUp[idx]) * 0.5)]) + xLoopGCTriplePt += xBifurcationRings[1][:int(len(xBifurcationRings[1]) * 0.5) + 1] - xLoopGCTriplePt += [xRow2Right[-1]] + [xOesoToDuodGC[1]] + [xRow2Left[0]] + for n2 in range(elementsAroundQuarterOeso - 2): + idx = -(3 + n2) + xLoopGCTriplePt.append(xUp[idx][int(len(xUp[idx]) * 0.5)]) - for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): - xLoopGCTriplePt.append(xUp[n2][int(len(xUp[n2]) * 0.5) + 1]) + xLoopGCTriplePt += [xRow2Right[-1]] + [xOesoToDuodGC[1]] + [xRow2Left[0]] - xLoopGCTriplePt += xBifurcationRings[1][int(len(xBifurcationRings[1]) * 0.5) + 1:] + for n2 in range(elementsAroundQuarterOeso - 2): + xLoopGCTriplePt.append(xUp[n2][int(len(xUp[n2]) * 0.5) + 1]) - for n in range(len(xLoopGCTriplePt)): - d = findDerivativeBetweenPoints(xLoopGCTriplePt[n], xLoopGCTriplePt[(n+1) % len(xLoopGCTriplePt)]) - dLoopGCTriplePt.append(d) - dSmoothLoopGCTriplePt = interp.smoothCubicHermiteDerivativesLoop(xLoopGCTriplePt, dLoopGCTriplePt) - # curvature - DONE + xLoopGCTriplePt += xBifurcationRings[1][int(len(xBifurcationRings[1]) * 0.5) + 1:] - # for n1 in range(len(xLoopGCTriplePt)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopGCTriplePt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopGCTriplePt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) - # nodeIdentifier += 1 + for n in range(len(xLoopGCTriplePt)): + d = findDerivativeBetweenPoints(xLoopGCTriplePt[n], xLoopGCTriplePt[(n+1) % len(xLoopGCTriplePt)]) + dLoopGCTriplePt.append(d) + dSmoothLoopGCTriplePt = interp.smoothCubicHermiteDerivativesLoop(xLoopGCTriplePt, dLoopGCTriplePt) + # curvature - DONE - # Assemble nodes and d1 - xOuter = [] - d1Outer = [] - countUp = 0 - countDown = 0 - for n2 in range(elementsCountAlong + 1): - xAround = [] - d1Around = [] - d2Around = [] - if n2 == 0: - # print(n2, 'GC') - for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): - xAround.append(xOesoToDuodGC[i + 1]) - d1Around.append(d2OesoToDuodGC[i + 1]) - - elif n2 == 1: - # print(n2, 'Row 2') - xAround = [xOesoToDuodGC[i + n2 + 1]] + xRow2Right[1:] + xRow2Left[:-1] - d1Around = [d2OesoToDuodGC[i + n2 + 1]] + d1Row2Right[1:] + d1Row2Left[:-1] # need to replace d1Row2 after smoothing - DONE - - elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): - # print(n2, 'Before triple point + triple point') - xAround = xUp[countUp] - if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt - # smooth d1 around - Make into function? - d1Around = d1Up[countUp] - 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)] - d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, - fixEndDerivative=True) - # Need to do curvature and rearrange to correct order - d1Around = [] - d1Around = d1LoopSmooth[int(len(xAround) * 0.5) : ] + d1LoopSmooth[: int(len(xAround) * 0.5) : ] - - elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation - # take smoothed d1 from dSmoothTripleTo6Pt - d1Around = dSmoothLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ - dSmoothLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5) : ] - - elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation - # take smoothed d1 from dSmoothGCToTriplePt - d1Around = dSmoothLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ - dSmoothLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5) : ] - countUp += 1 - - elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): - # print(n2, 'Downstream of triple point') - xAround = xAlongAround[countDown] - d1Around = d1AlongAround[countDown] + # for n1 in range(len(xLoopGCTriplePt)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopGCTriplePt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopGCTriplePt[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) + # nodeIdentifier += 1 + + # Resample loop before 6 point junction + for n in range(1, elementsCountAroundDuod + 1): + if elementsAroundHalfDuod <= n <=elementsAroundHalfDuod + 1: + pass + else: + if elementsCountAroundOeso > 8: + xStart = xAlongAround[-(elementsAlongAnnulusToDuod + 3)][n] + else: + xStart = xUp[-1][n] + xEnd = xAlongAround[-(elementsAlongAnnulusToDuod + 1)][n - (1 if n > elementsAroundHalfDuod else 0)] + startPosition = trackSurfaceStomach.findNearestPosition(xStart) + d2Start = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[2] + + endPosition = trackSurfaceStomach.findNearestPosition(xEnd) + d2End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[2] + + xSampled = interp.sampleCubicHermiteCurves([xStart, xEnd], [d2Start, d2End], 2)[0] + xNewPosition = trackSurfaceStomach.findNearestPosition(xSampled[1]) + xNew = trackSurfaceStomach.evaluateCoordinates(xNewPosition) + xAlongAround[-(elementsAlongAnnulusToDuod + 2)][n] = xNew + + # xStarts = [] + # d2Starts = [] + # xEnds = [] + # d2Ends = [] + # for n in range(elementsAroundHalfDuod + 2, elementsCountAroundDuod + 1): + # if elementsCountAroundOeso > 8: + # xStart = xAlongAround[-(elementsAlongAnnulusToDuod + 3)][n] + # else: + # xStart = xUp[-1][n] + # xEnd = xAlongAround[-(elementsAlongAnnulusToDuod + 1)][n - 1] + # + # startPosition = trackSurfaceStomach.findNearestPosition(xStart) + # d2Start = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[2] + # xStarts.append(xStart) + # d2Starts.append(d2Start) + # + # endPosition = trackSurfaceStomach.findNearestPosition(xEnd) + # d2End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[2] + # xEnds.append(xEnd) + # d2Ends.append(d2End) + # + # xSampled = interp.sampleCubicHermiteCurves([xStart, xEnd], [d2Start, d2End], 2)[0] + # xNewPosition = trackSurfaceStomach.findNearestPosition(xSampled[1]) + # xNew = trackSurfaceStomach.evaluateCoordinates(xNewPosition) + # + # xAlongAround[-(elementsAlongAnnulusToDuod + 2)][n] = xNew + + + # Assemble nodes and d1 + xOuter = [] + d1Outer = [] + countUp = 0 + countDown = 0 + for n2 in range(elementsCountAlong + 1): + xAround = [] + d1Around = [] + d2Around = [] + if n2 == 0: + # print(n2, 'GC') + for i in range(elementsAroundHalfDuod - 2): + xAround.append(xOesoToDuodGC[i + 1]) + d1Around.append(d2OesoToDuodGC[i + 1]) + + elif n2 == 1: + # print(n2, 'Row 2') + xAround = [xOesoToDuodGC[i + n2 + 1]] + xRow2Right[1:] + xRow2Left[:-1] + d1Around = [d2OesoToDuodGC[i + n2 + 1]] + d1Row2Right[1:] + d1Row2Left[:-1] # need to replace d1Row2 after smoothing - DONE + + elif n2 > 1 and n2 < elementsAroundQuarterOeso + 2: + # print(n2, 'Before triple point + triple point') + xAround = xUp[countUp] + if n2 < elementsAroundQuarterOeso: # upstream of triple pt # smooth d1 around - Make into function? - if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): - 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)] - d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, - fixEndDerivative=True) - # Need to do curvature and rearrange to correct order - d1Around = [] - d1Around = d1LoopSmooth[int(len(xAround) * 0.5):] + d1LoopSmooth[: int(len(xAround) * 0.5):] - - elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring - # take smoothed d1 from dSmoothedTripleTo6Pt - startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len(xAlongAround[junctionIdx]) * 0.5) - endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - d1Around = dSmoothLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ - dSmoothLoopTripleTo6Pt[startLeftIdx : startRightIdx] - countDown += 1 - - xOuter.append(xAround) - d1Outer.append(d1Around) - - # for m2 in range(len(xOuter)): - # for m1 in range(len(xOuter[m2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Calculate d2 - xRegularLoops = [] - d2RegularLoops = [] - d2RegularOrderedLoops = [] - - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): - xRegularLoop = [] - d1RegularRightLoop = [] - d2RegularLoop = [] - for n2 in range(elementsCountAlong): - idx = -(1 + n2) - xRegularLoop.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - d1RegularRightLoop.append(d1Outer[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - xRegularLoop.append(xOesoToDuodGC[n1 + 2]) - for n2 in range(elementsCountAlong): - xRegularLoop.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) - - for n in range(len(xRegularLoop) - 1): - d = findDerivativeBetweenPoints(xRegularLoop[n], xRegularLoop[n+1]) - d2RegularLoop.append(d) - d2RegularLoop.append(d) + d1Around = d1Up[countUp] + 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)] + d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, + fixEndDerivative=True) + # Need to do curvature and rearrange to correct order + d1Around = [] + d1Around = d1LoopSmooth[int(len(xAround) * 0.5) : ] + d1LoopSmooth[: int(len(xAround) * 0.5) : ] + + elif n2 == elementsAroundQuarterOeso: # upstream bifurcation + # take smoothed d1 from dSmoothTripleTo6Pt + d1Around = dSmoothLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ + dSmoothLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5) : ] + + elif n2 > elementsAroundQuarterOeso: # downstream bifurcation + # take smoothed d1 from dSmoothGCToTriplePt + d1Around = dSmoothLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ + dSmoothLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5) : ] + countUp += 1 + + elif n2 > elementsAroundQuarterOeso + 1: + # print(n2, 'Downstream of triple point') + xAround = xAlongAround[countDown] + d1Around = d1AlongAround[countDown] + + # smooth d1 around - Make into function? + if n2 < elementsAroundHalfOeso + 1: + 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)] + d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, + fixEndDerivative=True) + # Need to do curvature and rearrange to correct order + d1Around = [] + d1Around = d1LoopSmooth[int(len(xAround) * 0.5):] + d1LoopSmooth[: int(len(xAround) * 0.5):] + + elif n2 == elementsAroundHalfOeso + 1: # 6 point junction ring + # take smoothed d1 from dSmoothedTripleTo6Pt + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsAroundQuarterOeso + len(xAlongAround[junctionIdx]) * 0.5) + endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + d1Around = dSmoothLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ + dSmoothLoopTripleTo6Pt[startLeftIdx : startRightIdx] + countDown += 1 + + xOuter.append(xAround) + d1Outer.append(d1Around) + + # for m2 in range(len(xOuter)): + # for m1 in range(len(xOuter[m2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 - d2SmoothRegularLoop = interp.smoothCubicHermiteDerivativesLine(xRegularLoop, d2RegularLoop) - d2SmoothRegularOrderedLoop = copy.deepcopy(d2SmoothRegularLoop) - # curvature - DONE + # Calculate d2 + xRegularLoops = [] + d2RegularLoops = [] + d2RegularOrderedLoops = [] - # Switch direction on right side - for n2 in range(elementsCountAlong): - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1RegularRightLoop[n2]), d2SmoothRegularLoop[n2])) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d = d2SmoothRegularLoop[n2] - d2SmoothRegularLoop[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - - xRegularLoops.append(xRegularLoop) - d2RegularLoops.append(d2SmoothRegularLoop) - d2RegularOrderedLoops.append(d2SmoothRegularOrderedLoop) - - # for m1 in range(len(xRegularLoops)): - # for m2 in range(len(xRegularLoops[m1])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRegularLoops[m1][m2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2RegularOrderedLoops[m1][m2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #d2RegularLoops[m1][m2]) - # nodeIdentifier += 1 - - # Smooth d2 along row 2 - xLoop2Right = [] - d1Loop2Right = [] - d2Loop2Right = [] - - for n2 in range(len(xAlongAround) + len(xUp) - 1): + for n1 in range(elementsAroundHalfDuod - 2): + xRegularLoop = [] + d1RegularRightLoop = [] + d2RegularLoop = [] + for n2 in range(elementsCountAlong): idx = -(1 + n2) - xLoop2Right.append(xOuter[idx][1]) - d1Loop2Right.append(d1Outer[idx][1]) - xLoop2Right += xRow2Right - d1Loop2Right += d1Row2Right - - for n in range(len(xLoop2Right) - 1): - d = findDerivativeBetweenPoints(xLoop2Right[n], xLoop2Right[n + 1]) - d2Loop2Right.append(d) - d2Loop2Right.append(d1Row2Right[-1]) - - d2Loop2Right = interp.smoothCubicHermiteDerivativesLine(xLoop2Right, d2Loop2Right, fixEndDirection=True) - # curvature - USING LEFT SIDE - DONE - - # Switch direction of d2 for downstream nodes - for n2 in range(len(xAlongAround) + len(xUp)): - rotAxis = vector.normalise( - vector.crossproduct3(vector.normalise(d1Loop2Right[n2]), d2Loop2Right[n2])) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d = d2Loop2Right[n2] - d2Loop2Right[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - idxSwitchToD1 = n2 + xRegularLoop.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + d1RegularRightLoop.append(d1Outer[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + xRegularLoop.append(xOesoToDuodGC[n1 + 2]) + for n2 in range(elementsCountAlong): + xRegularLoop.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfOeso else 2))]) + + for n in range(len(xRegularLoop) - 1): + d = findDerivativeBetweenPoints(xRegularLoop[n], xRegularLoop[n+1]) + d2RegularLoop.append(d) + d2RegularLoop.append(d) - # for m in range(len(xLoop2Right)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Right[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) #d2Loop2Right[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Loop2Right[m]) - # nodeIdentifier += 1 + d2SmoothRegularLoop = interp.smoothCubicHermiteDerivativesLine(xRegularLoop, d2RegularLoop) + d2SmoothRegularOrderedLoop = copy.deepcopy(d2SmoothRegularLoop) + # curvature - DONE - # Left - xLoop2Left = [] - d2Loop2Left = [] + # Switch direction on right side + for n2 in range(elementsCountAlong): + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1RegularRightLoop[n2]), d2SmoothRegularLoop[n2])) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d = d2SmoothRegularLoop[n2] + d2SmoothRegularLoop[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - xLoop2Left += xRow2Left - for n2 in range(3, len(xOuter)): - xLoop2Left.append(xOuter[n2][-1]) + xRegularLoops.append(xRegularLoop) + d2RegularLoops.append(d2SmoothRegularLoop) + d2RegularOrderedLoops.append(d2SmoothRegularOrderedLoop) - d2Loop2Left.append(d1Row2Left[0]) - for n in range(1, len(xLoop2Left) - 1): - d = findDerivativeBetweenPoints(xLoop2Left[n], xLoop2Left[n + 1]) - d2Loop2Left.append(d) - d2Loop2Left.append(d) + # for m1 in range(len(xRegularLoops)): + # for m2 in range(len(xRegularLoops[m1])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRegularLoops[m1][m2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2RegularOrderedLoops[m1][m2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #d2RegularLoops[m1][m2]) + # nodeIdentifier += 1 - d2Loop2Left = interp.smoothCubicHermiteDerivativesLine(xLoop2Left, d2Loop2Left, fixStartDirection=True) - # curvature - DONE + # Smooth d2 along row 2 + xLoop2Right = [] + d1Loop2Right = [] + d2Loop2Right = [] + + for n2 in range(len(xAlongAround) + len(xUp) - 1): + idx = -(1 + n2) + xLoop2Right.append(xOuter[idx][1]) + d1Loop2Right.append(d1Outer[idx][1]) + xLoop2Right += xRow2Right + d1Loop2Right += d1Row2Right + + for n in range(len(xLoop2Right) - 1): + d = findDerivativeBetweenPoints(xLoop2Right[n], xLoop2Right[n + 1]) + d2Loop2Right.append(d) + d2Loop2Right.append(d1Row2Right[-1]) + + d2Loop2Right = interp.smoothCubicHermiteDerivativesLine(xLoop2Right, d2Loop2Right, fixEndDirection=True) + # curvature - USING LEFT SIDE - DONE + + # Switch direction of d2 for downstream nodes + for n2 in range(len(xAlongAround) + len(xUp)): + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1Loop2Right[n2]), d2Loop2Right[n2])) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d = d2Loop2Right[n2] + d2Loop2Right[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + idxSwitchToD1 = n2 + + # for m in range(len(xLoop2Right)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Right[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) #d2Loop2Right[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Loop2Right[m]) + # nodeIdentifier += 1 - # for m in range(len(xLoop2Left)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Left[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Loop2Left[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + # Left + xLoop2Left = [] + d2Loop2Left = [] - # Smooth lower curvature - xLC = [] - d2LC = [] - for n2 in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): - xLC.append(xOuter[n2][int(len(xOuter[n2]) * 0.5)]) + xLoop2Left += xRow2Left + for n2 in range(3, len(xOuter)): + xLoop2Left.append(xOuter[n2][-1]) - for n in range(len(xLC) - 1): - d = findDerivativeBetweenPoints(xLC[n], xLC[n + 1]) - d2LC.append(d) - d2LC.append(d) + d2Loop2Left.append(d1Row2Left[0]) + for n in range(1, len(xLoop2Left) - 1): + d = findDerivativeBetweenPoints(xLoop2Left[n], xLoop2Left[n + 1]) + d2Loop2Left.append(d) + d2Loop2Left.append(d) - d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC, fixStartDirection=True) - # curvature - DONE + d2Loop2Left = interp.smoothCubicHermiteDerivativesLine(xLoop2Left, d2Loop2Left, fixStartDirection=True) + # curvature - DONE - # for m in range(len(xLC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLC[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LC[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + # for m in range(len(xLoop2Left)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Left[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Loop2Left[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 - # Update d1 for upstream nodes - for n1 in range(1, len(xRow2Right)): - d1Outer[1][n1] = d2Loop2Right[idxSwitchToD1 + n1] - for n1 in range(1, len(xRow2Left)): - d1Outer[1][int(len(d1Outer[1]) * 0.5) + n1] = d2Loop2Left[n1 - 1] - - # Assemble d2 - d2Outer = [] - for n2 in range(elementsCountAlong + 1): - d2Around = [] - xAround = [] # KM - if n2 == 0: - # print(n2, 'GC') - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5)]) #KM - d2Around.append(dSmoothLoopGCTriplePt[int(len(dSmoothLoopGCTriplePt) * 0.5)]) - - for n1 in range(len(xOuter[0]) - 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) - d2Around.append(d2RegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) - nextIdx = n1 + 1 - - elif n2 == 1: - # print(n2, 'Row 2') - xAround.append(xRegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) - d2Around.append(d2RegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) - - for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) - - # right point on annulus - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2]) # KM - d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2] - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), vector.normalise(d2))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d2Around.append([rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) + # Smooth lower curvature + xLC = [] + d2LC = [] + for n2 in range(elementsAroundHalfOeso + 1, elementsCountAlong + 1): + xLC.append(xOuter[n2][int(len(xOuter[n2]) * 0.5)]) - # left point on annulus - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) # KM - d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) + for n in range(len(xLC) - 1): + d = findDerivativeBetweenPoints(xLC[n], xLC[n + 1]) + d2LC.append(d) + d2LC.append(d) - for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC, fixStartDirection=True) + # curvature - DONE - elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): - # print(n2, 'Before triple point + triple point') - # GC - xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) - d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) + # for m in range(len(xLC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLC[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LC[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 - # Row 2 right - xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) - d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) + # Smooth greater curvature + d2GC = [] + for n in range(len(xOesoToDuodGC) - 1): + d = findDerivativeBetweenPoints(xOesoToDuodGC[n], xOesoToDuodGC[n + 1]) + d2GC.append(d) + d2GC.append(d) + d2GC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2GC, fixStartDirection=True) - # Regular up right - for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + # for m in range(len(xOesoToDuodGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[m]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2GC[m]) + # nodeIdentifier += 1 - # Annulus right - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM - d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)] - if n2 <= int(elementsCountAroundOesophagus * 0.25): # Rotate to point towards duodenum - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), - vector.normalise(d2))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d2Around.append( - [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) - else: # just take d2 as-is cos we are going to remove this point later - d2Around.append(d2) + # Update d1 for upstream nodes + for n1 in range(1, len(xRow2Right)): + d1Outer[1][n1] = d2Loop2Right[idxSwitchToD1 + n1] + for n1 in range(1, len(xRow2Left)): + d1Outer[1][int(len(d1Outer[1]) * 0.5) + n1] = d2Loop2Left[n1 - 1] - # Annulus left - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM - d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + # Assemble d2 + d2Outer = [] + for n2 in range(elementsCountAlong + 1): + d2Around = [] + xAround = [] # KM + if n2 == 0: + # print(n2, 'GC') + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5)]) #KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(dSmoothLoopGCTriplePt) * 0.5)]) + + for n1 in range(len(xOuter[0]) - 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) + d2Around.append(d2RegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) + nextIdx = n1 + 1 + + elif n2 == 1: + # print(n2, 'Row 2') + xAround.append(xRegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) + d2Around.append(d2RegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) + + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + # right point on annulus + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2]) # KM + d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2] + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append([rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) - # Regular down left - for n1 in range(nextIdx + 1): + # left point on annulus + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) # KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) + + for n1 in range(nextIdx + 1): xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) - # Row 2 left - xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) - d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) + elif n2 > 1 and n2 < elementsAroundQuarterOeso + 2: + # print(n2, 'Before triple point + triple point') + # GC + xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + d2Around.append(d2GC[len(xOuter[0]) + n2]) + + # Row 2 right + xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) + d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) + + # Regular up right + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) + + # Annulus right + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterOeso else 0)]) # KM + d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterOeso else 0)] + if n2 <= elementsAroundQuarterOeso: # Rotate to point towards duodenum + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), + vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append( + [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) + else: # just take d2 as-is cos we are going to remove this point later + d2Around.append(d2) - # for m1 in range(len(d2Around)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Around[m1]) - # nodeIdentifier += 1 + # Annulus left + xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsAroundQuarterOeso else 0)]) # KM + d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsAroundQuarterOeso else 0)]) - elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): - # print(n2, 'Downstream of triple point') - # GC - xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) - d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) - - # Row 2 right - xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) - d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) - - # Regular up right - for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) - - if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: - # Annulus right - # print('between triple and 6 pt') - idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) - xAround.append(xLoopTripleTo6Pt[idx]) - if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: - d1 = dSmoothLoopTripleTo6Pt[idx] - d1Outer[n2][int(len(d1Outer[n2]) * 0.5)] = d1 - else: - d2Around.append(dSmoothLoopTripleTo6Pt[idx]) - - # Annulus left - need to rotate to point towards duodenum - xAround.append(xLoopTripleTo6Pt[-idx]) - # d2Around.append(dSmoothLoopTripleTo6Pt[-idx]) - d2 = dSmoothLoopTripleTo6Pt[-idx] - if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): - rotAxis = vector.normalise( - vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5 + 1)]), - vector.normalise(d2))) - else: # use d2 on previous overlapping point to rotate - rotAxis = vector.normalise( - vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d2Around.append( - [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in - range(3)]) - - elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: - # print('beyond 6 pt') - # LC - xAround.append(xLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) - d2Around.append(d2LC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) - - # Regular down left - for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + # Regular down left + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) - # Row 2 left - xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) - d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) + # Row 2 left + xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) + d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) - d2Outer.append(d2Around) + # for m1 in range(len(d2Around)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Around[m1]) + # nodeIdentifier += 1 - # remove triple point on both sides from downstream ring - n2Idx = int(elementsCountAroundOesophagus * 0.25 + 1) - n1Idx = int(len(xOuter[n2Idx]) * 0.5) - del xOuter[n2Idx][n1Idx: n1Idx + 2], d1Outer[n2Idx][n1Idx: n1Idx + 2], d2Outer[n2Idx][n1Idx: n1Idx + 2] + elif n2 > elementsAroundQuarterOeso + 1: + # print(n2, 'Downstream of triple point') + # GC + xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + d2Around.append(d2GC[len(xOuter[0]) + n2]) - d3UnitOuter = [] - for n2 in range(elementsCountAlong + 1): - d3Around = [] - for n1 in range(len(xOuter[n2])): - d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) - d3UnitOuter.append(d3Around) - - # for m2 in range(len(xOuter)): - # for m1 in range(len(xOuter[m2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[m2][m1]) - # nodeIdentifier += 1 - - # Calculate curvatures - # Curvatures along GC - xGC = [] - dGC = [] - norms = [] - for n1 in range(len(xOuter[0])): - xGC.append(xOuter[0][n1]) - dGC.append(d1Outer[0][n1]) - norms.append(d3UnitOuter[0][n1]) - for n2 in range(1, elementsCountAlong + 1): - xGC.append(xOuter[n2][0]) - dGC.append(d1Outer[n2][0] if n2 == 1 else d2Outer[n2][0]) - norms.append(d3UnitOuter[n2][0]) - curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 - - # for m1 in range(len(xGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 + # Row 2 right + xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) + d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) - # Curvature along rows adjacent to GC - calculate with left and use the same for right - norms = [] - xTest = [] - for n in range(int(len(xOuter[1]) * 0.5)): # d1s - xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM - norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) - for n2 in range(2, elementsCountAlong + 1): # d2s - xTest.append(xOuter[n2][-1]) # KM - norms.append(d3UnitOuter[n2][-1]) - curvatureAlong2Left = findCurvatureAlongLine(xLoop2Left, d2Loop2Left, norms) - - # for m1 in range(len(xTest)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTest[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, norms[m1]) - # nodeIdentifier += 1 + # Regular up right + for n1 in range(nextIdx, -1, -1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) - # Curvature along LC - xTest = [] # KM - norms = [] - for n in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): - xTest.append(xOuter[n][int(len(xOuter[n]) * 0.5)]) - norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) - curvatureAlongLC = findCurvatureAlongLine(xLC[1:], d2LC[1:], norms) + if n2 <= elementsAroundHalfOeso + 1: + # Annulus right + # print('between triple and 6 pt') + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsAroundQuarterOeso - 1) + xAround.append(xLoopTripleTo6Pt[idx]) + if n2 == elementsAroundHalfOeso + 1: + d1 = dSmoothLoopTripleTo6Pt[idx] + d1Outer[n2][int(len(d1Outer[n2]) * 0.5)] = d1 + else: + d2Around.append(dSmoothLoopTripleTo6Pt[idx]) + + # Annulus left - need to rotate to point towards duodenum + xAround.append(xLoopTripleTo6Pt[-idx]) + # d2Around.append(dSmoothLoopTripleTo6Pt[-idx]) + d2 = dSmoothLoopTripleTo6Pt[-idx] + if n2 < elementsAroundHalfOeso + 1: + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5 + 1)]), + vector.normalise(d2))) + else: # use d2 on previous overlapping point to rotate + rotAxis = vector.normalise( + vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) + d2Around.append( + [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in + range(3)]) + + elif n2 > elementsAroundHalfOeso + 1: + # print('beyond 6 pt') + # LC + xAround.append(xLC[n2 - (elementsAroundHalfOeso + 1)]) + d2Around.append(d2LC[n2 - (elementsAroundHalfOeso + 1)]) + + # Regular down left + for n1 in range(nextIdx + 1): + xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + + # Row 2 left + xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) + d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) + + d2Outer.append(d2Around) + + # remove triple point on both sides from downstream ring + n2Idx = elementsAroundQuarterOeso + 1 + n1Idx = int(len(xOuter[n2Idx]) * 0.5) + del xOuter[n2Idx][n1Idx: n1Idx + 2], d1Outer[n2Idx][n1Idx: n1Idx + 2], d2Outer[n2Idx][n1Idx: n1Idx + 2] + + d3UnitOuter = [] + for n2 in range(elementsCountAlong + 1): + d3Around = [] + for n1 in range(len(xOuter[n2])): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) + d3UnitOuter.append(d3Around) + + # for m2 in range(len(xOuter)): + # for m1 in range(len(xOuter[m2])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[m2][m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[m2][m1]) + # nodeIdentifier += 1 - # Curvature along path from triple point to 6 point junction - xTest = [] # KM - norms = [] - idxToAnnulus = int(elementsCountAroundDuodenum * 0.5 + 1) - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][: idxToAnnulus] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][:idxToAnnulus] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25)): - idx = int(elementsCountAroundOesophagus * 0.25) + 2 + n2 - if idx < (elementsCountAroundOesophagus * 0.5) + 1: - xTest.append(xOuter[idx][idxToAnnulus - 1]) - norms.append(d3UnitOuter[idx][idxToAnnulus - 1]) - xTest += xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ - xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ - d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): - idx = int(elementsCountAroundOesophagus * 0.5) - n2 - xTest.append(xOuter[idx][idxToAnnulus]) - norms.append(d3UnitOuter[idx][idxToAnnulus]) - - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] - - curvatureLoopTripleTo6Pt = findCurvatureAroundLoop(xLoopTripleTo6Pt, dSmoothLoopTripleTo6Pt, norms) - - # Curvature along path from GC to triple point - xTest = [] # KM + # Calculate curvatures + # Curvatures along GC + xGC = [] + dGC = [] + norms = [] + for n1 in range(len(xOuter[0])): + xGC.append(xOuter[0][n1]) + dGC.append(d1Outer[0][n1]) + norms.append(d3UnitOuter[0][n1]) + for n2 in range(1, elementsCountAlong + 1): + xGC.append(xOuter[n2][0]) + dGC.append(d1Outer[n2][0] if n2 == 1 else d2Outer[n2][0]) + norms.append(d3UnitOuter[n2][0]) + curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 + + # for m1 in range(len(xGC)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + # Curvature along rows adjacent to GC - calculate with left and use the same for right + norms = [] + xTest = [] + for n in range(int(len(xOuter[1]) * 0.5)): # d1s + xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM + norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) + for n2 in range(2, elementsCountAlong + 1): # d2s + xTest.append(xOuter[n2][-1]) # KM + norms.append(d3UnitOuter[n2][-1]) + curvatureAlong2Left = findCurvatureAlongLine(xLoop2Left, d2Loop2Left, norms) + + # for m1 in range(len(xTest)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTest[m1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, norms[m1]) + # nodeIdentifier += 1 + + # Curvature along LC + xTest = [] # KM + norms = [] + for n in range(elementsAroundHalfOeso + 1, elementsCountAlong + 1): + xTest.append(xOuter[n][int(len(xOuter[n]) * 0.5)]) + norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) + curvatureAlongLC = findCurvatureAlongLine(xLC[1:], d2LC[1:], norms) + + # Curvature along path from triple point to 6 point junction + xTest = [] # KM + norms = [] + idxToAnnulus = elementsAroundHalfDuod + 1 + xTest += xOuter[elementsAroundQuarterOeso][: idxToAnnulus] + norms += d3UnitOuter[elementsAroundQuarterOeso][:idxToAnnulus] + + for n2 in range(elementsAroundQuarterOeso): + idx = elementsAroundQuarterOeso + 2 + n2 + if idx < elementsAroundHalfOeso + 1: + xTest.append(xOuter[idx][idxToAnnulus - 1]) + norms.append(d3UnitOuter[idx][idxToAnnulus - 1]) + xTest += xOuter[elementsAroundHalfOeso + 1][idxToAnnulus - 1:] + \ + xOuter[elementsAroundHalfOeso + 1][: idxToAnnulus] + norms += d3UnitOuter[elementsAroundHalfOeso + 1][idxToAnnulus - 1:] + \ + d3UnitOuter[elementsAroundHalfOeso + 1][: idxToAnnulus] + + for n2 in range(elementsAroundQuarterOeso - 1): + idx = elementsAroundHalfOeso - n2 + xTest.append(xOuter[idx][idxToAnnulus]) + norms.append(d3UnitOuter[idx][idxToAnnulus]) + + xTest += xOuter[elementsAroundQuarterOeso][idxToAnnulus:] + norms += d3UnitOuter[elementsAroundQuarterOeso][idxToAnnulus:] + + curvatureLoopTripleTo6Pt = findCurvatureAroundLoop(xLoopTripleTo6Pt, dSmoothLoopTripleTo6Pt, norms) + + # Curvature along path from GC to triple point + xTest = [] # KM + norms = [] + xTest += xOuter[elementsAroundQuarterOeso + 1][:idxToAnnulus - 1] + norms += d3UnitOuter[elementsAroundQuarterOeso + 1][:idxToAnnulus - 1] + + for n2 in range(elementsAroundQuarterOeso): + idx = elementsAroundQuarterOeso - n2 + xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5)]) + norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5)]) + xTest.append(xOuter[0][0]) + norms.append(d3UnitOuter[0][0]) + for n2 in range(1, elementsAroundQuarterOeso + 1): + xTest.append(xOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + norms.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + xTest += xOuter[elementsAroundQuarterOeso + 1][idxToAnnulus - 1:] + norms += d3UnitOuter[elementsAroundQuarterOeso + 1][idxToAnnulus - 1:] + curvatureLoopGCTriplePt = findCurvatureAroundLoop(xLoopGCTriplePt, dSmoothLoopGCTriplePt, norms) + + # Curvature around regular loops + curvatureRegularLoops = [] + for n1 in range(elementsAroundHalfDuod - 2): + xTest = [] norms = [] - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25)): - idx = int(elementsCountAroundOesophagus * 0.25 - n2) - xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5)]) - norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5)]) - xTest.append(xOuter[0][0]) - norms.append(d3UnitOuter[0][0]) - for n2 in range(1, int(elementsCountAroundOesophagus * 0.25) + 1): - xTest.append(xOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) - norms.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] - curvatureLoopGCTriplePt = findCurvatureAroundLoop(xLoopGCTriplePt, dSmoothLoopGCTriplePt, norms) - - # Curvature around regular loops - curvatureRegularLoops = [] - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): + for n2 in range(elementsCountAlong): + idx = -(1 + n2) + xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) + if n1 < elementsAroundHalfDuod - 3: + xTest.append(xOuter[0][(n1 + 1)]) + norms.append(d3UnitOuter[0][n1 + 1]) + else: + xTest.append(xOuter[idx][0]) + norms.append(d3UnitOuter[idx][0]) + for n2 in range(elementsCountAlong): + xTest.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfOeso else 2))]) + norms.append(d3UnitOuter[n2 + 1][int( + len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfOeso else 2))]) + curvatureLoop = findCurvatureAlongLine(xRegularLoops[n1], d2RegularOrderedLoops[n1], norms) + curvatureRegularLoops.append(curvatureLoop) + + # Assemble curvatures + d1Curvature = [] + d2Curvature = [] + countUp = 0 + countDown = 0 + for n2 in range(elementsCountAlong + 1): + d1CurvatureAround = [] + d2CurvatureAround = [] + if n2 == 0: + # print(n2, 'GC') + for i in range(elementsAroundHalfDuod - 2): + d1CurvatureAround.append(curvatureAlongGC[i]) + + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5)]) + for n1 in range(len(xOuter[0]) - 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5)]) + nextIdx = n1 + 1 + + elif n2 == 1: + # print(n2, 'Row 2') + d1CurvatureAround.append(curvatureAlongGC[i + n2]) xTest = [] - norms = [] - for n2 in range(elementsCountAlong): - idx = -(1 + n2) - xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - if n1 < int(elementsCountAroundDuodenum * 0.5) - 3: - xTest.append(xOuter[0][(n1 + 1)]) - norms.append(d3UnitOuter[0][n1 + 1]) - else: - xTest.append(xOuter[idx][0]) - norms.append(d3UnitOuter[idx][0]) - for n2 in range(elementsCountAlong): - xTest.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) - norms.append(d3UnitOuter[n2 + 1][int( - len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) - curvatureLoop = findCurvatureAlongLine(xRegularLoops[n1], d2RegularOrderedLoops[n1], norms) - curvatureRegularLoops.append(curvatureLoop) - - # Assemble curvatures - d1Curvature = [] - d2Curvature = [] - countUp = 0 - countDown = 0 - for n2 in range(elementsCountAlong + 1): - d1CurvatureAround = [] - d2CurvatureAround = [] - if n2 == 0: - # print(n2, 'GC') - for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): - d1CurvatureAround.append(curvatureAlongGC[i]) - - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5)]) - for n1 in range(len(xOuter[0]) - 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5)]) - nextIdx = n1 + 1 - - elif n2 == 1: - # print(n2, 'Row 2') - d1CurvatureAround.append(curvatureAlongGC[i + n2]) - xTest = [] - dTest = [] - for n in range(int(len(xOuter[1]) * 0.5) - 1, -1, -1): - d1CurvatureAround.append(curvatureAlong2Left[n]) - d1CurvatureAround += curvatureAlong2Left[:int(len(xOuter[1]) * 0.5)] - xTest = xLoop2Left[:int(len(xOuter[1]) * 0.5)] - dTest = d2Loop2Left[:int(len(xOuter[1]) * 0.5)] - - d2CurvatureAround.append(curvatureRegularLoops[nextIdx][int(len(curvatureRegularLoops[nextIdx]) * 0.5)]) - for n1 in range(nextIdx, -1, -1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) - # right point on annulus - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) - n2]) - # left point on annulus - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2]) - for n1 in range(nextIdx + 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) - - elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): - # print(n2, 'Before triple point + triple point') - xAround = xOuter[n2] - if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt - # smooth d1 around - Make into function? - d1Around = d1Outer[n2] - norms = d3UnitOuter[n2] - 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 = norms[int(len(d1Around) * 0.5 + 1):] + norms[: 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):] - - elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation - # take smoothed d1 from dSmoothTripleTo6Pt - d1CurvatureAround = curvatureLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ - curvatureLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5):] - - elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation - # take smoothed d1 from dSmoothGCToTriplePt - d1CurvatureAround = curvatureLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ - curvatureLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5):] - - # GC - d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) - # Row 2 right - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - # Regular up right - for n1 in range(nextIdx, -1, -1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + dTest = [] + for n in range(int(len(xOuter[1]) * 0.5) - 1, -1, -1): + d1CurvatureAround.append(curvatureAlong2Left[n]) + d1CurvatureAround += curvatureAlong2Left[:int(len(xOuter[1]) * 0.5)] + xTest = xLoop2Left[:int(len(xOuter[1]) * 0.5)] + dTest = d2Loop2Left[:int(len(xOuter[1]) * 0.5)] + + d2CurvatureAround.append(curvatureRegularLoops[nextIdx][int(len(curvatureRegularLoops[nextIdx]) * 0.5)]) + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + # right point on annulus + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) - n2]) + # left point on annulus + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2]) + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + + elif n2 > 1 and n2 < elementsAroundQuarterOeso + 2: + # print(n2, 'Before triple point + triple point') + xAround = xOuter[n2] + if n2 < elementsAroundQuarterOeso: # upstream of triple pt + # smooth d1 around - Make into function? + d1Around = d1Outer[n2] + norms = d3UnitOuter[n2] + 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 = norms[int(len(d1Around) * 0.5 + 1):] + norms[: 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):] + + elif n2 == elementsAroundQuarterOeso: # upstream bifurcation + # take smoothed d1 from dSmoothTripleTo6Pt + d1CurvatureAround = curvatureLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ + curvatureLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5):] + + elif n2 > elementsAroundQuarterOeso: # downstream bifurcation + # take smoothed d1 from dSmoothGCToTriplePt + d1CurvatureAround = curvatureLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ + curvatureLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5):] + + # GC + d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) + # Row 2 right + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + # Regular up right + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + # Annulus right + d2CurvatureAround.append(curvatureLoopGCTriplePt[ + int(len(curvatureLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterOeso else 0)]) + # Annulus left + d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2 - ( + 1 if n2 > elementsAroundQuarterOeso else 0)]) + # Regular down left + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + # Row 2 left + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + + elif n2 > elementsAroundQuarterOeso + 1: + # print(n2, 'Downstream of triple point') + xAround = xOuter[n2] + d1Around = d1Outer[n2] + normsAround = d3UnitOuter[n2] + + # smooth d1 around - Make into function? + if n2 < elementsAroundHalfOeso + 1: + 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(normsAround) * 0.5 + 1):] + normsAround[: int(len(normsAround) * 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):] + + elif n2 == elementsAroundHalfOeso + 1: # 6 point junction ring + # take smoothed d1 from dSmoothedTripleTo6Pt + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsAroundQuarterOeso + len( + xAlongAround[junctionIdx]) * 0.5) + endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 + d1CurvatureAround = curvatureLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ + curvatureLoopTripleTo6Pt[startLeftIdx: startRightIdx] + + if n2 > elementsAroundHalfOeso + 1: # closed rings beyond 6 point junction + 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(normsAround) * 0.5 + 1):] + normsAround[ : int(len(normsAround) * 0.5 + 1)] + curvature = findCurvatureAroundLoop(xLoop, d1Loop, normsLoop) + # Rearrange to correct order + d1CurvatureAround = curvature[int(len(xLoop) * 0.5) - 1:] + curvature[: int(len(xAround) * 0.5) - 1] + + # GC + d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) + # Row 2 right + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + # Regular up right + for n1 in range(nextIdx, -1, -1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) + if n2 <= elementsAroundHalfOeso + 1: # Annulus right - d2CurvatureAround.append(curvatureLoopGCTriplePt[ - int(len(curvatureLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) + # print('between triple and 6 pt') + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsAroundQuarterOeso - 1) + if n2 == elementsAroundHalfOeso + 1: + d1CurvatureAround[int(len(d1Outer[n2]) * 0.5)] = curvatureLoopTripleTo6Pt[idx] + else: + d2CurvatureAround.append(curvatureLoopTripleTo6Pt[idx]) # Annulus left - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2 - ( - 1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) - # Regular down left - for n1 in range(nextIdx + 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) - # Row 2 left - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - - elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): - # print(n2, 'Downstream of triple point') - xAround = xOuter[n2] - d1Around = d1Outer[n2] - normsAround = d3UnitOuter[n2] - - # smooth d1 around - Make into function? - if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): - 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(normsAround) * 0.5 + 1):] + normsAround[: int(len(normsAround) * 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):] - - elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring - # take smoothed d1 from dSmoothedTripleTo6Pt - startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len( - xAlongAround[junctionIdx]) * 0.5) - endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - d1CurvatureAround = curvatureLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ - curvatureLoopTripleTo6Pt[startLeftIdx: startRightIdx] - - if n2 > int(elementsCountAroundOesophagus * 0.5 + 1): # closed rings beyond 6 point junction - 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(normsAround) * 0.5 + 1):] + normsAround[ : int(len(normsAround) * 0.5 + 1)] - curvature = findCurvatureAroundLoop(xLoop, d1Loop, normsLoop) - # Rearrange to correct order - d1CurvatureAround = curvature[int(len(xLoop) * 0.5) - 1:] + curvature[: int(len(xAround) * 0.5) - 1] - - # GC - d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) - # Row 2 right - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - # Regular up right - for n1 in range(nextIdx, -1, -1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) - if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: - # Annulus right - # print('between triple and 6 pt') - idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) - if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: - d1CurvatureAround[int(len(d1Outer[n2]) * 0.5)] = curvatureLoopTripleTo6Pt[idx] - else: - d2CurvatureAround.append(curvatureLoopTripleTo6Pt[idx]) - # Annulus left - d2CurvatureAround.append(curvatureLoopTripleTo6Pt[-idx]) - elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: - # print('beyond 6 pt') - # LC - d2CurvatureAround.append(curvatureAlongLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1) - 1]) - # Regular down left - for n1 in range(nextIdx + 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) - # Row 2 left - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - - d1Curvature.append(d1CurvatureAround) - d2Curvature.append(d2CurvatureAround) - - # Create inner nodes - xList = [] - d1List = [] - d2List = [] - d3List = [] - nodeIdx = bodyStartNode - - idxMat = [] - - for n2 in range(elementsCountAlong + 1): - idxThroughWall = [] - for n3 in range(elementsCountThroughWall + 1): - xi3 = 1 / elementsCountThroughWall * n3 - idxAround = [] - for n1 in range(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 * xi3 * d1Curvature[n2][n1] - d1 = [factor * c for c in d1Outer[n2][n1]] - d1List.append(d1) - - # d2 - factor = 1.0 - wallThickness * xi3 * d2Curvature[n2][n1] - d2 = [factor * c for c in d2Outer[n2][n1]] - d2List.append(d2) - - # d3 - d3 = [c * wallThickness / elementsCountThroughWall for c in norm] - d3List.append(d3) - - idxAround.append(nodeIdx) - nodeIdx += 1 - - idxThroughWall.append(idxAround) - idxMat.append(idxThroughWall) + d2CurvatureAround.append(curvatureLoopTripleTo6Pt[-idx]) + elif n2 > elementsAroundHalfOeso + 1: + # print('beyond 6 pt') + # LC + d2CurvatureAround.append(curvatureAlongLC[n2 - (elementsAroundHalfOeso + 1) - 1]) + # Regular down left + for n1 in range(nextIdx + 1): + d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) + # Row 2 left + d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) + + d1Curvature.append(d1CurvatureAround) + d2Curvature.append(d2CurvatureAround) + + # Create inner nodes + xList = [] + d1List = [] + d2List = [] + d3List = [] + nodeIdx = bodyStartNode + + idxMat = [] + + for n2 in range(elementsCountAlong + 1): + idxThroughWall = [] + for n3 in range(elementsCountThroughWall + 1): + xi3 = 1 / elementsCountThroughWall * n3 + idxAround = [] + for n1 in range(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 / elementsCountThroughWall for c in norm] + d3List.append(d3) + + idxAround.append(nodeIdx) + nodeIdx += 1 + + idxThroughWall.append(idxAround) + idxMat.append(idxThroughWall) + if makeStomach: for n2 in range(len(xList)): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) @@ -1964,7 +2189,7 @@ def generateBaseMesh(cls, region, options): elementIdentifier = nextElementIdentifier - for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2): + for e2 in range(elementsAroundQuarterOeso + 2): # Row 1 if e2 == 0: startNode = bodyStartNode @@ -2117,7 +2342,7 @@ def generateBaseMesh(cls, region, options): elementIdentifier += 1 # Additional elements between second and upstream bifurcation ring - elif e2 > 1 and e2 < int(elementsCountAroundOesophagus * 0.25): + elif e2 > 1 and e2 < elementsAroundQuarterOeso: startNode = bodyStartNode for e in range(e2): startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) @@ -2148,7 +2373,7 @@ def generateBaseMesh(cls, region, options): elementIdentifier += 1 # Upstream bifurcation - elif e2 == int(elementsCountAroundOesophagus * 0.25): + elif e2 == elementsAroundQuarterOeso: startNode = bodyStartNode for e in range(e2): startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) @@ -2204,7 +2429,7 @@ def generateBaseMesh(cls, region, options): elementIdentifier += 1 # Downstream bifurcation - elif e2 == int(elementsCountAroundOesophagus * 0.25) + 1: + elif e2 == elementsAroundQuarterOeso + 1: startNode = bodyStartNode for e in range(e2): startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) @@ -2273,8 +2498,7 @@ def generateBaseMesh(cls, region, options): elementIdentifier += 1 # Rows between downstream and penultimate ring - for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2, - int(elementsCountAroundOesophagus * 0.5)): + for e2 in range(elementsAroundQuarterOeso + 2, elementsAroundHalfOeso): startNode = bodyStartNode for e in range(e2): startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) @@ -2300,7 +2524,7 @@ def generateBaseMesh(cls, region, options): elementIdentifier = elementIdentifier + 1 # Penultimate row connecting to annulus and beyond - for e2 in range(int(elementsCountAroundOesophagus * 0.5), elementsCountAlong): + for e2 in range(elementsAroundHalfOeso, elementsCountAlong): startNode = bodyStartNode for e in range(e2): startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) @@ -2311,11 +2535,11 @@ def generateBaseMesh(cls, region, options): for e3 in range(elementsCountThroughWall): for e1 in range( - elementsCountAround1 - (1 if e2 == int(elementsCountAroundOesophagus * 0.5) else 0)): + elementsCountAround1 - (1 if e2 == elementsAroundHalfOeso else 0)): scaleFactors = [] eft1 = eftStandard elementtemplate1 = elementtemplateStandard - if e2 == int(elementsCountAroundOesophagus * 0.5): + if e2 == elementsAroundHalfOeso: bni11 = startNode + e3 * elementsCountAround1 + e1 + ( 0 if e1 < int(elementsCountAround1 * 0.5) else 1) bni12 = startNode + e3 * elementsCountAround1 + (e1 + ( @@ -2339,7 +2563,7 @@ def generateBaseMesh(cls, region, options): bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2, bni22 + elementsCountAround2] - if e2 == int(elementsCountAroundOesophagus * 0.5) + 1: + if e2 == elementsAroundHalfOeso + 1: if e1 == int(elementsCountAround1 * 0.5) - 1: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() @@ -2363,26 +2587,26 @@ def generateBaseMesh(cls, region, options): # Annulus # Assemble endPoints for annulus - endPoints_x = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endPoints_d1 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endPoints_d2 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endNode_Id = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endDerivativesMap = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] + endPoints_x = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] + endPoints_d1 = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] + endPoints_d2 = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] + endNode_Id = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] + endDerivativesMap = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] endProportions = [] thicknessIdx = [0, -1] - for nAround in range(elementsCountAroundOesophagus): + for nAround in range(elementsCountAroundOeso): for n3 in range(len(thicknessIdx)): if nAround == 0: idx = idxMat[nAround][thicknessIdx[n3]][0] - elif nAround <= int(elementsCountAroundOesophagus * 0.25): + elif nAround <= elementsAroundQuarterOeso: idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] - elif int(elementsCountAroundOesophagus * 0.25) < nAround < int(elementsCountAroundOesophagus * 0.5): + elif elementsAroundQuarterOeso < nAround < elementsAroundHalfOeso: idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] - elif nAround == int(elementsCountAroundOesophagus * 0.5): + elif nAround == elementsAroundHalfOeso: idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] - elif nAround > int(elementsCountAroundOesophagus * 0.5): - idx = endNode_Id[n3][int(elementsCountAroundOesophagus * 0.5) - (nAround - int(elementsCountAroundOesophagus * 0.5))] + 1 + elif nAround > elementsAroundHalfOeso: + idx = endNode_Id[n3][elementsAroundHalfOeso - (nAround - elementsAroundHalfOeso)] + 1 endPoints_x[n3][nAround] = xList[idx - bodyStartNode] endPoints_d1[n3][nAround] = d1List[idx - bodyStartNode] @@ -2395,22 +2619,22 @@ def generateBaseMesh(cls, region, options): # print(xCheck, endPoints_x[n3][nAround]) # KM endProportions.append(trackSurfaceStomach.getProportion(endPosition)) - for nAround in range(elementsCountAroundOesophagus): + for nAround in range(elementsCountAroundOeso): if nAround == 0: endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) - elif nAround == int(elementsCountAroundOesophagus * 0.25): + elif nAround == elementsAroundQuarterOeso: endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) - elif 0 < nAround < int(elementsCountAroundOesophagus * 0.5): + elif 0 < nAround < elementsAroundHalfOeso: endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == int(elementsCountAroundOesophagus * 0.5): + elif nAround == elementsAroundHalfOeso: endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - elif nAround == int(elementsCountAroundOesophagus * 0.75): + elif nAround == int(elementsCountAroundOeso * 0.75): endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - elif int(elementsCountAroundOesophagus * 0.5) < nAround < elementsCountAroundOesophagus: + elif elementsAroundHalfOeso < nAround < elementsCountAroundOeso: endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) startProportions = [] - for n in range(elementsCountAroundOesophagus): + for n in range(elementsCountAroundOeso): startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( @@ -2421,13 +2645,13 @@ def generateBaseMesh(cls, region, options): startProportions = startProportions, endProportions = endProportions, rescaleStartDerivatives = True, rescaleEndDerivatives = True) - if trackSurface: + if showTrackSurface: for n2 in range(len(xTrackSurface)): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TrackSurface[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TrackSurface[n2]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) nodeIdentifier += 1 @@ -2441,6 +2665,26 @@ def generateBaseMesh(cls, region, options): coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, sd3[n2]) nodeIdentifier += 1 + # nodeIdentifier = 10000 + # for n1 in range(len(xStarts)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xStarts[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Starts[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + # + # for n1 in range(len(xEnds)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xEnds[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Ends[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) + # nodeIdentifier += 1 + + fm.endChange() annotationGroup = [] @@ -2504,6 +2748,7 @@ def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, start trackSurface.createHermiteCurvePoints(startProportion1, startProportion2, endProportion1, endProportion2, elementsOut, startDerivative, endDerivative, curveMode) + xSampled, dSampled = trackSurface.resampleHermiteCurvePointsSmooth(mx, md2, md1, md3, mProportions, startDerivativeMagnitude, endDerivativeMagnitude)[0:2] From 861e3c6fa4f1ac883413d3728e782cc3005da3ed Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Thu, 8 Apr 2021 14:48:16 +1200 Subject: [PATCH 05/38] Update parameters for rat and human --- .../meshtypes/meshtype_3d_stomach1.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index e15b4d88..8134a4a1 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -50,19 +50,19 @@ class MeshType_3d_stomach1(Scaffold_base): Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ [[70.8, 72.3, 0.0], [-15.1, -43.8, 0.0], [37.3, -18.7, 0.0], [2.2, 7.2, 0.0], [0.0, 0.0, 38.7], [0.0, 0.0, 4.5]], - [[51.1, 30.7, 0.0], [-21.4, -33.7, 0.0], [33.9, -17.5, 0.0], [-9.0, -4.7, 0.0], [0.0, 0.0, 41.4], + [[51.1, 30.7, 0.0], [-21.4, -33.7, 0.0], [33.9, -17.5, 0.0], [-9.0, -4.8, 0.0], [0.0, 0.0, 41.4], [0.0, 0.0, 0.9]], - [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [20.5, -27.0, 0.0], [-16.5, -6.7, 0.0], [0.0, 0.0, 40.9], + [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [20.5, -27.0, 0.0], [-17.1, -3.5, 0.0], [0.0, 0.0, 40.9], [0.0, 0.0, -5.0]], - [[-0.3, -5.8, 0.0], [-28.0, -2.6, 0.0], [1.5, -31.5, 0.0], [-14.2, 3.8, 0.0], [0.0, 0.0, 32.3], + [[-0.3, -5.8, 0.0], [-28.0, -2.6, 0.0], [0.4, -25.7, 0.0], [-12.6, 3.7, 0.0], [0.0, 0.0, 32.3], [0.0, 0.0, -9.4]], - [[-26.5, -2.9, 0.0], [-20.6, 8.0, 0.0], [-8.5, -20.3, 0.0], [-8.1, 10.9, 0.0], [0.0, 0.0, 22.1], + [[-26.5, -2.9, 0.0], [-20.6, 8.0, 0.0], [-5.4, -19.9, 0.0], [-5.6, 7.7, 0.0], [0.0, 0.0, 22.1], [0.0, 0.0, -6.8]], - [[-40.6, 7.4, 0.0], [-11.0, 12.5, 0.0], [-15.3, -9.6, 0.0], [-0.1, 8.5, 0.0], [0.0, 0.0, 17.6], + [[-40.6, 7.4, 0.0], [-11.0, 12.5, 0.0], [-10.9, -10.9, 0.0], [-1.3, 7.9, 0.0], [0.0, 0.0, 17.6], [0.0, 0.0, -5.9]], - [[-48.1, 21.0, 0.0], [-6.4, 15.7, 0.0], [-9.4, -3.0, 0.0], [2.3, 3.1, 0.0], [0.0, 0.0, 10.5], + [[-48.1, 21.0, 0.0], [-6.4, 15.7, 0.0], [-8.4, -4.0, 0.0], [0.1, 4.9, 0.0], [0.0, 0.0, 10.5], [0.0, 0.0, -3.1]], - [[-52.9, 38.6, 0.0], [-3.2, 19.3, 0.0], [-11.3, -4.0, 0.0], [-6.1, -5.1, 0.0], [0.0, 0.0, 12.0], + [[-52.9, 38.6, 0.0], [-3.2, 19.3, 0.0], [-11.2, -1.5, 0.0], [-5.7, 0.1, 0.0], [0.0, 0.0, 12.0], [0.0, 0.0, 6.1]]]) }), @@ -155,8 +155,8 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of elements through wall': 1, # not implemented for > 1 'Unit scale': 1.0, 'Outlet': False, - 'Ostium diameter': 5.0, - 'Ostium length': 5.0, + 'Ostium diameter': 4.0, + 'Ostium length': 3.5, 'Ostium wall thickness': 0.5, 'Ostium inter-vessel distance': 0.0, 'Ostium inter-vessel height': 0.0, @@ -1392,7 +1392,7 @@ def generateBaseMesh(cls, region, options): # Resample loop before 6 point junction for n in range(1, elementsCountAroundDuod + 1): - if elementsAroundHalfDuod <= n <=elementsAroundHalfDuod + 1: + if elementsAroundHalfDuod <= n <= elementsAroundHalfDuod + 1: pass else: if elementsCountAroundOeso > 8: From cdbd95e7216f7cd46ad9863987316dd1b01e69f5 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 13 Apr 2021 15:09:16 +1200 Subject: [PATCH 06/38] Add annotation groups --- src/scaffoldmaker/annotation/stomach_terms.py | 30 ++ .../meshtypes/meshtype_3d_stomach1.py | 331 +++++++++++++----- 2 files changed, 268 insertions(+), 93 deletions(-) create mode 100644 src/scaffoldmaker/annotation/stomach_terms.py diff --git a/src/scaffoldmaker/annotation/stomach_terms.py b/src/scaffoldmaker/annotation/stomach_terms.py new file mode 100644 index 00000000..ed1ba35f --- /dev/null +++ b/src/scaffoldmaker/annotation/stomach_terms.py @@ -0,0 +1,30 @@ +""" +Common resource for stomach annotation terms. +""" + +# convention: preferred name, preferred id, followed by any other ids and alternative names +stomach_terms = [ + ( "body of stomach", "UBERON:0001161", " FMA:14560", "ILX:0724929"), + ( "cardia of stomach", "UBERON:0001162", " FMA:14561", "ILX:0729096"), + ( "duodenum", "UBERON:0002114", " FMA:7206", "ILX:0726125"), + ( "esophagus", "UBERON:0001043", "FMA: 7131", "ILX:0735017"), + ( "esophagogastric junction", "UBERON:0007650", "FMA: 9434", "ILX:0733910"), + ( "forestomach-glandular stomach junction", "UBERON:0012270", "ILX:0729974"), + ( "fundus of stomach", "UBERON:0001160", " FMA:14559", "ILX:0724443"), + ( "greater curvature of stomach", "UBERON:0001164", " FMA:14574", "ILX:0724395"), + ( "lesser curvature of stomach", "UBERON:0001163", " FMA:14572", "ILX:0733753"), + ( "pyloric antrum", "UBERON:0001165", " FMA:14579", "ILX:0728672"), + ( "pylorus", "UBERON:0001166", " FMA:14581", "ILX:0734150"), + ( "stomach", "UBERON:0000945", "FMA:7148", "ILX:0736697") + ] + +def get_stomach_term(name : str): + """ + Find term by matching name to any identifier held for a term. + Raise exception if name not found. + :return ( preferred name, preferred id ) + """ + for term in stomach_terms: + if name in term: + return ( term[0], term[1] ) + raise NameError("Stomach annotation term '" + name + "' not found.") diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 8134a4a1..8f6f9822 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -7,6 +7,8 @@ from __future__ import division import math import copy +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups +from scaffoldmaker.annotation.stomach_terms import get_stomach_term from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates from opencmiss.zinc.element import Element from opencmiss.zinc.field import Field @@ -46,51 +48,108 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of elements': 7 }, 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[70.8, 72.3, 0.0], [-15.1, -43.8, 0.0], [37.3, -18.7, 0.0], [2.2, 7.2, 0.0], [0.0, 0.0, 38.7], - [0.0, 0.0, 4.5]], - [[51.1, 30.7, 0.0], [-21.4, -33.7, 0.0], [33.9, -17.5, 0.0], [-9.0, -4.8, 0.0], [0.0, 0.0, 41.4], - [0.0, 0.0, 0.9]], - [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [20.5, -27.0, 0.0], [-17.1, -3.5, 0.0], [0.0, 0.0, 40.9], - [0.0, 0.0, -5.0]], - [[-0.3, -5.8, 0.0], [-28.0, -2.6, 0.0], [0.4, -25.7, 0.0], [-12.6, 3.7, 0.0], [0.0, 0.0, 32.3], - [0.0, 0.0, -9.4]], - [[-26.5, -2.9, 0.0], [-20.6, 8.0, 0.0], [-5.4, -19.9, 0.0], [-5.6, 7.7, 0.0], [0.0, 0.0, 22.1], - [0.0, 0.0, -6.8]], - [[-40.6, 7.4, 0.0], [-11.0, 12.5, 0.0], [-10.9, -10.9, 0.0], [-1.3, 7.9, 0.0], [0.0, 0.0, 17.6], - [0.0, 0.0, -5.9]], - [[-48.1, 21.0, 0.0], [-6.4, 15.7, 0.0], [-8.4, -4.0, 0.0], [0.1, 4.9, 0.0], [0.0, 0.0, 10.5], - [0.0, 0.0, -3.1]], - [[-52.9, 38.6, 0.0], [-3.2, 19.3, 0.0], [-11.2, -1.5, 0.0], [-5.7, 0.1, 0.0], [0.0, 0.0, 12.0], - [0.0, 0.0, 6.1]]]) - - }), + [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], [ + [ [ 70.8, 72.3, 0.0 ], [ -15.1, -43.8, 0.0 ], [ 37.3, -18.7, 0.0 ], [ 2.2, 7.2, 0.0 ], [ 0.0, 0.0, 38.7 ], [ 0.0, 0.0, 4.5 ] ], + [ [ 51.1, 30.7, 0.0 ], [ -21.4, -33.7, 0.0 ], [ 33.9, -17.5, 0.0 ], [ -9.0, -4.8, 0.0 ], [ 0.0, 0.0, 41.4 ], [ 0.0, 0.0, 0.9 ] ], + [ [ 27.8, 2.7, 0.0 ], [ -27.7, -18.4, 0.0 ], [ 20.5, -27.0, 0.0 ], [-17.1, -3.5, 0.0 ], [ 0.0, 0.0, 40.9 ], [ 0.0, 0.0, -5.0 ] ], + [ [ -0.3, -5.8, 0.0 ], [ -28.0, -2.6, 0.0 ], [ 0.4, -25.7, 0.0 ], [-12.6, 3.7, 0.0 ], [ 0.0, 0.0, 32.3 ], [ 0.0, 0.0, -9.4 ] ], + [ [ -26.5, -2.9, 0.0 ], [ -20.6, 8.0, 0.0 ], [ -5.4, -19.9, 0.0 ], [ -5.6, 7.7, 0.0 ], [ 0.0, 0.0, 22.1 ], [ 0.0, 0.0, -6.8 ] ], + [ [ -40.6, 7.4, 0.0 ], [ -11.0, 12.5, 0.0 ], [ -10.9, -10.9, 0.0 ], [ -1.3, 7.9, 0.0 ], [ 0.0, 0.0, 17.6 ], [ 0.0, 0.0, -5.9 ] ], + [ [ -48.1, 21.0, 0.0 ], [ -6.4, 15.7, 0.0 ], [ -8.4, -4.0, 0.0 ], [ 0.1, 4.9, 0.0 ], [ 0.0, 0.0, 10.5 ], [ 0.0, 0.0, -3.1 ] ], + [ [ -52.9, 38.6, 0.0 ], [ -3.2, 19.3, 0.0 ], [ -11.2, -1.5, 0.0 ], [ -5.7, 0.1, 0.0 ], [ 0.0, 0.0, 12.0 ], [ 0.0, 0.0, 6.1 ] ] ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1', + 'name': get_stomach_term('fundus of stomach')[0], + 'ontId': get_stomach_term('fundus of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '2-3', + 'name': get_stomach_term('body of stomach')[0], + 'ontId': get_stomach_term('body of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '4-5', + 'name': get_stomach_term('pyloric antrum')[0], + 'ontId': get_stomach_term('pyloric antrum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '6', + 'name': get_stomach_term('pylorus')[0], + 'ontId': get_stomach_term('pylorus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '7', + 'name': get_stomach_term('duodenum')[0], + 'ontId': get_stomach_term('duodenum')[1] + }] + }), 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 6 + 'Number of elements': 7 }, 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[12.4, 11.9, 0.0], [2.3, -12.3, 0.0], [8.7, -1.4, 0.0], [0.5, -3.7, 0.0], [0.0, 0.0, 7.4], - [0.0, 0.0, 1.6]], - [[9.5, -0.2, 0.0], [-6.0, -9.6, 0.0], [6.6, -5.1, 0.0], [-3.9, -4.3, 0.0], [0.0, 0.0, 8.5], - [0.0, 0.0, 0.7]], - [[2.3, -5.2, 0.0], [-9.3, -2.2, 0.0], [2.1, -9.1, -0.0], [-6.4, -1.6, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, -0.1]], - [[-7.8, -3.9, 0.0], [-7.5, 4.2, 0.0], [-6.0, -8.0, 0.0], [-3.4, 3.4, 0.0], [0.0, 0.0, 8.1], - [0.0, 0.0, -1.5]], - [[-11.7, 1.7, 0.0], [-1.7, 7.2, 0.0], [-6.4, -3.5, 0.0], [1.4, 4.0, 0.0], [0.0, 0.0, 6.2], - [0.0, 0.0, -2.8]], - [[-10.7, 9.4, 0.0], [0.1, 6.6, 0.0], [-2.9, 0.0, 0.0], [1.1, 1.3, 0.0], [0.0, 0.0, 2.4], - [0.0, 0.0, -1.0]], - [[-11.3, 14.8, 0.0], [-1.2, 4.1, 0.0], [-3.5, -0.3, 0.0], [-2.3, -1.9, 0.0], [0.0, 0.0, 3.4], - [0.0, 0.0, 3.0]]]) + [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], [ + [ [ 12.4, 11.9, 0.0 ], [ 0.3, -14.4, 0.0 ], [ 8.7, -1.4, 0.0 ], [ 0.5, -3.7, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.6 ] ], + [ [ 9.5, -0.2, 0.0 ], [ -6.1, -8.9, 0.0 ], [ 6.6, -5.1, 0.0 ], [ -3.9, -4.3, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], + [ [ 2.3, -5.2, 0.0 ], [ -9.4, -2.3, 0.0 ], [ 2.1, -9.1, 0.0 ], [ -6.4, -1.6, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, -0.1 ] ], + [ [ -7.8, -3.9, 0.0 ], [ -7.5, 4.5, 0.0 ], [ -6.0, -8.0, 0.0 ], [ -3.4, 3.4, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.5 ] ], + [ [ -11.7, 1.7, 0.0 ], [ -1.7, 7.2, 0.0 ], [ -6.4, -3.5, 0.0 ], [ 1.4, 4.0, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], + [ [ -10.7, 9.4, 0.0 ], [ 0.4, 5.3, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 1.1, 1.3, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -1.0 ] ], + [ [ -10.7, 12.2, 0.0 ], [ -0.3, 2.7, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -2.3, -1.9, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 3.0 ] ], + [ [ -11.3, 14.8, 0.0 ], [ -1.0, 2.5, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -2.3, -1.9, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 3.0 ] ] ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_stomach_term('fundus of stomach')[0], + 'ontId': get_stomach_term('fundus of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-4', + 'name': get_stomach_term('body of stomach')[0], + 'ontId': get_stomach_term('body of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5', + 'name': get_stomach_term('pyloric antrum')[0], + 'ontId': get_stomach_term('pyloric antrum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '6', + 'name': get_stomach_term('pylorus')[0], + 'ontId': get_stomach_term('pylorus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '7', + 'name': get_stomach_term('duodenum')[0], + 'ontId': get_stomach_term('duodenum')[1] + }] }), 'Stomach coordinates': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { @@ -101,18 +160,12 @@ class MeshType_3d_stomach1(Scaffold_base): 'Number of elements': 4 }, 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.5, 1.2], [0.0, -0.7, 9.0], - [0.0, 1.2, 1.5]], - [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -9.0, -0.1], [0.0, 1.4, 0.0], [0.0, -0.1, 9.0], - [0.0, 0.0, -1.4]], - [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -6.8, -0.4], [0.0, 3.5, 0.0], [0.0, -0.4, 6.8], - [0.0, 0.0, -3.5]], - [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.6, 0.2], [0.0, -0.1, 2.4], - [0.0, 0.2, -1.6]], - [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.0, 0.2], [0.0, 0.1, 3.6], - [0.0, 0.2, 4.0]]]) + [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], [ + [ [ 17.9, 0.0, 0.0 ], [ -21.6, 0.0, 0.0 ], [ 0.0, -9.0, -0.7 ], [ 0.0, -1.5, 1.2 ], [ 0.0, -0.7, 9.0 ], [ 0.0, 1.2, 1.5 ] ], + [ [ 0.0, 0.0, 0.0 ], [ -14.2, 0.0, 0.0 ], [ 0.0, -9.0, -0.1 ], [ 0.0, 1.4, 0.0 ], [ 0.0, -0.1, 9.0 ], [ 0.0, 0.0, -1.4 ] ], + [ [ -10.5, 0.0, 0.0 ], [ -9.2, 0.0, 0.0 ], [ 0.0, -6.8, -0.4 ], [ 0.0, 3.5, 0.0 ], [ 0.0, -0.4, 6.8 ], [ 0.0, 0.0, -3.5 ] ], + [ [ -18.4, 0.0, 0.0 ], [ -7.8, 0.0, 0.0 ], [ 0.0, -2.4, -0.1 ], [ 0.0, 1.6, 0.2 ], [ 0.0, -0.1, 2.4 ], [ 0.0, 0.2, -1.6 ] ], + [ [ -26.2, 0.0, 0.0 ], [ -7.8, 0.0, 0.0 ], [ 0.0, -3.6, 0.1 ], [ 0.0, -4.0, 0.2 ], [ 0.0, 0.1, 3.6 ], [ 0.0, 0.2, 4.0 ] ] ] ) }), } @@ -390,11 +443,7 @@ def generateBaseMesh(cls, region, options): elementsAroundHalfOeso = int(elementsCountAroundOeso * 0.5) elementsAroundQuarterOeso = int(elementsCountAroundOeso * 0.25) elementsAroundHalfDuod = int(elementsCountAroundDuod * 0.5) - - # if useLimitingRidge: # Rat / mouse - # annulusDerivativeFactor = 0.2 - # else: - # annulusDerivativeFactor = 1.0 + elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfOeso + 1 ############################################################################################ zero = [0.0, 0.0, 0.0] @@ -425,53 +474,98 @@ def generateBaseMesh(cls, region, options): firstElementIdentifier = 1 # Central path - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - cx, cd1, cd2, cd3, cd12, cd13 = extractPathParametersFromRegion(tmpRegion, - [Node.VALUE_LABEL_VALUE, - Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, - Node.VALUE_LABEL_D_DS3, - Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS1DS3]) - del tmpRegion - # for i in range(len(cx)): - # cd3New = vector.setMagnitude(cd3[i], vector.magnitude(cd2[i])) - # print(i, vector.magnitude(cd2[i]), vector.magnitude(cd3[i]), cd3New) - # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') + # Extract length of each group along stomach from central path + arcLengthOfGroupsAlong = [] + stomachTermsAlong = [None, 'fundus of stomach', 'body of stomach', 'pyloric antrum', 'pylorus', 'duodenum'] + for i in range(len(stomachTermsAlong)): + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ + extractPathParametersFromRegion(tmpRegion, [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, + Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3, + Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D2_DS1DS3], + groupName=stomachTermsAlong[i]) + + arcLength = 0.0 + for e in range(len(cxGroup) - 1): + arcLength += interp.getCubicHermiteArcLength(cxGroup[e], cd1Group[e], + cxGroup[e + 1], cd1Group[e + 1]) + arcLengthOfGroupsAlong.append(arcLength) + + if i == 0: + cx = cxGroup + cd1 = cd1Group + cd2 = cd2Group + cd3 = cd3Group + cd12 = cd12Group + cd13 = cd13Group + del tmpRegion sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongTrackSurface) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) - # Make sampled d2 and d3 normal to central path - # d2Check = [] - # for c in range(len(sx)): - # td2 = vector.vectorRejection(sd2[c], sd1[c]) - # sd2[c] = vector.setMagnitude(td2, vector.magnitude(sd2[c])) - # d2Check.append(matrix.rotateAboutZAxis(sd2[c], math.pi)) - # td3 = vector.vectorRejection(sd3[c], sd1[c]) - # sd3[c] = vector.setMagnitude(td3, vector.magnitude(sd3[c])) - - # Calculate length of central path - stomachCentralPathLength = 0.0 - for e in range(len(sx) - 1): - arcLength = interp.getCubicHermiteArcLength(sx[e], sd1[e], sx[e + 1], sd1[e + 1]) - # print(e+1, arcLength) - stomachCentralPathLength += arcLength - lengthElementAlong = stomachCentralPathLength / elementsCountAlongTrackSurface + # # Calculate length of central path + # testStomachCentralPathLength = 0.0 + # for e in range(len(sx) - 1): + # arcLength = interp.getCubicHermiteArcLength(sx[e], sd1[e], sx[e + 1], sd1[e + 1]) + # # print(e+1, arcLength) + # testStomachCentralPathLength += arcLength + # testLengthElementAlong = testStomachCentralPathLength / elementsCountAlongTrackSurface + + # Create annotation groups for stomach sections + allAnnotationGroups = [] + elementsCountAlongGroups = [] + stomachCentralPathLength = arcLengthOfGroupsAlong[0] + lengthElementAlong = stomachCentralPathLength / elementsCountAlong + lengthElementAlongTrackSurface = stomachCentralPathLength / elementsCountAlongTrackSurface + totalElementsAlongGroup = 0 + roundDownGroup = [] + for i in range(1, len(stomachTermsAlong)): + elementsCountAlongGroup = round(arcLengthOfGroupsAlong[i]/lengthElementAlong) + totalElementsAlongGroup += elementsCountAlongGroup + mod1 = (arcLengthOfGroupsAlong[i]/lengthElementAlong) % 1.0 + roundDownGroup.append(mod1 if mod1 < 0.5 else 0.0) + elementsCountAlongGroups.append(elementsCountAlongGroup) + + if totalElementsAlongGroup < elementsCountAlong: + for n in range(elementsCountAlong - totalElementsAlongGroup): + closestToPt5 = max(roundDownGroup) + idx = roundDownGroup.index(closestToPt5) + elementsCountAlongGroups[idx] += 1 + roundDownGroup[idx] = 0.0 + + stomachGroup = AnnotationGroup(region, get_stomach_term("stomach")) + fundusGroup = AnnotationGroup(region, get_stomach_term("fundus of stomach")) + bodyGroup = AnnotationGroup(region, get_stomach_term("body of stomach")) + antrumGroup = AnnotationGroup(region, get_stomach_term("pyloric antrum")) + pylorusGroup = AnnotationGroup(region, get_stomach_term("pylorus")) + duodenumGroup = AnnotationGroup(region, get_stomach_term("duodenum")) + + annotationGroupAlong = [[stomachGroup, fundusGroup], + [stomachGroup, bodyGroup], + [stomachGroup, antrumGroup], + [stomachGroup, pylorusGroup], + [stomachGroup, duodenumGroup]] + + annotationGroupsAlong = [] + for i in range(len(elementsCountAlongGroups)): + elementsCount = elementsCountAlongGroups[i] + for n in range(elementsCount): + annotationGroupsAlong.append(annotationGroupAlong[i]) nodeIdentifier = firstNodeIdentifier elementIdentifier = firstElementIdentifier # Fundus diameter fundusRadius = vector.magnitude(sd2[0]) - elementsAlongFundus = int(fundusRadius / lengthElementAlong) + elementsAlongFundus = int(fundusRadius / lengthElementAlongTrackSurface) d2Apex = [] d2 = sd2[0] for n1 in range(elementsCountAroundDuod): rotAngle = n1 * 2.0 * math.pi / elementsCountAroundDuod - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) # vector.normalise(sd1[0]) + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) 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)] d2Apex.append(d2Rot) @@ -610,13 +704,19 @@ def generateBaseMesh(cls, region, options): xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) axis1 = d1Centre - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + mesh = fm.findMeshByDimension(3) + esophagusGroup = AnnotationGroup(region, get_stomach_term("esophagus")) + esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) + esophagogastricJunctionGroup = AnnotationGroup(region, get_stomach_term("esophagogastric junction")) + esophagogastricJunctionMeshGroup = esophagogastricJunctionGroup.getMeshGroup(mesh) + allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup] nextNodeIdentifier = nodeIdentifier nextElementIdentifier = elementIdentifier nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, - nextNodeIdentifier, nextElementIdentifier) + nextNodeIdentifier, nextElementIdentifier, vesselMeshGroups=[[esophagusMeshGroup]], + ostiumMeshGroups=[esophagogastricJunctionMeshGroup]) bodyStartNode = nextNodeIdentifier nodeIdentifier = nextNodeIdentifier @@ -633,7 +733,7 @@ def generateBaseMesh(cls, region, options): # nodeIdentifier += 1 elementsAlongFundus = elementsAroundQuarterOeso + (0 if useLimitingRidge else 1) - elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfOeso + 1 + # elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfOeso + 1 # From fundus end to duodenum elementsAlongFundusEndToDuod = elementsCountAlong - elementsAlongFundus @@ -2252,7 +2352,12 @@ def generateBaseMesh(cls, region, options): if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) elementIdentifier += 1 - + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) # Row 2 elif e2 == 1: startNode = bodyStartNode @@ -2340,6 +2445,12 @@ def generateBaseMesh(cls, region, options): if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) # Additional elements between second and upstream bifurcation ring elif e2 > 1 and e2 < elementsAroundQuarterOeso: @@ -2371,6 +2482,12 @@ def generateBaseMesh(cls, region, options): if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) # Upstream bifurcation elif e2 == elementsAroundQuarterOeso: @@ -2427,6 +2544,12 @@ def generateBaseMesh(cls, region, options): if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) # Downstream bifurcation elif e2 == elementsAroundQuarterOeso + 1: @@ -2496,6 +2619,12 @@ def generateBaseMesh(cls, region, options): if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) # Rows between downstream and penultimate ring for e2 in range(elementsAroundQuarterOeso + 2, elementsAroundHalfOeso): @@ -2522,6 +2651,12 @@ def generateBaseMesh(cls, region, options): element = mesh.createElement(elementIdentifier, elementtemplateStandard) result = element.setNodesByIdentifier(eftStandard, nodeIdentifiers) elementIdentifier = elementIdentifier + 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) # Penultimate row connecting to annulus and beyond for e2 in range(elementsAroundHalfOeso, elementsCountAlong): @@ -2584,6 +2719,12 @@ def generateBaseMesh(cls, region, options): if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) # Annulus # Assemble endPoints for annulus @@ -2637,12 +2778,17 @@ def generateBaseMesh(cls, region, options): for n in range(elementsCountAroundOeso): startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) + cardiaGroup = AnnotationGroup(region, get_stomach_term("cardia of stomach")) + cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) + stomachMeshGroup = stomachGroup.getMeshGroup(mesh) + allAnnotationGroups.append(cardiaGroup) + 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 = elementsCountAnnulus, tracksurface=trackSurfaceStomach, - startProportions = startProportions, endProportions = endProportions, + elementsCountRadial = elementsCountAnnulus, meshGroups= [stomachMeshGroup, cardiaMeshGroup], + tracksurface=trackSurfaceStomach, startProportions = startProportions, endProportions = endProportions, rescaleStartDerivatives = True, rescaleEndDerivatives = True) if showTrackSurface: @@ -2687,8 +2833,7 @@ def generateBaseMesh(cls, region, options): fm.endChange() - annotationGroup = [] - return annotationGroup + return allAnnotationGroups @classmethod def refineMesh(cls, meshrefinement, options): From 1ec8235553ae340459af73238529c7e796887e77 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Thu, 15 Apr 2021 16:17:36 +1200 Subject: [PATCH 07/38] Create annotation groups --- .../meshtypes/meshtype_3d_stomach1.py | 145 +++++++++++------- 1 file changed, 92 insertions(+), 53 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 8f6f9822..e52dac64 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -101,52 +101,53 @@ class MeshType_3d_stomach1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 7 + 'Number of elements': 8 }, 'meshEdits': exnodeStringFromNodeValues( [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], [ - [ [ 12.4, 11.9, 0.0 ], [ 0.3, -14.4, 0.0 ], [ 8.7, -1.4, 0.0 ], [ 0.5, -3.7, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.6 ] ], - [ [ 9.5, -0.2, 0.0 ], [ -6.1, -8.9, 0.0 ], [ 6.6, -5.1, 0.0 ], [ -3.9, -4.3, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], - [ [ 2.3, -5.2, 0.0 ], [ -9.4, -2.3, 0.0 ], [ 2.1, -9.1, 0.0 ], [ -6.4, -1.6, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, -0.1 ] ], - [ [ -7.8, -3.9, 0.0 ], [ -7.5, 4.5, 0.0 ], [ -6.0, -8.0, 0.0 ], [ -3.4, 3.4, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.5 ] ], - [ [ -11.7, 1.7, 0.0 ], [ -1.7, 7.2, 0.0 ], [ -6.4, -3.5, 0.0 ], [ 1.4, 4.0, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], - [ [ -10.7, 9.4, 0.0 ], [ 0.4, 5.3, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 1.1, 1.3, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -1.0 ] ], - [ [ -10.7, 12.2, 0.0 ], [ -0.3, 2.7, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -2.3, -1.9, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 3.0 ] ], - [ [ -11.3, 14.8, 0.0 ], [ -1.0, 2.5, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -2.3, -1.9, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 3.0 ] ] ] ), + [ [ 12.4, 11.9, 0.0 ], [ -0.1, -14.5, 0.0 ], [ 8.7, -1.4, 0.0 ], [ -0.7, -3.5, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.5 ] ], + [ [ 9.5, -0.2, 0.0 ], [ -5.7, -9.0, 0.0 ], [ 6.6, -5.1, 0.0 ], [ -3.5, -3.9, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], + [ [ 2.8, -5.5, 0.0 ], [ -6.5, -2.5, 0.0 ], [ 2.1, -9.1, 0.0 ], [ -4.0, -1.5, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, 0.0 ] ], + [ [ -2.4, -5.9, 0.0 ], [ -5.5, 0.8, 0.0 ], [ -1.6, -9.2, 0.0 ], [ -4.0, 0.5, 0.0 ], [ 0.0, 0.0, 8.8 ], [ 0.0, 0.0, -0.4 ] ], + [ [ -7.8, -3.9, 0.0 ], [ -5.0, 3.9, 0.0 ], [ -6.0, -8.0, 0.0 ], [ -2.5, 2.7, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.2 ] ], + [ [ -11.7, 1.7, 0.0 ], [ -1.7, 7.2, 0.0 ], [ -6.4, -3.5, 0.0 ], [ 1.4, 4.0, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], + [ [ -10.7, 9.4, 0.0 ], [ 0.3, 5.3, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 0.5, 0.7, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -0.3 ] ], + [ [ -10.7, 12.2, 0.0 ], [ -0.3, 2.7, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -0.3, -0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 0.5 ] ], + [ [ -11.3, 14.8, 0.0 ], [ -0.9, 2.5, 0.0 ], [ -3.5, -0.3, 0.0 ], [ 0.3, 0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, -0.5 ] ] ] ), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-2', + 'identifierRanges': '1-3', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '3-4', + 'identifierRanges': '4-5', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '5', + 'identifierRanges': '6', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6', + 'identifierRanges': '7', 'name': get_stomach_term('pylorus')[0], 'ontId': get_stomach_term('pylorus')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7', + 'identifierRanges': '8', 'name': get_stomach_term('duodenum')[0], 'ontId': get_stomach_term('duodenum')[1] }] @@ -266,7 +267,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of radial elements in annulus': 1, # KM 'Wall thickness': 5.0, 'Limiting ridge': False, - 'Fundus end position along factor': 0.3, + # 'Fundus end position along factor': 0.24, 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), 'Gastro-oesophagal junction position along factor': 0.35, 'Annulus derivative factor': 1.0, @@ -288,11 +289,11 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Gastro-oesophagal junction position along factor'] = 0.55 options['Annulus derivative factor'] = 0.2 options['Limiting ridge'] = True - options['Fundus end position along factor'] = 0.5 + # options['Fundus end position along factor'] = 0.5 elif 'Stomach coordinates' in parameterSetName: options['Wall thickness'] = 0.5 options['Gastro-oesophagal junction position along factor'] = 0.45 - options['Fundus end position along factor'] = 0.45 + # options['Fundus end position along factor'] = 0.45 cls.updateSubScaffoldOptions(options) return options @@ -308,7 +309,7 @@ def getOrderedOptionNames(): 'Number of radial elements in annulus', 'Wall thickness', 'Limiting ridge', - 'Fundus end position along factor', + # 'Fundus end position along factor', 'Gastro-oesophagal junction', 'Gastro-oesophagal junction position along factor', 'Annulus derivative factor', @@ -385,7 +386,7 @@ def checkOptions(cls, options): # if options['Number of elements along'] < 8: # options['Number of elements along'] = 8 for key in [ - 'Fundus end position along factor', + # 'Fundus end position along factor', 'Annulus derivative factor']: if options[key] < 0: options[key] = 0.0 @@ -431,7 +432,7 @@ def generateBaseMesh(cls, region, options): GOJOptions = options['Gastro-oesophagal junction'] GOJSettings = GOJOptions.getScaffoldSettings() useLimitingRidge = options['Limiting ridge'] - fundusEndPositionAlongFactor = options['Fundus end position along factor'] + # fundusEndPositionAlongFactor = options['Fundus end position along factor'] elementsCountAnnulus = options['Number of radial elements in annulus'] annulusDerivativeFactor = options['Annulus derivative factor'] @@ -505,35 +506,32 @@ def generateBaseMesh(cls, region, options): sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) - # # Calculate length of central path - # testStomachCentralPathLength = 0.0 - # for e in range(len(sx) - 1): - # arcLength = interp.getCubicHermiteArcLength(sx[e], sd1[e], sx[e + 1], sd1[e + 1]) - # # print(e+1, arcLength) - # testStomachCentralPathLength += arcLength - # testLengthElementAlong = testStomachCentralPathLength / elementsCountAlongTrackSurface - # Create annotation groups for stomach sections allAnnotationGroups = [] - elementsCountAlongGroups = [] - stomachCentralPathLength = arcLengthOfGroupsAlong[0] - lengthElementAlong = stomachCentralPathLength / elementsCountAlong - lengthElementAlongTrackSurface = stomachCentralPathLength / elementsCountAlongTrackSurface - totalElementsAlongGroup = 0 - roundDownGroup = [] - for i in range(1, len(stomachTermsAlong)): - elementsCountAlongGroup = round(arcLengthOfGroupsAlong[i]/lengthElementAlong) - totalElementsAlongGroup += elementsCountAlongGroup - mod1 = (arcLengthOfGroupsAlong[i]/lengthElementAlong) % 1.0 - roundDownGroup.append(mod1 if mod1 < 0.5 else 0.0) - elementsCountAlongGroups.append(elementsCountAlongGroup) - - if totalElementsAlongGroup < elementsCountAlong: - for n in range(elementsCountAlong - totalElementsAlongGroup): - closestToPt5 = max(roundDownGroup) - idx = roundDownGroup.index(closestToPt5) - elementsCountAlongGroups[idx] += 1 - roundDownGroup[idx] = 0.0 + stomachCentralPathLength = sum(arcLengthOfGroupsAlong[1:]) + fundusEndPositionAlongFactor = arcLengthOfGroupsAlong[1]/stomachCentralPathLength + arcLengthRatioForGroupsFromFundusEnd = [] + checkLength = 0.0 + for i in range(2, len(stomachTermsAlong)): + checkLength += arcLengthOfGroupsAlong[i] + arcLengthRatio = (arcLengthOfGroupsAlong[i])/(stomachCentralPathLength - arcLengthOfGroupsAlong[1]) + arcLengthRatioForGroupsFromFundusEnd.append(arcLengthRatio) + + # totalElementsAlongGroup = 0 + # roundDownGroup = [] + # for i in range(1, len(stomachTermsAlong)): + # elementsCountAlongGroup = round(arcLengthOfGroupsAlong[i]/lengthElementAlong) + # totalElementsAlongGroup += elementsCountAlongGroup + # mod1 = (arcLengthOfGroupsAlong[i]/lengthElementAlong) % 1.0 + # roundDownGroup.append(mod1 if mod1 < 0.5 else 0.0) + # elementsCountAlongGroups.append(elementsCountAlongGroup) + # + # if totalElementsAlongGroup < elementsCountAlong: + # for n in range(elementsCountAlong - totalElementsAlongGroup): + # closestToPt5 = max(roundDownGroup) + # idx = roundDownGroup.index(closestToPt5) + # elementsCountAlongGroups[idx] += 1 + # roundDownGroup[idx] = 0.0 stomachGroup = AnnotationGroup(region, get_stomach_term("stomach")) fundusGroup = AnnotationGroup(region, get_stomach_term("fundus of stomach")) @@ -548,17 +546,12 @@ def generateBaseMesh(cls, region, options): [stomachGroup, pylorusGroup], [stomachGroup, duodenumGroup]] - annotationGroupsAlong = [] - for i in range(len(elementsCountAlongGroups)): - elementsCount = elementsCountAlongGroups[i] - for n in range(elementsCount): - annotationGroupsAlong.append(annotationGroupAlong[i]) - nodeIdentifier = firstNodeIdentifier elementIdentifier = firstElementIdentifier # Fundus diameter fundusRadius = vector.magnitude(sd2[0]) + lengthElementAlongTrackSurface = stomachCentralPathLength / elementsCountAlongTrackSurface elementsAlongFundus = int(fundusRadius / lengthElementAlongTrackSurface) d2Apex = [] @@ -816,6 +809,52 @@ def generateBaseMesh(cls, region, options): xOesoToDuodGC = xAlongGCOesoToFundusEnd[:-1] + xAlongGCFundusEndToDuod d2OesoToDuodGC = d2AlongGCOesoToFundusEnd[:-1] + d2AlongGCFundusEndToDuod + # Use element spacing on greater curvature to determine where annotation groups should sit + arcLengthGCFromFundusEnd = 0.0 + arcLengthsGCFromFundusEnd = [] + for n2 in range(len(xAlongGCFundusEndToDuod) - 1): + arcLengthGCFromFundusEnd += interp.getCubicHermiteArcLength(xAlongGCFundusEndToDuod[n2], d2AlongGCFundusEndToDuod[n2], + xAlongGCFundusEndToDuod[n2 + 1], d2AlongGCFundusEndToDuod[n2 + 1]) + arcLengthsGCFromFundusEnd.append(arcLengthGCFromFundusEnd) + arcLengthGCFundusEndToDuod = arcLengthGCFromFundusEnd + + # Move along elements on GC and assign to annotation group + elementsCountAlongGroups = [] + elementsCountAlongGroups.append(elementsAlongFundus) + groupLength = 0.0 + e = 0 + elementsCount = 1 + length = arcLengthsGCFromFundusEnd[e] + for i in range(len(arcLengthRatioForGroupsFromFundusEnd)): + groupLength += arcLengthRatioForGroupsFromFundusEnd[i] * arcLengthGCFundusEndToDuod + + if e == len(arcLengthsGCFromFundusEnd) - 2: + elementsCount += 1 + elementsCountAlongGroups.append(elementsCount) + else: + while length < groupLength: + elementsCount += 1 + e += 1 + length = arcLengthsGCFromFundusEnd[e] + + # check which end is grouplength closer to + distToUpperEnd = abs(length - groupLength) + distToLowerEnd = abs(groupLength - arcLengthsGCFromFundusEnd[e - 1]) + if distToLowerEnd < distToUpperEnd: + elementsCount -= 1 + elementsCountAlongGroups.append(elementsCount) + e -= 1 + length = arcLengthsGCFromFundusEnd[e] + else: + elementsCountAlongGroups.append(elementsCount) + elementsCount = 0 + + annotationGroupsAlong = [] + for i in range(len(elementsCountAlongGroups)): + elementsCount = elementsCountAlongGroups[i] + for n in range(elementsCount): + annotationGroupsAlong.append(annotationGroupAlong[i]) + # for n2 in range(len(xAlongUpFundus)): # node = nodes.createNode(nodeIdentifier, nodetemplate) # cache.setNode(node) From c2945a5bda6bf4af3ef1ba8f679f6ed74b8a6bce Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 16 Apr 2021 12:07:00 +1200 Subject: [PATCH 08/38] Remove redundant code --- src/scaffoldmaker/annotation/stomach_terms.py | 3 - .../meshtypes/meshtype_3d_stomach1.py | 1945 ++++++----------- 2 files changed, 657 insertions(+), 1291 deletions(-) diff --git a/src/scaffoldmaker/annotation/stomach_terms.py b/src/scaffoldmaker/annotation/stomach_terms.py index ed1ba35f..73bab181 100644 --- a/src/scaffoldmaker/annotation/stomach_terms.py +++ b/src/scaffoldmaker/annotation/stomach_terms.py @@ -9,10 +9,7 @@ ( "duodenum", "UBERON:0002114", " FMA:7206", "ILX:0726125"), ( "esophagus", "UBERON:0001043", "FMA: 7131", "ILX:0735017"), ( "esophagogastric junction", "UBERON:0007650", "FMA: 9434", "ILX:0733910"), - ( "forestomach-glandular stomach junction", "UBERON:0012270", "ILX:0729974"), ( "fundus of stomach", "UBERON:0001160", " FMA:14559", "ILX:0724443"), - ( "greater curvature of stomach", "UBERON:0001164", " FMA:14574", "ILX:0724395"), - ( "lesser curvature of stomach", "UBERON:0001163", " FMA:14572", "ILX:0733753"), ( "pyloric antrum", "UBERON:0001165", " FMA:14579", "ILX:0728672"), ( "pylorus", "UBERON:0001166", " FMA:14581", "ILX:0734150"), ( "stomach", "UBERON:0000945", "FMA:7148", "ILX:0736697") diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index e52dac64..b319c098 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1,6 +1,6 @@ """ Generates a 3-D stomach mesh along the central line, with variable -numbers of elements around oesophagus and duodenum, along and through +numbers of elements around esophagus and duodenum, along and through wall, with variable radius and thickness along. """ @@ -32,11 +32,11 @@ class MeshType_3d_stomach1(Scaffold_base): """ - Generates a 3-D stomach mesh with variable numbers of elements around the oesophagus and duodenum, - along the central line, and through wall. The stomach is created by a function that generates a bean - volume defined by a central path as its longitudinal axis. D2 of the central path points to the greater - curvature of the stomach and magnitude of D2 and D3 are the radii of the stomach in the respective - direction. + Generates a 3-D stomach mesh with variable numbers of elements around the esophagus and duodenum, + along the central line, and through wall. The stomach is created using a central path as the longitudinal axis + of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 + are the radii of the stomach in the respective direction. D2 and D3 on the first node of the central path provide + the radii of the fundus dome. """ centralPathDefaultScaffoldPackages = { 'Human 1': ScaffoldPackage(MeshType_1d_path1, { @@ -152,22 +152,6 @@ class MeshType_3d_stomach1(Scaffold_base): 'ontId': get_stomach_term('duodenum')[1] }] }), - 'Stomach coordinates': ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 4 - }, - 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [ [ 17.9, 0.0, 0.0 ], [ -21.6, 0.0, 0.0 ], [ 0.0, -9.0, -0.7 ], [ 0.0, -1.5, 1.2 ], [ 0.0, -0.7, 9.0 ], [ 0.0, 1.2, 1.5 ] ], - [ [ 0.0, 0.0, 0.0 ], [ -14.2, 0.0, 0.0 ], [ 0.0, -9.0, -0.1 ], [ 0.0, 1.4, 0.0 ], [ 0.0, -0.1, 9.0 ], [ 0.0, 0.0, -1.4 ] ], - [ [ -10.5, 0.0, 0.0 ], [ -9.2, 0.0, 0.0 ], [ 0.0, -6.8, -0.4 ], [ 0.0, 3.5, 0.0 ], [ 0.0, -0.4, 6.8 ], [ 0.0, 0.0, -3.5 ] ], - [ [ -18.4, 0.0, 0.0 ], [ -7.8, 0.0, 0.0 ], [ 0.0, -2.4, -0.1 ], [ 0.0, 1.6, 0.2 ], [ 0.0, -0.1, 2.4 ], [ 0.0, 0.2, -1.6 ] ], - [ [ -26.2, 0.0, 0.0 ], [ -7.8, 0.0, 0.0 ], [ 0.0, -3.6, 0.1 ], [ 0.0, -4.0, 0.2 ], [ 0.0, 0.1, 3.6 ], [ 0.0, 0.2, 4.0 ] ] ] ) - }), } ostiumDefaultScaffoldPackages = { @@ -240,40 +224,29 @@ def getParameterSetNames(): return [ 'Default', 'Human 1', - 'Rat 1', - 'Stomach coordinates'] + 'Rat 1'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Rat 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] - elif 'Generic 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Generic 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] - elif 'Stomach coordinates' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Stomach coordinates'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] else: centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] options = { 'Central path': copy.deepcopy(centralPathOption), - 'Number of elements around oesophagus': 8, + 'Number of elements around esophagus': 8, 'Number of elements around duodenum': 12, 'Number of elements between annulus and duodenum': 6, 'Number of elements through wall': 1, - 'Number of radial elements in annulus': 1, # KM + 'Number of radial elements in annulus': 1, 'Wall thickness': 5.0, 'Limiting ridge': False, - # 'Fundus end position along factor': 0.24, - 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), - 'Gastro-oesophagal junction position along factor': 0.35, + 'Gastro-esophagal junction': copy.deepcopy(ostiumOption), + 'Gastro-esophagal junction position along factor': 0.35, 'Annulus derivative factor': 1.0, - 'Show track surface': False, # KM - 'Make stomach': True, # KM - 'Show central path': False, # KM 'Use cross derivatives': False, 'Use linear through wall' : False, # need to deal with wedge not available in bicubichermite 'Refine': False, @@ -282,18 +255,13 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Rat 1' in parameterSetName: - options['Number of elements around oesophagus'] = 12 + options['Number of elements around esophagus'] = 12 options['Number of elements around duodenum'] = 14 options['Number of elements between annulus and duodenum'] = 2 options['Wall thickness'] = 0.5 - options['Gastro-oesophagal junction position along factor'] = 0.55 + options['Gastro-esophagal junction position along factor'] = 0.55 options['Annulus derivative factor'] = 0.2 options['Limiting ridge'] = True - # options['Fundus end position along factor'] = 0.5 - elif 'Stomach coordinates' in parameterSetName: - options['Wall thickness'] = 0.5 - options['Gastro-oesophagal junction position along factor'] = 0.45 - # options['Fundus end position along factor'] = 0.45 cls.updateSubScaffoldOptions(options) return options @@ -302,20 +270,16 @@ def getDefaultOptions(cls, parameterSetName='Default'): def getOrderedOptionNames(): return [ 'Central path', - 'Number of elements around oesophagus', + 'Number of elements around esophagus', 'Number of elements around duodenum', 'Number of elements between annulus and duodenum', 'Number of elements through wall', 'Number of radial elements in annulus', 'Wall thickness', 'Limiting ridge', - # 'Fundus end position along factor', - 'Gastro-oesophagal junction', - 'Gastro-oesophagal junction position along factor', + 'Gastro-esophagal junction', + 'Gastro-esophagal junction position along factor', 'Annulus derivative factor', - 'Show track surface', - 'Make stomach', - 'Show central path', 'Use cross derivatives', 'Use linear through wall', 'Refine', @@ -327,7 +291,7 @@ def getOrderedOptionNames(): def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': return [MeshType_1d_path1] - if optionName == 'Gastro-oesophagal junction': + if optionName == 'Gastro-esophagal junction': return [MeshType_3d_ostium1] return [] @@ -335,7 +299,7 @@ def getOptionValidScaffoldTypes(cls, optionName): def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.keys()) - if optionName == 'Gastro-oesophagal junction': + if optionName == 'Gastro-esophagal junction': return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ @@ -356,7 +320,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-oesophagal junction': + if optionName == 'Gastro-esophagal junction': if not parameterSetName: parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) @@ -366,30 +330,22 @@ 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-oesophagal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( - 'Gastro-oesophagal junction'): - options['Gastro-oesophagal junction'] = cls.getOptionScaffoldPackage('Gastro-oesophagal junction', + if not options['Gastro-esophagal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( + 'Gastro-esophagal junction'): + options['Gastro-esophagal junction'] = cls.getOptionScaffoldPackage('Gastro-esophagal junction', MeshType_3d_ostium1) - if options['Number of elements around oesophagus'] < 8: - options['Number of elements around oesophagus'] = 8 - if options['Number of elements around oesophagus'] % 4 > 0: - options['Number of elements around oesophagus'] = options['Number of elements around oesophagus'] // 4 * 4 + if options['Number of elements around esophagus'] < 8: + options['Number of elements around esophagus'] = 8 + if options['Number of elements around esophagus'] % 4 > 0: + options['Number of elements around esophagus'] = options['Number of elements around esophagus'] // 4 * 4 if options['Number of elements around duodenum'] < 12: options['Number of elements around duodenum'] = 12 + if options['Number of elements around duodenum'] % 2: + options['Number of elements around duodenum'] += 1 if options['Number of elements between annulus and duodenum'] < 2: options['Number of elements between annulus and duodenum'] = 2 - for key in [ - 'Number of elements around oesophagus', - 'Number of elements around duodenum']: - if options[key] % 2: - options[key] += 1 - # if options['Number of elements along'] < 8: - # options['Number of elements along'] = 8 - for key in [ - # 'Fundus end position along factor', - 'Annulus derivative factor']: - if options[key] < 0: - options[key] = 0.0 + if options['Annulus derivative factor'] <= 0.0: + options['Annulus derivative factor'] = 0.1 for key in [ 'Number of elements through wall', 'Refine number of elements around', @@ -406,7 +362,7 @@ def updateSubScaffoldOptions(cls, options): Update ostium sub-scaffold options which depend on parent options. ''' wallThickness = options['Wall thickness'] - ostiumOptions = options['Gastro-oesophagal junction'] + ostiumOptions = options['Gastro-esophagal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() ostiumSettings['Ostium wall thickness'] = wallThickness @@ -420,7 +376,7 @@ def generateBaseMesh(cls, region, options): """ cls.updateSubScaffoldOptions(options) centralPath = options['Central path'] - elementsCountAroundOeso = options['Number of elements around oesophagus'] + elementsCountAroundEso = options['Number of elements around esophagus'] elementsCountAroundDuod = options['Number of elements around duodenum'] elementsAlongAnnulusToDuod = options['Number of elements between annulus and duodenum'] elementsCountThroughWall = options['Number of elements through wall'] @@ -428,25 +384,18 @@ def generateBaseMesh(cls, region, options): useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not (options['Use linear through wall']) - GOJPositionAlongFactor = options['Gastro-oesophagal junction position along factor'] - GOJOptions = options['Gastro-oesophagal junction'] + GOJPositionAlongFactor = options['Gastro-esophagal junction position along factor'] + GOJOptions = options['Gastro-esophagal junction'] GOJSettings = GOJOptions.getScaffoldSettings() - useLimitingRidge = options['Limiting ridge'] - # fundusEndPositionAlongFactor = options['Fundus end position along factor'] + limitingRidge = options['Limiting ridge'] elementsCountAnnulus = options['Number of radial elements in annulus'] annulusDerivativeFactor = options['Annulus derivative factor'] - showTrackSurface = options['Show track surface'] - makeStomach = options['Make stomach'] - showCentralPath = options['Show central path'] - elementsCountAlongTrackSurface = 20 - elementsAroundHalfOeso = int(elementsCountAroundOeso * 0.5) - elementsAroundQuarterOeso = int(elementsCountAroundOeso * 0.25) + elementsAroundHalfEso = int(elementsCountAroundEso * 0.5) + elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) elementsAroundHalfDuod = int(elementsCountAroundDuod * 0.5) - elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfOeso + 1 - - ############################################################################################ + elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfEso + 1 zero = [0.0, 0.0, 0.0] fm = region.getFieldmodule() @@ -469,12 +418,10 @@ def generateBaseMesh(cls, region, options): nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) cache = fm.createFieldcache() - ########################################################################################### - firstNodeIdentifier = 1 - firstElementIdentifier = 1 + nodeIdentifier = 1 + elementIdentifier = 1 - # Central path # Extract length of each group along stomach from central path arcLengthOfGroupsAlong = [] stomachTermsAlong = [None, 'fundus of stomach', 'body of stomach', 'pyloric antrum', 'pylorus', 'duodenum'] @@ -517,22 +464,6 @@ def generateBaseMesh(cls, region, options): arcLengthRatio = (arcLengthOfGroupsAlong[i])/(stomachCentralPathLength - arcLengthOfGroupsAlong[1]) arcLengthRatioForGroupsFromFundusEnd.append(arcLengthRatio) - # totalElementsAlongGroup = 0 - # roundDownGroup = [] - # for i in range(1, len(stomachTermsAlong)): - # elementsCountAlongGroup = round(arcLengthOfGroupsAlong[i]/lengthElementAlong) - # totalElementsAlongGroup += elementsCountAlongGroup - # mod1 = (arcLengthOfGroupsAlong[i]/lengthElementAlong) % 1.0 - # roundDownGroup.append(mod1 if mod1 < 0.5 else 0.0) - # elementsCountAlongGroups.append(elementsCountAlongGroup) - # - # if totalElementsAlongGroup < elementsCountAlong: - # for n in range(elementsCountAlong - totalElementsAlongGroup): - # closestToPt5 = max(roundDownGroup) - # idx = roundDownGroup.index(closestToPt5) - # elementsCountAlongGroups[idx] += 1 - # roundDownGroup[idx] = 0.0 - stomachGroup = AnnotationGroup(region, get_stomach_term("stomach")) fundusGroup = AnnotationGroup(region, get_stomach_term("fundus of stomach")) bodyGroup = AnnotationGroup(region, get_stomach_term("body of stomach")) @@ -546,9 +477,6 @@ def generateBaseMesh(cls, region, options): [stomachGroup, pylorusGroup], [stomachGroup, duodenumGroup]] - nodeIdentifier = firstNodeIdentifier - elementIdentifier = firstElementIdentifier - # Fundus diameter fundusRadius = vector.magnitude(sd2[0]) lengthElementAlongTrackSurface = stomachCentralPathLength / elementsCountAlongTrackSurface @@ -596,30 +524,10 @@ def generateBaseMesh(cls, region, options): d2Around.append(d2) d2Ellipses.append(d2Around) - # for n2 in range(len(xEllipses)): - # for n1 in range(elementsCountAroundDuod): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xEllipses[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Ellipses[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Ellipses[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # Merge fundus and body xAll = [[sx[0]] * elementsCountAroundDuod] + xEllipses d2All = [d2Apex] + d2Ellipses - # for n2 in range(len(xAll)): - # for n1 in range(elementsCountAroundDuod): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2All[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # Spread out elements xRaw = [] d2Raw = [] @@ -668,16 +576,6 @@ def generateBaseMesh(cls, region, options): d1SampledAll.append(d1Smoothed) d2SampledAll.append(d2Around) - # for n2 in range(elementsCountAlongTrackSurface + 1): - # for n1 in range(elementsCountAroundDuod): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # Create tracksurface xTrackSurface = [] d1TrackSurface = [] @@ -691,8 +589,8 @@ def generateBaseMesh(cls, region, options): trackSurfaceStomach = TrackSurface(elementsCountAroundDuod, elementsCountAlongTrackSurface, xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) - # Set up gastro-oesophagal junction - GOJSettings['Number of elements around ostium'] = elementsCountAroundOeso + # Set up gastro-esophagal junction + GOJSettings['Number of elements around ostium'] = elementsCountAroundEso GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) axis1 = d1Centre @@ -704,29 +602,18 @@ def generateBaseMesh(cls, region, options): esophagogastricJunctionMeshGroup = esophagogastricJunctionGroup.getMeshGroup(mesh) allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup] - nextNodeIdentifier = nodeIdentifier - nextElementIdentifier = elementIdentifier nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, - nextNodeIdentifier, nextElementIdentifier, vesselMeshGroups=[[esophagusMeshGroup]], + nodeIdentifier, elementIdentifier, vesselMeshGroups=[[esophagusMeshGroup]], ostiumMeshGroups=[esophagogastricJunctionMeshGroup]) - bodyStartNode = nextNodeIdentifier + stomachStartNode = nextNodeIdentifier nodeIdentifier = nextNodeIdentifier + elementIdentifier = nextElementIdentifier fundusEndPosition = trackSurfaceStomach.createPositionProportion(0.0, fundusEndPositionAlongFactor) xFundusEnd, d1FundusEnd, d2FundusEnd = trackSurfaceStomach.evaluateCoordinates(fundusEndPosition, derivatives=True) - - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFundusEnd) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2FundusEnd) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1FundusEnd) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - elementsAlongFundus = elementsAroundQuarterOeso + (0 if useLimitingRidge else 1) - # elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfOeso + 1 + elementsAlongFundus = elementsAroundQuarterEso + (0 if limitingRidge else 1) # From fundus end to duodenum elementsAlongFundusEndToDuod = elementsCountAlong - elementsAlongFundus @@ -740,47 +627,42 @@ def generateBaseMesh(cls, region, options): xAlongDownFundus.append(xSampledAll[n2][0]) d2AlongDownFundus.append(d2SampledAll[n2][0]) - # From oesophagus to fundus end - elementsAlongGCFromOesoToFundusEnd = elementsAroundHalfDuod - 2 + elementsAlongFundus + # From esophagus to fundus end + elementsAlongGCFromEsoToFundusEnd = elementsAroundHalfDuod - 2 + elementsAlongFundus xAlongUpFundus = [] d2AlongUpFundus = [] xAlongUpFundus.append(o1_x[1][0]) d2AlongUpFundus.append([annulusDerivativeFactor * c for c in o1_d2[1][0]]) - # From oesophagus to fundus apex - oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] - elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) - arcLengthOesoApex = 0.0 - for n2 in range(elementsAlongUpstreamOfOeso): - nAlong = elementsAlongUpstreamOfOeso - n2 + # From esophagus to fundus apex + esoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] + elementsAlongUpstreamOfEso = int(elementsCountAlongTrackSurface * esoStartProportion2) + arcLengthEsoApex = 0.0 + for n2 in range(elementsAlongUpstreamOfEso): + nAlong = elementsAlongUpstreamOfEso - n2 v1 = xSampledAll[nAlong][elementsAroundHalfDuod] v2 = xSampledAll[nAlong - 1][elementsAroundHalfDuod] d = [v2[c] - v1[c] for c in range(3)] arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) - arcLengthOesoApex += arcLengthAround + arcLengthEsoApex += arcLengthAround d2 = [c * arcLengthAround for c in vector.normalise(d)] xAlongUpFundus.append(v1) d2AlongUpFundus.append(d2) # From fundus apex to end - for n2 in range(startIdx - (0 if useLimitingRidge else 1)): + for n2 in range(startIdx - (0 if limitingRidge else 1)): xAlongUpFundus.append(xSampledAll[n2][0]) d2AlongUpFundus.append(d2SampledAll[n2][0]) - if useLimitingRidge: - # Sample from oesophagus to fundus end - # xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ - # interp.sampleCubicHermiteCurves(xAlongUpFundus, d2AlongUpFundus, elementsAlongGCFromOesoToFundusEnd, - # addLengthStart=0.5 * vector.magnitude(d2AlongUpFundus[0]), - # lengthFractionStart=0.5, arcLengthDerivatives=True)[0:2] - xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ + if limitingRidge: + # Sample from esophagus to fundus end + xAlongGCEsoToFundusEnd, d2AlongGCEsoToFundusEnd = \ interp.sampleCubicHermiteCurvesSmooth(xAlongUpFundus, d2AlongUpFundus, - elementsAlongGCFromOesoToFundusEnd, + elementsAlongGCFromEsoToFundusEnd, derivativeMagnitudeStart=vector.magnitude(d2AlongUpFundus[0]))[0:2] - # Sample from limiting ridge to duodenum - xAlongDownFundus[0] = xAlongGCOesoToFundusEnd[-1] - d2AlongDownFundus[0] = d2AlongGCOesoToFundusEnd[-1] + xAlongDownFundus[0] = xAlongGCEsoToFundusEnd[-1] + d2AlongDownFundus[0] = d2AlongGCEsoToFundusEnd[-1] xAlongGCFundusEndToDuod, d2AlongGCFundusEndToDuod = \ interp.sampleCubicHermiteCurves(xAlongDownFundus, d2AlongDownFundus, elementsAlongFundusEndToDuod, addLengthStart=0.5 * vector.magnitude(d2AlongDownFundus[0]), @@ -791,30 +673,27 @@ def generateBaseMesh(cls, region, options): xAlongGCFundusEndToDuod, d2AlongGCFundusEndToDuod = \ interp.sampleCubicHermiteCurves(xAlongDownFundus, d2AlongDownFundus, elementsAlongFundusEndToDuod, arcLengthDerivatives=True)[0:2] - # Sample from ostium to end of fundus - # Provide first element size so that we can transit + # Provide first element size for transition xAlongUpFundus[-1] = xAlongGCFundusEndToDuod[0] d2AlongUpFundus[-1] = d2AlongGCFundusEndToDuod[0] - # xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ - # interp.sampleCubicHermiteCurves(xAlongUpFundus, d2AlongUpFundus, elementsAlongGCFromOesoToFundusEnd, - # addLengthStart=0.5* vector.magnitude(d2AlongUpFundus[0]), - # lengthFractionStart = 0.5, addLengthEnd=0.5 * vector.magnitude(d2AlongUpFundus[-1]), - # lengthFractionEnd=0.5, arcLengthDerivatives=True)[0:2] - xAlongGCOesoToFundusEnd, d2AlongGCOesoToFundusEnd = \ - interp.sampleCubicHermiteCurvesSmooth(xAlongUpFundus, d2AlongUpFundus, elementsAlongGCFromOesoToFundusEnd, - derivativeMagnitudeStart= vector.magnitude(d2AlongUpFundus[0]), - derivativeMagnitudeEnd = vector.magnitude(d2AlongUpFundus[-1]))[0:2] - - xOesoToDuodGC = xAlongGCOesoToFundusEnd[:-1] + xAlongGCFundusEndToDuod - d2OesoToDuodGC = d2AlongGCOesoToFundusEnd[:-1] + d2AlongGCFundusEndToDuod - - # Use element spacing on greater curvature to determine where annotation groups should sit + xAlongGCEsoToFundusEnd, d2AlongGCEsoToFundusEnd = \ + interp.sampleCubicHermiteCurvesSmooth(xAlongUpFundus, d2AlongUpFundus, + elementsAlongGCFromEsoToFundusEnd, + derivativeMagnitudeStart= vector.magnitude(d2AlongUpFundus[0]), + derivativeMagnitudeEnd = vector.magnitude(d2AlongUpFundus[-1]))[0:2] + + xEsoToDuodGC = xAlongGCEsoToFundusEnd[:-1] + xAlongGCFundusEndToDuod + d2EsoToDuodGC = d2AlongGCEsoToFundusEnd[:-1] + d2AlongGCFundusEndToDuod + + # Use element spacing on greater curvature to decide where annotation groups should sit arcLengthGCFromFundusEnd = 0.0 arcLengthsGCFromFundusEnd = [] for n2 in range(len(xAlongGCFundusEndToDuod) - 1): - arcLengthGCFromFundusEnd += interp.getCubicHermiteArcLength(xAlongGCFundusEndToDuod[n2], d2AlongGCFundusEndToDuod[n2], - xAlongGCFundusEndToDuod[n2 + 1], d2AlongGCFundusEndToDuod[n2 + 1]) + arcLengthGCFromFundusEnd += interp.getCubicHermiteArcLength(xAlongGCFundusEndToDuod[n2], + d2AlongGCFundusEndToDuod[n2], + xAlongGCFundusEndToDuod[n2 + 1], + d2AlongGCFundusEndToDuod[n2 + 1]) arcLengthsGCFromFundusEnd.append(arcLengthGCFromFundusEnd) arcLengthGCFundusEndToDuod = arcLengthGCFromFundusEnd @@ -827,7 +706,6 @@ def generateBaseMesh(cls, region, options): length = arcLengthsGCFromFundusEnd[e] for i in range(len(arcLengthRatioForGroupsFromFundusEnd)): groupLength += arcLengthRatioForGroupsFromFundusEnd[i] * arcLengthGCFundusEndToDuod - if e == len(arcLengthsGCFromFundusEnd) - 2: elementsCount += 1 elementsCountAlongGroups.append(elementsCount) @@ -855,39 +733,12 @@ def generateBaseMesh(cls, region, options): for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) - # for n2 in range(len(xAlongUpFundus)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongUpFundus[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2AlongUpFundus[n2]) - # nodeIdentifier += 1 - # - # for n2 in range(len(xAlongGCFundusEndToDuod)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongGCFundusEndToDuod[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2AlongGCFundusEndToDuod[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # for n2 in range(len(xOesoToDuodGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - arcLength = 0.0 - for e in range(len(xOesoToDuodGC) - 1): - arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], - xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) - if arcLength > arcLengthOesoApex: - nodesCountFromOesoToApex = e + 2 + for e in range(len(xEsoToDuodGC) - 1): + arcLength += interp.getCubicHermiteArcLength(xEsoToDuodGC[e], d2EsoToDuodGC[e], + xEsoToDuodGC[e + 1], d2EsoToDuodGC[e + 1]) + if arcLength > arcLengthEsoApex: + nodesCountFromEsoToApex = e + 2 break ptsOnTrackSurfaceGC = [] @@ -898,49 +749,34 @@ def generateBaseMesh(cls, region, options): # Rings adjacent to triple point (excluding triple point rings) to 6 point junction # First half - for n2 in range(elementsAroundQuarterOeso + 1, elementsAroundHalfOeso): + for n2 in range(elementsAroundQuarterEso + 1, elementsAroundHalfEso): ostiumIdx = n2 GCIdx = elementsAroundHalfDuod - 1 + n2 - GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xEsoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) - endPosition = o1_Positions[ostiumIdx] rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) d2 = o1_d2[1][ostiumIdx] d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] - xFirstHalf, d1FirstHalf = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, endProportion2, elementsAroundHalfDuod + 1, startDerivative=d1GC, endDerivative=d1EndOstium, endDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude(d2)) - - # for n2 in range(len(xFirstHalf)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstHalf[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1FirstHalf[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # Second half ostiumIdx2 = -n2 startPosition = o1_Positions[ostiumIdx2] d1StartOstium = o1_d2[1][ostiumIdx2] startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] - xSecondHalf, d1SecondHalf = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, - GCProportion2, elementsAroundHalfDuod + 1, startDerivative=d1StartOstium, - endDerivative=d1GC, - startDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude( - d1StartOstium)) + GCProportion2, elementsAroundHalfDuod + 1, + startDerivative=d1StartOstium, endDerivative=d1GC, + startDerivativeMagnitude=annulusDerivativeFactor * + vector.magnitude(d1StartOstium)) xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] @@ -949,11 +785,10 @@ def generateBaseMesh(cls, region, options): d1AlongAround.append(d1Around) # Elements downstream of 6 pt junction - xTests = [] # KM - for idx in range(-(elementsCountAlong - elementsAroundHalfOeso - 1), 0): + for idx in range(-(elementsCountAlong - elementsAroundHalfEso - 1), 0): # Search for point on central path and use that to make ellipse - xStart = xOesoToDuodGC[idx] - startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], + xStart = xEsoToDuodGC[idx] + startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xEsoToDuodGC[idx], ptsOnTrackSurfaceGC, trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) @@ -967,10 +802,8 @@ def generateBaseMesh(cls, region, options): xOnGCNextElem = [sx[closestIdxOnCentralPath + 1][c] + sd2[closestIdxOnCentralPath + 1][c] for c in range(3)] distBetweenXOnGCNextElem = vector.magnitude([xStart[c] - xOnGCNextElem[c] for c in range(3)]) eiLowerLimit = closestIdxOnCentralPath - (1 if distBetweenXOnGCNextElem > distBetweenXOnGCPrevElem else 0) - elif closestIdxOnCentralPath == len(sx) - 1: eiLowerLimit = closestIdxOnCentralPath - 1 - elif closestIdxOnCentralPath == 0: eiLowerLimit = closestIdxOnCentralPath @@ -1020,36 +853,36 @@ def generateBaseMesh(cls, region, options): sd2[eiLowerLimit + 1], sd12[eiLowerLimit + 1], xiProjection) axis2 = interp.interpolateCubicHermite(sd3[eiLowerLimit], sd13[eiLowerLimit], sd3[eiLowerLimit + 1], sd13[eiLowerLimit + 1], xiProjection) - xAround, d1Around = createEllipsePoints(xProjection, 2 * math.pi, axis1, axis2, elementsCountAroundDuod, startRadians=0.0) + xAround, d1Around = createEllipsePoints(xProjection, 2 * math.pi, axis1, axis2, elementsCountAroundDuod, + startRadians=0.0) elif startProportion2 == 0: - xAround, d1Around = createEllipsePoints(sx[0], 2 * math.pi, sd2[0], sd3[0], - elementsCountAroundDuod, startRadians=0.0) + xAround, d1Around = createEllipsePoints(sx[0], 2 * math.pi, sd2[0], sd3[0], elementsCountAroundDuod, + startRadians=0.0) elif startProportion2 == 1.0: - xAround, d1Around = createEllipsePoints(sx[-1], 2 * math.pi, sd2[-1], sd3[-1], - elementsCountAroundDuod, startRadians=0.0) + xAround, d1Around = createEllipsePoints(sx[-1], 2 * math.pi, sd2[-1], sd3[-1], elementsCountAroundDuod, + startRadians=0.0) - d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) + d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around, + magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) - # Average adjacent ring with first downstream ring that is not adjacent to oesophagus - if idx == -(elementsCountAlong - elementsAroundHalfOeso - 1): + # Average adjacent ring with first downstream ring that is not adjacent to esophagus + if idx == -(elementsCountAlong - elementsAroundHalfEso - 1): xAve = [] dAve = [] - xAve.append(xOesoToDuodGC[idx - 1]) + xAve.append(xEsoToDuodGC[idx - 1]) for n in range(1, elementsCountAroundDuod): startPosition = trackSurfaceStomach.findNearestPosition(xAround[n]) startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - if n == elementsAroundHalfDuod: # Point to search for 6 point junction - Work here if need to move 6pt junction closer to annulus - endPosition = o1_Positions[elementsAroundHalfOeso] + if n == elementsAroundHalfDuod: + endPosition = o1_Positions[elementsAroundHalfEso] else: endPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[-1][n + (0 if n < elementsAroundHalfDuod else 1)]) endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - xSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, endProportion1, endProportion2, 2)[0] - #endDerivativeMagnitude = annulusDerivativeFactor * vector.magnitude(o1_d2[1][elementsAroundHalfOeso]))[0] - + xSampled = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, endProportion1, endProportion2, + 2)[0] xAve.append(xSampled[1]) for n in range(len(xAve)): @@ -1058,48 +891,32 @@ def generateBaseMesh(cls, region, options): d1 = findDerivativeBetweenPoints(v1, v2) dAve.append(d1) dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) - xAlongAround.append(xAve) d1AlongAround.append(dAve) - xAlongAround.append(xAround) d1AlongAround.append(d1Around) - # for n2 in range(len(xAlongAround)): - # for n1 in range(len(xAlongAround[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround - ptsOnTrackSurfaceOesoToFundus = [] + ptsOnTrackSurfaceEsoToFundus = [] for n2 in range(elementsCountAlongTrackSurface + 1): - ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][elementsAroundHalfDuod]) + ptsOnTrackSurfaceEsoToFundus.append(xSampledAll[n2][elementsAroundHalfDuod]) xLoopsRight = [] xLoopsLeft = [] - d2LoopsRight = [] # KM - d2LoopsLeft = [] # KM - - for nLoop in range(1, elementsAroundHalfDuod - 1): #3): + for nLoop in range(1, elementsAroundHalfDuod - 1): GCIdx = nLoop + 1 - if GCIdx < nodesCountFromOesoToApex: - ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus + if GCIdx < nodesCountFromEsoToApex: + ptsOnTrackSurface = ptsOnTrackSurfaceEsoToFundus proportion1 = 0.5 else: ptsOnTrackSurface = ptsOnTrackSurfaceGC proportion1 = 0.0 - d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], + d2GC = findClosestPositionAndDerivativeOnTrackSurface(xEsoToDuodGC[GCIdx], ptsOnTrackSurface, trackSurfaceStomach, proportion1, elementsCountAlongTrackSurface)[1] - - if GCIdx < nodesCountFromOesoToApex: - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + if GCIdx < nodesCountFromEsoToApex: + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2EsoToDuodGC[GCIdx]), math.pi) d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] d2GC = d2GCRot @@ -1109,22 +926,22 @@ def generateBaseMesh(cls, region, options): d2End = [xAlongAround[1][elementsAroundHalfDuod - nLoop][c] - xAlongAround[0][elementsAroundHalfDuod - nLoop][c] for c in range(3)] else: - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2EsoToDuodGC[GCIdx]), math.pi) d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in range(3)] d2GC = d2GCRot xEnd = xAlongAround[0][elementsAroundHalfDuod + 1 + nLoop] d2End = [xAlongAround[1][elementsAroundHalfDuod + nLoop][c] - - xAlongAround[0][elementsAroundHalfDuod + (0 if elementsCountAroundOeso > 8 else 1) + nLoop][c] for c in range(3)] + xAlongAround[0][elementsAroundHalfDuod + (0 if elementsCountAroundEso > 8 else 1) + nLoop][c] for c in range(3)] - nx = [xOesoToDuodGC[GCIdx], xEnd] + nx = [xEsoToDuodGC[GCIdx], xEnd] nd2 = [d2GC, d2End] - x, d2 = interp.sampleCubicHermiteCurves(nx, nd2, elementsAroundQuarterOeso + 2, arcLengthDerivatives=True)[0:2] + x, d2 = interp.sampleCubicHermiteCurves(nx, nd2, elementsAroundQuarterEso + 2, arcLengthDerivatives=True)[0:2] # Find closest sampled points onto track surface xProjectedPoints = [] d2ProjectedPoints = [] - xProjectedPoints.append(xOesoToDuodGC[GCIdx]) + xProjectedPoints.append(xEsoToDuodGC[GCIdx]) d2ProjectedPoints.append(d2GC) for n2 in range(1, len(x)): projectedPosition = trackSurfaceStomach.findNearestPosition(x[n2]) @@ -1137,34 +954,11 @@ def generateBaseMesh(cls, region, options): d2ProjectedPoints.append(d2End) # Sample points again - xLoop, d2Loop = interp.sampleCubicHermiteCurves(xProjectedPoints, d2ProjectedPoints, - elementsAroundQuarterOeso + 2, - addLengthEnd=0.5 * vector.magnitude( - d2ProjectedPoints[-1]), - lengthFractionEnd=0.5, - arcLengthDerivatives=True)[0:2] + xLoop = interp.sampleCubicHermiteCurves(xProjectedPoints, d2ProjectedPoints, + elementsAroundQuarterEso + 2, + addLengthEnd=0.5 * vector.magnitude(d2ProjectedPoints[-1]), + lengthFractionEnd=0.5, arcLengthDerivatives=True)[0] (xLoopsRight if nSide == 0 else xLoopsLeft).append(xLoop) - (d2LoopsRight if nSide == 0 else d2LoopsLeft).append(d2Loop) - - # for n2 in range(len(xLoopsRight)): - # for n1 in range(len(xLoopsRight[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsRight[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LoopsRight[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # for n2 in range(len(xLoopsLeft)): - # for n1 in range(len(xLoopsLeft[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopsLeft[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LoopsLeft[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 # Find triple point xTriplePts = [[None], [None]] # Right, left @@ -1173,7 +967,7 @@ def generateBaseMesh(cls, region, options): d3TriplePtsNorm = [[None], [None]] for nSide in range(2): - ostiumIdx = elementsAroundQuarterOeso if nSide == 0 else -elementsAroundQuarterOeso + ostiumIdx = elementsAroundQuarterEso if nSide == 0 else -elementsAroundQuarterEso p1x = o1_x[1][ostiumIdx] d = o1_d2[1][ostiumIdx] rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][ostiumIdx], math.pi) @@ -1181,13 +975,13 @@ def generateBaseMesh(cls, region, options): p1d = [annulusDerivativeFactor * c for c in p1d] xLoops = xLoopsRight if nSide == 0 else xLoopsLeft - p2x = xLoops[0][elementsAroundQuarterOeso + 1] # downstream bifurcation - p2d = findDerivativeBetweenPoints(xLoops[0][elementsAroundQuarterOeso + 1], - xLoops[1][elementsAroundQuarterOeso + 1]) + p2x = xLoops[0][elementsAroundQuarterEso + 1] # downstream bifurcation + p2d = findDerivativeBetweenPoints(xLoops[0][elementsAroundQuarterEso + 1], + xLoops[1][elementsAroundQuarterEso + 1]) - p3x = xLoops[0][elementsAroundQuarterOeso] - p3d = findDerivativeBetweenPoints(xLoops[0][elementsAroundQuarterOeso], - xLoops[1][elementsAroundQuarterOeso]) + p3x = xLoops[0][elementsAroundQuarterEso] + p3d = findDerivativeBetweenPoints(xLoops[0][elementsAroundQuarterEso], + xLoops[1][elementsAroundQuarterEso]) xTriplePts[nSide], d1TriplePts[nSide], d2TriplePts[nSide] = get_bifurcation_triple_point(p1x, p1d, p2x, p2d, @@ -1200,64 +994,30 @@ def generateBaseMesh(cls, region, options): triplePointPosition = trackSurfaceStomach.findNearestPosition(xTriplePts[nSide]) xTriplePts[nSide] = trackSurfaceStomach.evaluateCoordinates(triplePointPosition) - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p1x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p1d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p2x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p2d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p3x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p3d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3TriplePtsNorm[nSide]) - # nodeIdentifier += 1 - - # Plan A - Sample points from GC to bottom of loops to create nodes running on row 2 + # Sample points from GC to bottom of loops to create nodes running on row 2 xBifurcationRings = [] d1BifurcationRings = [] xUp = [] d1Up = [] - for n2 in range(elementsAroundQuarterOeso): - xAround = [] - d1Around = [] + for n2 in range(elementsAroundQuarterEso): xAroundRight = [] d1AroundRight = [] xAroundLeft = [] d1AroundLeft = [] loopIdx = n2 + 2 - ostiumIdx = loopIdx + (0 if n2 < elementsAroundQuarterOeso - 1 else -1) - GCIdx = elementsAlongGCFromOesoToFundusEnd - elementsAroundQuarterOeso + n2 + (2 if useLimitingRidge else 1) - d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + ostiumIdx = loopIdx + (0 if n2 < elementsAroundQuarterEso - 1 else -1) + GCIdx = elementsAlongGCFromEsoToFundusEnd - elementsAroundQuarterEso + n2 + (2 if limitingRidge else 1) + d1GC = findClosestPositionAndDerivativeOnTrackSurface(xEsoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface)[1] for nSide in range(2): if nSide == 0: # Right side - xAroundRight.append(xOesoToDuodGC[GCIdx]) + xAroundRight.append(xEsoToDuodGC[GCIdx]) d1AroundRight.append(d1GC) xOnLastLoopRight = xLoopsRight[-1][loopIdx] d1OnLastLoopRight = findDerivativeBetweenPoints(xLoopsRight[-1][loopIdx], xLoopsRight[-2][loopIdx]) - nx = [xOesoToDuodGC[GCIdx], xOnLastLoopRight] + nx = [xEsoToDuodGC[GCIdx], xOnLastLoopRight] nd1 = [d1GC, d1OnLastLoopRight] x, d1 = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] @@ -1268,7 +1028,6 @@ def generateBaseMesh(cls, region, options): # Sample points again x, d1 = interp.sampleCubicHermiteCurves(x, d1, 2, arcLengthDerivatives=True)[0:2] - xAroundRight.append(x[1]) d1AroundRight.append(d1[1]) @@ -1276,7 +1035,7 @@ def generateBaseMesh(cls, region, options): xAroundRight.append(xLoopsRight[-(1 + n)][loopIdx]) d1AroundRight.append(findDerivativeBetweenPoints(xLoopsRight[-(1 + n)][loopIdx], xLoopsRight[-(1 + n + 1)][loopIdx])) - if loopIdx < elementsAroundQuarterOeso: # additional elements upstream of triple point + if loopIdx < elementsAroundQuarterEso: # additional elements upstream of triple point xLoop = xLoopsRight[0][loopIdx] xLoopPosition = trackSurfaceStomach.findNearestPosition(xLoop) xLoopProportion1, xLoopProportion2 = trackSurfaceStomach.getProportion(xLoopPosition) @@ -1288,7 +1047,7 @@ def generateBaseMesh(cls, region, options): xSampled, dSampled = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, xLoopProportion1, xLoopProportion2, ostiumProportion1, - ostiumProportion2, 2, # startDerivative=d, + ostiumProportion2, 2, endDerivativeMagnitude=endDerivativeMag)[0:2] xAroundRight += xSampled[:2] d1AroundRight += dSampled[:2] @@ -1298,17 +1057,8 @@ def generateBaseMesh(cls, region, options): d1AroundRight += [findDerivativeBetweenPoints(xLoopsRight[0][loopIdx], xTriplePts[0])] + \ [d1TriplePts[0]] - # for n1 in range(len(xAroundRight)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundRight[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1AroundRight[n1]) - # nodeIdentifier += 1 - else: # left side - if loopIdx < elementsAroundQuarterOeso: # additional elements upstream of triple point + if loopIdx < elementsAroundQuarterEso: # additional elements upstream of triple point xLoop = xLoopsLeft[0][loopIdx] xLoopPosition = trackSurfaceStomach.findNearestPosition(xLoop) xLoopProportion1, xLoopProportion2 = trackSurfaceStomach.getProportion(xLoopPosition) @@ -1318,8 +1068,9 @@ def generateBaseMesh(cls, region, options): d = findDerivativeBetweenPoints(xOstium, xLoop) startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, - xLoopProportion1, xLoopProportion2, 2, # endDerivative=d, + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, + ostiumProportion2, xLoopProportion1, + xLoopProportion2, 2, startDerivativeMagnitude=startDerivativeMag)[0:2] xAroundLeft.append(xSampled[1]) d1AroundLeft.append(dSampled[1]) @@ -1334,7 +1085,7 @@ def generateBaseMesh(cls, region, options): xOnLastLoopLeft = xLoopsLeft[-1][loopIdx] d1OnLastLoopLeft = findDerivativeBetweenPoints(xLoopsLeft[-2][loopIdx], xLoopsLeft[-1][loopIdx]) - nx = [xOnLastLoopLeft, xOesoToDuodGC[GCIdx]] + nx = [xOnLastLoopLeft, xEsoToDuodGC[GCIdx]] nd1 = [d1OnLastLoopLeft, d1GC] x, d1 = interp.sampleCubicHermiteCurves(nx, nd1, 2, arcLengthDerivatives=True)[0:2] @@ -1345,49 +1096,18 @@ def generateBaseMesh(cls, region, options): # Sample points again x, d1 = interp.sampleCubicHermiteCurves(x, d1, 2, arcLengthDerivatives=True)[0:2] - - xAroundLeft += [xOnLastLoopLeft] + [x[1]] + [xOesoToDuodGC[GCIdx]] + xAroundLeft += [xOnLastLoopLeft] + [x[1]] + [xEsoToDuodGC[GCIdx]] d1AroundLeft += [findDerivativeBetweenPoints(xOnLastLoopLeft, x[1])] + [d1[1]] + [d1GC] - # for n1 in range(len(xAroundLeft)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundLeft[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1AroundLeft[n1]) - # nodeIdentifier += 1 - xAround = xAroundRight + xAroundLeft[:-1] d1Around = d1AroundRight + d1AroundLeft[:-1] - xUp.append(xAround) d1Up.append(d1Around) - if loopIdx >= elementsAroundQuarterOeso: + if loopIdx >= elementsAroundQuarterEso: xBifurcationRings.append(xAround) d1BifurcationRings.append(d1Around) - # for n2 in range(len(xBifurcationRings)): - # for n1 in range(len(xBifurcationRings[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBifurcationRings[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1BifurcationRings[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # for n2 in range(len(xUp)): - # for n1 in range(len(xUp[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xUp[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Up[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # Row 2 xRow2Right = [] d1Row2Right = [] @@ -1417,10 +1137,10 @@ def generateBaseMesh(cls, region, options): xSampled, dSampled = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, xLoopProportion1, xLoopProportion2, ostiumProportion1, - ostiumProportion2, 2, # startDerivative=d, + ostiumProportion2, 2, endDerivativeMagnitude=endDerivativeMag)[0:2] xRow2Right += xSampled[0:2] - d1Row2Right += [findDerivativeBetweenPoints(xSampled[0], xSampled[1])] + [dSampled[1]] # dSampled[0:2] + d1Row2Right += [findDerivativeBetweenPoints(xSampled[0], xSampled[1])] + [dSampled[1]] else: xLoop = xLoopsLeft[0][loopIdx] @@ -1434,7 +1154,7 @@ def generateBaseMesh(cls, region, options): xSampled, dSampled = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, - xLoopProportion1, xLoopProportion2, 2, # endDerivative=d, + xLoopProportion1, xLoopProportion2, 2, startDerivativeMagnitude=startDerivativeMag)[0:2] xRow2Left += xSampled[1:] d1Row2Left += [dSampled[1]] + [findDerivativeBetweenPoints(xSampled[1], xSampled[2])] @@ -1446,37 +1166,18 @@ def generateBaseMesh(cls, region, options): xRow2Left.append(xUp[0][-1]) d1Row2Left.append(findDerivativeBetweenPoints(xLoopsLeft[-1][1], xUp[0][-1])) - # for n1 in range(len(xRow2Right)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Right[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Right[n1]) - # # print(vector.magnitude(d1Row2Right[n1]), vector.magnitude(d1Row2Left[-(1+n1)])) - # nodeIdentifier += 1 - # - # for n1 in range(len(xRow2Left)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Left[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Left[n1]) - # nodeIdentifier += 1 - # Smooth derivatives from triple point to 6 point junction # Start from GC at upstream bifurcation ring to annulus to 6 point junction ring on right then left xLoopTripleTo6Pt = [] dLoopTripleTo6Pt = [] xLoopTripleTo6Pt += xBifurcationRings[0][0:int(len(xBifurcationRings[0]) * 0.5) + 1] - for n2 in range(elementsAroundQuarterOeso - 1): + for n2 in range(elementsAroundQuarterEso - 1): xLoopTripleTo6Pt.append(xAlongAround[n2][int(len(xAlongAround[n2]) * 0.5)]) junctionIdx = n2 + 1 xLoopTripleTo6Pt += xAlongAround[junctionIdx][int(len(xAlongAround[junctionIdx]) * 0.5):] + \ xAlongAround[junctionIdx][0: int(len(xAlongAround[junctionIdx]) * 0.5 + 1)] - for n2 in range(elementsAroundQuarterOeso - 1): # Note order here - going upstream + for n2 in range(elementsAroundQuarterEso - 1): # Note order here - going upstream idx = junctionIdx - 1 - n2 xLoopTripleTo6Pt.append(xAlongAround[idx][int(len(xAlongAround[idx]) * 0.5) + 1]) xLoopTripleTo6Pt += xBifurcationRings[0][int(len(xBifurcationRings[0]) * 0.5 + 1):] @@ -1485,16 +1186,6 @@ def generateBaseMesh(cls, region, options): d = findDerivativeBetweenPoints(xLoopTripleTo6Pt[n], xLoopTripleTo6Pt[(n+1) % len(xLoopTripleTo6Pt)]) dLoopTripleTo6Pt.append(d) dSmoothLoopTripleTo6Pt = interp.smoothCubicHermiteDerivativesLoop(xLoopTripleTo6Pt, dLoopTripleTo6Pt) - # curvature - DONE - - # for n1 in range(len(xLoopTripleTo6Pt)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopTripleTo6Pt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopTripleTo6Pt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) - # nodeIdentifier += 1 # Smooth derivatives around top loop # Starts from GC at downstream bifurcation ring to annulus and back @@ -1503,13 +1194,13 @@ def generateBaseMesh(cls, region, options): xLoopGCTriplePt += xBifurcationRings[1][:int(len(xBifurcationRings[1]) * 0.5) + 1] - for n2 in range(elementsAroundQuarterOeso - 2): + for n2 in range(elementsAroundQuarterEso - 2): idx = -(3 + n2) xLoopGCTriplePt.append(xUp[idx][int(len(xUp[idx]) * 0.5)]) - xLoopGCTriplePt += [xRow2Right[-1]] + [xOesoToDuodGC[1]] + [xRow2Left[0]] + xLoopGCTriplePt += [xRow2Right[-1]] + [xEsoToDuodGC[1]] + [xRow2Left[0]] - for n2 in range(elementsAroundQuarterOeso - 2): + for n2 in range(elementsAroundQuarterEso - 2): xLoopGCTriplePt.append(xUp[n2][int(len(xUp[n2]) * 0.5) + 1]) xLoopGCTriplePt += xBifurcationRings[1][int(len(xBifurcationRings[1]) * 0.5) + 1:] @@ -1518,23 +1209,13 @@ def generateBaseMesh(cls, region, options): d = findDerivativeBetweenPoints(xLoopGCTriplePt[n], xLoopGCTriplePt[(n+1) % len(xLoopGCTriplePt)]) dLoopGCTriplePt.append(d) dSmoothLoopGCTriplePt = interp.smoothCubicHermiteDerivativesLoop(xLoopGCTriplePt, dLoopGCTriplePt) - # curvature - DONE - - # for n1 in range(len(xLoopGCTriplePt)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopGCTriplePt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopGCTriplePt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) - # nodeIdentifier += 1 # Resample loop before 6 point junction for n in range(1, elementsCountAroundDuod + 1): if elementsAroundHalfDuod <= n <= elementsAroundHalfDuod + 1: pass else: - if elementsCountAroundOeso > 8: + if elementsCountAroundEso > 8: xStart = xAlongAround[-(elementsAlongAnnulusToDuod + 3)][n] else: xStart = xUp[-1][n] @@ -1551,34 +1232,6 @@ def generateBaseMesh(cls, region, options): xNew = trackSurfaceStomach.evaluateCoordinates(xNewPosition) xAlongAround[-(elementsAlongAnnulusToDuod + 2)][n] = xNew - # xStarts = [] - # d2Starts = [] - # xEnds = [] - # d2Ends = [] - # for n in range(elementsAroundHalfDuod + 2, elementsCountAroundDuod + 1): - # if elementsCountAroundOeso > 8: - # xStart = xAlongAround[-(elementsAlongAnnulusToDuod + 3)][n] - # else: - # xStart = xUp[-1][n] - # xEnd = xAlongAround[-(elementsAlongAnnulusToDuod + 1)][n - 1] - # - # startPosition = trackSurfaceStomach.findNearestPosition(xStart) - # d2Start = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[2] - # xStarts.append(xStart) - # d2Starts.append(d2Start) - # - # endPosition = trackSurfaceStomach.findNearestPosition(xEnd) - # d2End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[2] - # xEnds.append(xEnd) - # d2Ends.append(d2End) - # - # xSampled = interp.sampleCubicHermiteCurves([xStart, xEnd], [d2Start, d2End], 2)[0] - # xNewPosition = trackSurfaceStomach.findNearestPosition(xSampled[1]) - # xNew = trackSurfaceStomach.evaluateCoordinates(xNewPosition) - # - # xAlongAround[-(elementsAlongAnnulusToDuod + 2)][n] = xNew - - # Assemble nodes and d1 xOuter = [] d1Outer = [] @@ -1587,61 +1240,42 @@ def generateBaseMesh(cls, region, options): for n2 in range(elementsCountAlong + 1): xAround = [] d1Around = [] - d2Around = [] if n2 == 0: - # print(n2, 'GC') for i in range(elementsAroundHalfDuod - 2): - xAround.append(xOesoToDuodGC[i + 1]) - d1Around.append(d2OesoToDuodGC[i + 1]) + xAround.append(xEsoToDuodGC[i + 1]) + d1Around.append(d2EsoToDuodGC[i + 1]) elif n2 == 1: - # print(n2, 'Row 2') - xAround = [xOesoToDuodGC[i + n2 + 1]] + xRow2Right[1:] + xRow2Left[:-1] - d1Around = [d2OesoToDuodGC[i + n2 + 1]] + d1Row2Right[1:] + d1Row2Left[:-1] # need to replace d1Row2 after smoothing - DONE + xAround = [xEsoToDuodGC[i + n2 + 1]] + xRow2Right[1:] + xRow2Left[:-1] + d1Around = [d2EsoToDuodGC[i + n2 + 1]] + d1Row2Right[1:] + d1Row2Left[:-1] - elif n2 > 1 and n2 < elementsAroundQuarterOeso + 2: - # print(n2, 'Before triple point + triple point') + elif n2 > 1 and n2 < elementsAroundQuarterEso + 2: xAround = xUp[countUp] - if n2 < elementsAroundQuarterOeso: # upstream of triple pt - # smooth d1 around - Make into function? + if n2 < elementsAroundQuarterEso: # upstream of triple pt d1Around = d1Up[countUp] - 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)] - d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, - fixEndDerivative=True) - # Need to do curvature and rearrange to correct order - d1Around = [] - d1Around = d1LoopSmooth[int(len(xAround) * 0.5) : ] + d1LoopSmooth[: int(len(xAround) * 0.5) : ] + d1Around = smoothD1Around(xAround, d1Around) - elif n2 == elementsAroundQuarterOeso: # upstream bifurcation + elif n2 == elementsAroundQuarterEso: # upstream bifurcation # take smoothed d1 from dSmoothTripleTo6Pt d1Around = dSmoothLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ dSmoothLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5) : ] - elif n2 > elementsAroundQuarterOeso: # downstream bifurcation + elif n2 > elementsAroundQuarterEso: # downstream bifurcation # take smoothed d1 from dSmoothGCToTriplePt d1Around = dSmoothLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ dSmoothLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5) : ] countUp += 1 - elif n2 > elementsAroundQuarterOeso + 1: - # print(n2, 'Downstream of triple point') + elif n2 > elementsAroundQuarterEso + 1: xAround = xAlongAround[countDown] d1Around = d1AlongAround[countDown] - # smooth d1 around - Make into function? - if n2 < elementsAroundHalfOeso + 1: - 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)] - d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, - fixEndDerivative=True) - # Need to do curvature and rearrange to correct order - d1Around = [] - d1Around = d1LoopSmooth[int(len(xAround) * 0.5):] + d1LoopSmooth[: int(len(xAround) * 0.5):] + if n2 < elementsAroundHalfEso + 1: + d1Around = smoothD1Around(xAround, d1Around) - elif n2 == elementsAroundHalfOeso + 1: # 6 point junction ring + elif n2 == elementsAroundHalfEso + 1: # 6 point junction ring # take smoothed d1 from dSmoothedTripleTo6Pt - startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsAroundQuarterOeso + len(xAlongAround[junctionIdx]) * 0.5) + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsAroundQuarterEso + len(xAlongAround[junctionIdx]) * 0.5) endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 d1Around = dSmoothLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ @@ -1651,16 +1285,6 @@ def generateBaseMesh(cls, region, options): xOuter.append(xAround) d1Outer.append(d1Around) - # for m2 in range(len(xOuter)): - # for m1 in range(len(xOuter[m2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # Calculate d2 xRegularLoops = [] d2RegularLoops = [] @@ -1674,9 +1298,9 @@ def generateBaseMesh(cls, region, options): idx = -(1 + n2) xRegularLoop.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) d1RegularRightLoop.append(d1Outer[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - xRegularLoop.append(xOesoToDuodGC[n1 + 2]) + xRegularLoop.append(xEsoToDuodGC[n1 + 2]) for n2 in range(elementsCountAlong): - xRegularLoop.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfOeso else 2))]) + xRegularLoop.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfEso else 2))]) for n in range(len(xRegularLoop) - 1): d = findDerivativeBetweenPoints(xRegularLoop[n], xRegularLoop[n+1]) @@ -1685,7 +1309,6 @@ def generateBaseMesh(cls, region, options): d2SmoothRegularLoop = interp.smoothCubicHermiteDerivativesLine(xRegularLoop, d2RegularLoop) d2SmoothRegularOrderedLoop = copy.deepcopy(d2SmoothRegularLoop) - # curvature - DONE # Switch direction on right side for n2 in range(elementsCountAlong): @@ -1693,21 +1316,10 @@ def generateBaseMesh(cls, region, options): rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) d = d2SmoothRegularLoop[n2] d2SmoothRegularLoop[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - xRegularLoops.append(xRegularLoop) d2RegularLoops.append(d2SmoothRegularLoop) d2RegularOrderedLoops.append(d2SmoothRegularOrderedLoop) - # for m1 in range(len(xRegularLoops)): - # for m2 in range(len(xRegularLoops[m1])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRegularLoops[m1][m2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2RegularOrderedLoops[m1][m2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #d2RegularLoops[m1][m2]) - # nodeIdentifier += 1 - # Smooth d2 along row 2 xLoop2Right = [] d1Loop2Right = [] @@ -1724,9 +1336,7 @@ def generateBaseMesh(cls, region, options): d = findDerivativeBetweenPoints(xLoop2Right[n], xLoop2Right[n + 1]) d2Loop2Right.append(d) d2Loop2Right.append(d1Row2Right[-1]) - d2Loop2Right = interp.smoothCubicHermiteDerivativesLine(xLoop2Right, d2Loop2Right, fixEndDirection=True) - # curvature - USING LEFT SIDE - DONE # Switch direction of d2 for downstream nodes for n2 in range(len(xAlongAround) + len(xUp)): @@ -1737,19 +1347,9 @@ def generateBaseMesh(cls, region, options): d2Loop2Right[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] idxSwitchToD1 = n2 - # for m in range(len(xLoop2Right)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Right[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) #d2Loop2Right[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Loop2Right[m]) - # nodeIdentifier += 1 - # Left xLoop2Left = [] d2Loop2Left = [] - xLoop2Left += xRow2Left for n2 in range(3, len(xOuter)): xLoop2Left.append(xOuter[n2][-1]) @@ -1761,21 +1361,11 @@ def generateBaseMesh(cls, region, options): d2Loop2Left.append(d) d2Loop2Left = interp.smoothCubicHermiteDerivativesLine(xLoop2Left, d2Loop2Left, fixStartDirection=True) - # curvature - DONE - - # for m in range(len(xLoop2Left)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Left[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Loop2Left[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 # Smooth lower curvature xLC = [] d2LC = [] - for n2 in range(elementsAroundHalfOeso + 1, elementsCountAlong + 1): + for n2 in range(elementsAroundHalfEso + 1, elementsCountAlong + 1): xLC.append(xOuter[n2][int(len(xOuter[n2]) * 0.5)]) for n in range(len(xLC) - 1): @@ -1784,33 +1374,14 @@ def generateBaseMesh(cls, region, options): d2LC.append(d) d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC, fixStartDirection=True) - # curvature - DONE - - # for m in range(len(xLC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLC[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LC[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 # Smooth greater curvature d2GC = [] - for n in range(len(xOesoToDuodGC) - 1): - d = findDerivativeBetweenPoints(xOesoToDuodGC[n], xOesoToDuodGC[n + 1]) + for n in range(len(xEsoToDuodGC) - 1): + d = findDerivativeBetweenPoints(xEsoToDuodGC[n], xEsoToDuodGC[n + 1]) d2GC.append(d) d2GC.append(d) - d2GC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2GC, fixStartDirection=True) - - # for m in range(len(xOesoToDuodGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2GC[m]) - # nodeIdentifier += 1 + d2GC = interp.smoothCubicHermiteDerivativesLine(xEsoToDuodGC, d2GC, fixStartDirection=True) # Update d1 for upstream nodes for n1 in range(1, len(xRow2Right)): @@ -1822,121 +1393,85 @@ def generateBaseMesh(cls, region, options): d2Outer = [] for n2 in range(elementsCountAlong + 1): d2Around = [] - xAround = [] # KM if n2 == 0: - # print(n2, 'GC') - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5)]) #KM d2Around.append(dSmoothLoopGCTriplePt[int(len(dSmoothLoopGCTriplePt) * 0.5)]) - for n1 in range(len(xOuter[0]) - 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) d2Around.append(d2RegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) nextIdx = n1 + 1 - elif n2 == 1: - # print(n2, 'Row 2') - xAround.append(xRegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) + elif n2 == 1: # Row 2 d2Around.append(d2RegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) # right point on annulus - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2]) # KM d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2] rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), vector.normalise(d2))) rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) d2Around.append([rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) # left point on annulus - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) # KM d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) + d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) - elif n2 > 1 and n2 < elementsAroundQuarterOeso + 2: - # print(n2, 'Before triple point + triple point') - # GC - xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + elif n2 > 1 and n2 < elementsAroundQuarterEso + 2: + # GC before triple point & triple point d2Around.append(d2GC[len(xOuter[0]) + n2]) # Row 2 right - xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) # Regular up right for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) # Annulus right - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterOeso else 0)]) # KM - d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterOeso else 0)] - if n2 <= elementsAroundQuarterOeso: # Rotate to point towards duodenum + d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterEso else 0)] + if n2 <= elementsAroundQuarterEso: # Rotate to point towards duodenum rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), vector.normalise(d2))) rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) d2Around.append( [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) - else: # just take d2 as-is cos we are going to remove this point later - d2Around.append(d2) + else: + d2Around.append(d2) # just take d2 as-is cos we are going to remove this point later # Annulus left - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsAroundQuarterOeso else 0)]) # KM - d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsAroundQuarterOeso else 0)]) + d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsAroundQuarterEso else 0)]) # Regular down left for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) # Row 2 left - xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) - # for m1 in range(len(d2Around)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Around[m1]) - # nodeIdentifier += 1 - - elif n2 > elementsAroundQuarterOeso + 1: - # print(n2, 'Downstream of triple point') - # GC - xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) + elif n2 > elementsAroundQuarterEso + 1: + # GC downstream of triple point d2Around.append(d2GC[len(xOuter[0]) + n2]) # Row 2 right - xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) # Regular up right for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) - if n2 <= elementsAroundHalfOeso + 1: - # Annulus right - # print('between triple and 6 pt') - idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsAroundQuarterOeso - 1) - xAround.append(xLoopTripleTo6Pt[idx]) - if n2 == elementsAroundHalfOeso + 1: + if n2 <= elementsAroundHalfEso + 1: + # Annulus right between triple and 6 pt + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsAroundQuarterEso - 1) + if n2 == elementsAroundHalfEso + 1: d1 = dSmoothLoopTripleTo6Pt[idx] d1Outer[n2][int(len(d1Outer[n2]) * 0.5)] = d1 else: d2Around.append(dSmoothLoopTripleTo6Pt[idx]) - # Annulus left - need to rotate to point towards duodenum - xAround.append(xLoopTripleTo6Pt[-idx]) - # d2Around.append(dSmoothLoopTripleTo6Pt[-idx]) + # Annulus left - Rotated to point towards duodenum d2 = dSmoothLoopTripleTo6Pt[-idx] - if n2 < elementsAroundHalfOeso + 1: + if n2 < elementsAroundHalfEso + 1: rotAxis = vector.normalise( vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5 + 1)]), vector.normalise(d2))) @@ -1948,25 +1483,20 @@ def generateBaseMesh(cls, region, options): [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) - elif n2 > elementsAroundHalfOeso + 1: - # print('beyond 6 pt') - # LC - xAround.append(xLC[n2 - (elementsAroundHalfOeso + 1)]) - d2Around.append(d2LC[n2 - (elementsAroundHalfOeso + 1)]) + elif n2 > elementsAroundHalfEso + 1: + # LC - beyond 6 pt junction + d2Around.append(d2LC[n2 - (elementsAroundHalfEso + 1)]) # Regular down left for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) # Row 2 left - xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) - d2Outer.append(d2Around) # remove triple point on both sides from downstream ring - n2Idx = elementsAroundQuarterOeso + 1 + n2Idx = elementsAroundQuarterEso + 1 n1Idx = int(len(xOuter[n2Idx]) * 0.5) del xOuter[n2Idx][n1Idx: n1Idx + 2], d1Outer[n2Idx][n1Idx: n1Idx + 2], d2Outer[n2Idx][n1Idx: n1Idx + 2] @@ -1978,18 +1508,8 @@ def generateBaseMesh(cls, region, options): vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) d3UnitOuter.append(d3Around) - # for m2 in range(len(xOuter)): - # for m1 in range(len(xOuter[m2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[m2][m1]) - # nodeIdentifier += 1 - # Calculate curvatures - # Curvatures along GC + # Curvature along GC xGC = [] dGC = [] norms = [] @@ -2003,141 +1523,87 @@ def generateBaseMesh(cls, region, options): norms.append(d3UnitOuter[n2][0]) curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 - # for m1 in range(len(xGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Curvature along rows adjacent to GC - calculate with left and use the same for right + # Curvature along rows adjacent to GC - calculate with left and use for right as well norms = [] - xTest = [] - for n in range(int(len(xOuter[1]) * 0.5)): # d1s - xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM + for n in range(int(len(xOuter[1]) * 0.5)): # d1 norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) - for n2 in range(2, elementsCountAlong + 1): # d2s - xTest.append(xOuter[n2][-1]) # KM + for n2 in range(2, elementsCountAlong + 1): # d2 norms.append(d3UnitOuter[n2][-1]) curvatureAlong2Left = findCurvatureAlongLine(xLoop2Left, d2Loop2Left, norms) - # for m1 in range(len(xTest)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTest[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, norms[m1]) - # nodeIdentifier += 1 - # Curvature along LC - xTest = [] # KM norms = [] - for n in range(elementsAroundHalfOeso + 1, elementsCountAlong + 1): - xTest.append(xOuter[n][int(len(xOuter[n]) * 0.5)]) + for n in range(elementsAroundHalfEso + 1, elementsCountAlong + 1): norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) curvatureAlongLC = findCurvatureAlongLine(xLC[1:], d2LC[1:], norms) # Curvature along path from triple point to 6 point junction - xTest = [] # KM norms = [] idxToAnnulus = elementsAroundHalfDuod + 1 - xTest += xOuter[elementsAroundQuarterOeso][: idxToAnnulus] - norms += d3UnitOuter[elementsAroundQuarterOeso][:idxToAnnulus] + norms += d3UnitOuter[elementsAroundQuarterEso][:idxToAnnulus] - for n2 in range(elementsAroundQuarterOeso): - idx = elementsAroundQuarterOeso + 2 + n2 - if idx < elementsAroundHalfOeso + 1: - xTest.append(xOuter[idx][idxToAnnulus - 1]) + for n2 in range(elementsAroundQuarterEso): + idx = elementsAroundQuarterEso + 2 + n2 + if idx < elementsAroundHalfEso + 1: norms.append(d3UnitOuter[idx][idxToAnnulus - 1]) - xTest += xOuter[elementsAroundHalfOeso + 1][idxToAnnulus - 1:] + \ - xOuter[elementsAroundHalfOeso + 1][: idxToAnnulus] - norms += d3UnitOuter[elementsAroundHalfOeso + 1][idxToAnnulus - 1:] + \ - d3UnitOuter[elementsAroundHalfOeso + 1][: idxToAnnulus] - - for n2 in range(elementsAroundQuarterOeso - 1): - idx = elementsAroundHalfOeso - n2 - xTest.append(xOuter[idx][idxToAnnulus]) - norms.append(d3UnitOuter[idx][idxToAnnulus]) - - xTest += xOuter[elementsAroundQuarterOeso][idxToAnnulus:] - norms += d3UnitOuter[elementsAroundQuarterOeso][idxToAnnulus:] + norms += d3UnitOuter[elementsAroundHalfEso + 1][idxToAnnulus - 1:] + \ + d3UnitOuter[elementsAroundHalfEso + 1][: idxToAnnulus] + for n2 in range(elementsAroundQuarterEso - 1): + idx = elementsAroundHalfEso - n2 + norms.append(d3UnitOuter[idx][idxToAnnulus]) + norms += d3UnitOuter[elementsAroundQuarterEso][idxToAnnulus:] curvatureLoopTripleTo6Pt = findCurvatureAroundLoop(xLoopTripleTo6Pt, dSmoothLoopTripleTo6Pt, norms) # Curvature along path from GC to triple point - xTest = [] # KM norms = [] - xTest += xOuter[elementsAroundQuarterOeso + 1][:idxToAnnulus - 1] - norms += d3UnitOuter[elementsAroundQuarterOeso + 1][:idxToAnnulus - 1] - - for n2 in range(elementsAroundQuarterOeso): - idx = elementsAroundQuarterOeso - n2 - xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5)]) + norms += d3UnitOuter[elementsAroundQuarterEso + 1][:idxToAnnulus - 1] + for n2 in range(elementsAroundQuarterEso): + idx = elementsAroundQuarterEso - n2 norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5)]) - xTest.append(xOuter[0][0]) norms.append(d3UnitOuter[0][0]) - for n2 in range(1, elementsAroundQuarterOeso + 1): - xTest.append(xOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) + for n2 in range(1, elementsAroundQuarterEso + 1): norms.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) - xTest += xOuter[elementsAroundQuarterOeso + 1][idxToAnnulus - 1:] - norms += d3UnitOuter[elementsAroundQuarterOeso + 1][idxToAnnulus - 1:] + norms += d3UnitOuter[elementsAroundQuarterEso + 1][idxToAnnulus - 1:] curvatureLoopGCTriplePt = findCurvatureAroundLoop(xLoopGCTriplePt, dSmoothLoopGCTriplePt, norms) # Curvature around regular loops curvatureRegularLoops = [] for n1 in range(elementsAroundHalfDuod - 2): - xTest = [] norms = [] for n2 in range(elementsCountAlong): idx = -(1 + n2) - xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) if n1 < elementsAroundHalfDuod - 3: - xTest.append(xOuter[0][(n1 + 1)]) norms.append(d3UnitOuter[0][n1 + 1]) else: - xTest.append(xOuter[idx][0]) norms.append(d3UnitOuter[idx][0]) for n2 in range(elementsCountAlong): - xTest.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfOeso else 2))]) norms.append(d3UnitOuter[n2 + 1][int( - len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfOeso else 2))]) + len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= elementsAroundHalfEso else 2))]) curvatureLoop = findCurvatureAlongLine(xRegularLoops[n1], d2RegularOrderedLoops[n1], norms) curvatureRegularLoops.append(curvatureLoop) # Assemble curvatures d1Curvature = [] d2Curvature = [] - countUp = 0 - countDown = 0 for n2 in range(elementsCountAlong + 1): d1CurvatureAround = [] d2CurvatureAround = [] - if n2 == 0: - # print(n2, 'GC') + if n2 == 0: # GC for i in range(elementsAroundHalfDuod - 2): d1CurvatureAround.append(curvatureAlongGC[i]) - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5)]) for n1 in range(len(xOuter[0]) - 1): d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5)]) nextIdx = n1 + 1 - - elif n2 == 1: - # print(n2, 'Row 2') + elif n2 == 1: #Row 2 d1CurvatureAround.append(curvatureAlongGC[i + n2]) - xTest = [] - dTest = [] for n in range(int(len(xOuter[1]) * 0.5) - 1, -1, -1): d1CurvatureAround.append(curvatureAlong2Left[n]) d1CurvatureAround += curvatureAlong2Left[:int(len(xOuter[1]) * 0.5)] - xTest = xLoop2Left[:int(len(xOuter[1]) * 0.5)] - dTest = d2Loop2Left[:int(len(xOuter[1]) * 0.5)] - d2CurvatureAround.append(curvatureRegularLoops[nextIdx][int(len(curvatureRegularLoops[nextIdx]) * 0.5)]) + for n1 in range(nextIdx, -1, -1): d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) # right point on annulus @@ -2147,26 +1613,19 @@ def generateBaseMesh(cls, region, options): for n1 in range(nextIdx + 1): d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) - elif n2 > 1 and n2 < elementsAroundQuarterOeso + 2: - # print(n2, 'Before triple point + triple point') + elif n2 > 1 and n2 < elementsAroundQuarterEso + 2: # Before triple pt & triple point xAround = xOuter[n2] - if n2 < elementsAroundQuarterOeso: # upstream of triple pt - # smooth d1 around - Make into function? + if n2 < elementsAroundQuarterEso: # upstream of triple pt d1Around = d1Outer[n2] - norms = d3UnitOuter[n2] - 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 = norms[int(len(d1Around) * 0.5 + 1):] + norms[: 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):] + normsAround = d3UnitOuter[n2] + d1CurvatureAround = findD1CurvatureAround(xAround, d1Around, normsAround) - elif n2 == elementsAroundQuarterOeso: # upstream bifurcation + elif n2 == elementsAroundQuarterEso: # upstream bifurcation # take smoothed d1 from dSmoothTripleTo6Pt d1CurvatureAround = curvatureLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ curvatureLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5):] - elif n2 > elementsAroundQuarterOeso: # downstream bifurcation + elif n2 > elementsAroundQuarterEso: # downstream bifurcation # take smoothed d1 from dSmoothGCToTriplePt d1CurvatureAround = curvatureLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ curvatureLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5):] @@ -2180,41 +1639,34 @@ def generateBaseMesh(cls, region, options): d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) # Annulus right d2CurvatureAround.append(curvatureLoopGCTriplePt[ - int(len(curvatureLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterOeso else 0)]) + int(len(curvatureLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsAroundQuarterEso else 0)]) # Annulus left d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2 - ( - 1 if n2 > elementsAroundQuarterOeso else 0)]) + 1 if n2 > elementsAroundQuarterEso else 0)]) # Regular down left for n1 in range(nextIdx + 1): d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) # Row 2 left d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - elif n2 > elementsAroundQuarterOeso + 1: - # print(n2, 'Downstream of triple point') + elif n2 > elementsAroundQuarterEso + 1: # Downstream of triple point xAround = xOuter[n2] d1Around = d1Outer[n2] normsAround = d3UnitOuter[n2] - # smooth d1 around - Make into function? - if n2 < elementsAroundHalfOeso + 1: - 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(normsAround) * 0.5 + 1):] + normsAround[: int(len(normsAround) * 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):] + if n2 < elementsAroundHalfEso + 1: + d1CurvatureAround = findD1CurvatureAround(xAround, d1Around, normsAround) - elif n2 == elementsAroundHalfOeso + 1: # 6 point junction ring + elif n2 == elementsAroundHalfEso + 1: # 6 point junction ring # take smoothed d1 from dSmoothedTripleTo6Pt - startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsAroundQuarterOeso + len( + startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsAroundQuarterEso + len( xAlongAround[junctionIdx]) * 0.5) endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 d1CurvatureAround = curvatureLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ curvatureLoopTripleTo6Pt[startLeftIdx: startRightIdx] - if n2 > elementsAroundHalfOeso + 1: # closed rings beyond 6 point junction + if n2 > elementsAroundHalfEso + 1: # closed rings beyond 6 point junction 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(normsAround) * 0.5 + 1):] + normsAround[ : int(len(normsAround) * 0.5 + 1)] @@ -2229,26 +1681,23 @@ def generateBaseMesh(cls, region, options): # Regular up right for n1 in range(nextIdx, -1, -1): d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) - if n2 <= elementsAroundHalfOeso + 1: - # Annulus right - # print('between triple and 6 pt') - idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsAroundQuarterOeso - 1) - if n2 == elementsAroundHalfOeso + 1: + if n2 <= elementsAroundHalfEso + 1: + # Annulus right between triple and 6 pt + idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsAroundQuarterEso - 1) + if n2 == elementsAroundHalfEso + 1: d1CurvatureAround[int(len(d1Outer[n2]) * 0.5)] = curvatureLoopTripleTo6Pt[idx] else: d2CurvatureAround.append(curvatureLoopTripleTo6Pt[idx]) # Annulus left d2CurvatureAround.append(curvatureLoopTripleTo6Pt[-idx]) - elif n2 > elementsAroundHalfOeso + 1: - # print('beyond 6 pt') + elif n2 > elementsAroundHalfEso + 1: # Beyond 6 pt junction # LC - d2CurvatureAround.append(curvatureAlongLC[n2 - (elementsAroundHalfOeso + 1) - 1]) + d2CurvatureAround.append(curvatureAlongLC[n2 - (elementsAroundHalfEso + 1) - 1]) # Regular down left for n1 in range(nextIdx + 1): d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) # Row 2 left d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - d1Curvature.append(d1CurvatureAround) d2Curvature.append(d2CurvatureAround) @@ -2257,8 +1706,7 @@ def generateBaseMesh(cls, region, options): d1List = [] d2List = [] d3List = [] - nodeIdx = bodyStartNode - + nodeIdx = stomachStartNode idxMat = [] for n2 in range(elementsCountAlong + 1): @@ -2291,368 +1739,254 @@ def generateBaseMesh(cls, region, options): idxAround.append(nodeIdx) nodeIdx += 1 - idxThroughWall.append(idxAround) idxMat.append(idxThroughWall) - if makeStomach: - 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 - - # Create element - mesh = fm.findMeshByDimension(3) - - 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) - result = elementtemplateStandard.defineField(coordinates, -1, eftStandard) - - elementtemplateX = mesh.createElementtemplate() - elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) - - elementIdentifier = nextElementIdentifier - - for e2 in range(elementsAroundQuarterOeso + 2): - # Row 1 - if e2 == 0: - startNode = bodyStartNode - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(int(elementsCountAround1) * 2 + 1): - if e1 != elementsCountAround1: - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - if e1 < elementsCountAround1: - # scaleFactors = [-1.0] - if e1 == 0: - bni11 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + e1 - bni12 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - 1 - else: - bni11 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - bni12 = bni11 - 1 - bni21 = startNode + elementsAroundThroughWall + 1 + e1 + e3 * elementsCountAround2 - bni22 = bni21 + 1 + 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 + + # Create element + 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) + result = elementtemplateStandard.defineField(coordinates, -1, eftStandard) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + for e2 in range(elementsCountAlong): + startNode = stomachStartNode + for e in range(e2): + startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) + elementsCountAround1 = len(xOuter[e2]) + elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) + elementsCountAround2 = len(xOuter[e2 + 1]) + + # Row 1 + if e2 == 0: + for e3 in range(elementsCountThroughWall): + for e1 in range(int(elementsCountAround1) * 2 + 1): + if e1 != elementsCountAround1: + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < elementsCountAround1: + if e1 == 0: + bni11 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + e1 + bni12 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - 1 + else: + bni11 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 + bni12 = bni11 - 1 + bni21 = startNode + elementsAroundThroughWall + 1 + e1 + e3 * elementsCountAround2 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + (elementsCountAround2 if e1 == 0 else elementsCountAround1), + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + scaleFactors = [-1.0] + setEftScaleFactorIds(eft1, [1], []) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], + [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS1DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], + [Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D2_DS2DS3, + Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > elementsCountAround1: + if e1 < elementsCountAround1 * 2: + bni11 = startNode + e1 - elementsCountAround1 - 1 + elementsCountAround1 * e3 + bni12 = bni11 + 1 + else: + bni11 = startNode + elementsCountAround1 + e3 * elementsCountAround1 - 1 + bni12 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = bni21 + 1 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, + bni12 + (elementsCountAround1 if e1 < elementsCountAround1 * 2 else elementsCountAround2), + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + # Row 2 + elif e2 == 1: + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 2): + if e1 != int(elementsCountAround1 * 0.5 + 1): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < 2: + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) + bni21 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + e1 + bni22 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + (e1 + 1) + if e1 == 0: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + ( - elementsCountAround2 if e1 == 0 else elementsCountAround1), + bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] eft1 = eftfactory.createEftNoCrossDerivatives() - scaleFactors = [-1.0] setEftScaleFactorIds(eft1, [1], []) - scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], - [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS1DS3, - Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) - scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], - [Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS2DS3, - Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > elementsCountAround1: - if e1 < elementsCountAround1 * 2: - bni11 = startNode + e1 - elementsCountAround1 - 1 + elementsCountAround1 * e3 - bni12 = bni11 + 1 - else: - bni11 = startNode + elementsCountAround1 + e3 * elementsCountAround1 - 1 - bni12 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 - bni22 = bni21 + 1 - nodeIdentifiers = [bni11, bni12, bni21, bni22, + remapEftNodeValueLabel(eft1, [1, 5], 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, [])]) + 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_DS2, [])]) + elif e1 == 1: # Bottom right wedge + nodeIdentifiers = [bni11, bni21, bni22, bni11 + elementsCountAround1, - bni12 + ( - elementsCountAround1 if e1 < elementsCountAround1 * 2 else elementsCountAround2), - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - # Row 2 - elif e2 == 1: - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 + 2): - if e1 != int(elementsCountAround1 * 0.5 + 1): - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - - if e1 < 2: - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + ( - e1 + 1) # % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + e1 - bni22 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + ( - e1 + 1) # % elementsCountAround2 - if e1 == 0: # Remap derivatives of element adjacent to GC - scaleFactors = [-1.0] - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 5], 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, [])]) - 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_DS2, [])]) - elif e1 == 1: # Bottom right wedge - nodeIdentifiers = [bni11, bni21, bni22, - bni11 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > 1 and e1 < elementsCountAround1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 - bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - elif e1 >= elementsCountAround1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 2 - bni12 = startNode + e3 * elementsCountAround1 + (e1 - 1) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - if e1 == elementsCountAround1: # Bottom left wedge - nodeIdentifiers = [bni12, bni21, bni22, - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([2, 6]) - elif e1 == elementsCountAround1 + 1: # Remap derivatives of element adjacent to GC - scaleFactors = [-1.0] - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - - # Additional elements between second and upstream bifurcation ring - elif e2 > 1 and e2 < elementsAroundQuarterOeso: - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1): - if e1 != int(elementsCountAround1 * 0.5): - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 > 1 and e1 < elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 nodeIdentifiers = [bni11, bni12, bni21, bni22, bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2, bni22 + elementsCountAround2] - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - - # Upstream bifurcation - elif e2 == elementsAroundQuarterOeso: - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1): - if e1 != int(elementsCountAround1 * 0.5): - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + elif e1 >= elementsCountAround1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 2 + bni12 = startNode + e3 * elementsCountAround1 + (e1 - 1) % elementsCountAround1 bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - - if e1 < int(elementsCountAround1 * 0.5) - 1: - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - elif e1 == int(elementsCountAround1 * 0.5) - 1: # right wedge - nodeIdentifiers = [bni11, bni12, bni21, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(elementsCountAround1 * 0.5) + 1: # left wedge - bni21 = bni21 - 1 - nodeIdentifiers = [bni11, bni12, bni21, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > int(elementsCountAround1 * 0.5) + 1: - bni21 = bni21 - 2 - bni22 = startNode + elementsAroundThroughWall + ( - e1 - 1) % elementsCountAround2 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + if e1 == elementsCountAround1: # Bottom left wedge + nodeIdentifiers = [bni12, bni21, bni22, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([2, 6]) + elif e1 == elementsCountAround1 + 1: # Remap derivatives of element adjacent to GC + scaleFactors = [-1.0] nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - - # Downstream bifurcation - elif e2 == elementsAroundQuarterOeso + 1: - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 + 1): - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - if e1 < int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - elif e1 == int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( - xOuter[e2 - 1]) + e1 + 1 - elif e1 > int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 - - if e1 < int(elementsCountAround1 * 0.5): - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - elif e1 == int(elementsCountAround1 * 0.5): - bni12 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( - xOuter[e2 - 1]) + e1 + 1 - elif e1 > int(elementsCountAround1 * 0.5): - bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + bni11 + elementsCountAround1, + bni12 + elementsCountAround1, + bni21 + elementsCountAround2, + bni22 + elementsCountAround2] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX - if e1 > int(elementsCountAround1 * 0.5): - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 2) % elementsCountAround2 + elementsCountAround2 * e3 - else: - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + # Additional elements between second and upstream bifurcation ring + elif e2 > 1 and e2 < elementsAroundQuarterEso: + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1): + if e1 != int(elementsCountAround1 * 0.5): + scaleFactors = [] + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + (len(xOuter[e2 - 1]) if e1 == int( - elementsCountAround1 * 0.5) + 1 else elementsCountAround1), - bni12 + (len(xOuter[e2 - 1]) if e1 == int( - elementsCountAround1 * 0.5) else elementsCountAround1), + bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2, bni22 + elementsCountAround2] - if e1 == int(elementsCountAround1 * 0.5): - 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, [])]) + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + + # Upstream bifurcation + elif e2 == elementsAroundQuarterEso: + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1): + if e1 != int(elementsCountAround1 * 0.5): + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + bni11 = startNode + e3 * elementsCountAround1 + e1 + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + + if e1 < int(elementsCountAround1 * 0.5) - 1: + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + elif e1 == int(elementsCountAround1 * 0.5) - 1: # right wedge + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX - elif e1 == int(elementsCountAround1 * 0.5) + 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, [ ])]) + elif e1 == int(elementsCountAround1 * 0.5) + 1: # left wedge + bni21 = bni21 - 1 + nodeIdentifiers = [bni11, bni12, bni21, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2] + eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni21 = bni21 - 2 + bni22 = startNode + elementsAroundThroughWall + (e1 - 1) % elementsCountAround2 + elementsCountAround2 * e3 + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + elementsCountAround1, bni12 + elementsCountAround1, + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + element = mesh.createElement(elementIdentifier, elementtemplate1) result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) if scaleFactors: @@ -2665,25 +1999,76 @@ def generateBaseMesh(cls, region, options): meshGroup = annotationGroup.getMeshGroup(mesh) meshGroup.addElement(element) - # Rows between downstream and penultimate ring - for e2 in range(elementsAroundQuarterOeso + 2, elementsAroundHalfOeso): - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) + # Downstream bifurcation + elif e2 == elementsAroundQuarterEso + 1: + for e3 in range(elementsCountThroughWall): + for e1 in range(elementsCountAround1 + 1): + eft1 = eftStandard + elementtemplate1 = elementtemplateStandard + if e1 < int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 + elif e1 == int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len(xOuter[e2 - 1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5) + 1: + bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 + + if e1 < int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 + elif e1 == int(elementsCountAround1 * 0.5): + bni12 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len(xOuter[e2 - 1]) + e1 + 1 + elif e1 > int(elementsCountAround1 * 0.5): + bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 + + if e1 > int(elementsCountAround1 * 0.5): + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 + bni22 = startNode + elementsAroundThroughWall + (e1 + 2) % elementsCountAround2 + elementsCountAround2 * e3 + else: + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 + + nodeIdentifiers = [bni11, bni12, bni21, bni22, + bni11 + (len(xOuter[e2 - 1]) if e1 == int(elementsCountAround1 * 0.5) + 1 else elementsCountAround1), + bni12 + (len(xOuter[e2 - 1]) if e1 == int(elementsCountAround1 * 0.5) else elementsCountAround1), + bni21 + elementsCountAround2, bni22 + elementsCountAround2] + if e1 == int(elementsCountAround1 * 0.5): + 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, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == int(elementsCountAround1 * 0.5) + 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, [ ])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + result3 = element.setScaleFactors(eft1, scaleFactors) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + + # Rows between downstream and penultimate ring + elif elementsAroundQuarterEso + 2 <= e2 < elementsAroundHalfEso: for e3 in range(elementsCountThroughWall): for e1 in range(elementsCountAround1 - 1): - bni11 = startNode + e3 * elementsCountAround1 + e1 + ( - 0 if e1 < int(elementsCountAround1 * 0.5) else 1) - bni12 = startNode + e3 * elementsCountAround1 + ( - e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + ( - 0 if e1 < int(elementsCountAround1 * 0.5) else 1) - bni22 = startNode + elementsAroundThroughWall + (e1 + (1 if e1 < int( - elementsCountAround1 * 0.5) else 2)) % elementsCountAround2 + elementsCountAround2 * e3 + bni11 = startNode + e3 * elementsCountAround1 + e1 + (0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni12 = startNode + e3 * elementsCountAround1 + (e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 + bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + (0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni22 = startNode + elementsAroundThroughWall + (e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround2 + elementsCountAround2 * e3 nodeIdentifiers = [bni11, bni12, bni21, bni22, bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2, bni22 + elementsCountAround2] @@ -2698,26 +2083,15 @@ def generateBaseMesh(cls, region, options): meshGroup.addElement(element) # Penultimate row connecting to annulus and beyond - for e2 in range(elementsAroundHalfOeso, elementsCountAlong): - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - + elif elementsAroundHalfEso <= e2: for e3 in range(elementsCountThroughWall): - for e1 in range( - elementsCountAround1 - (1 if e2 == elementsAroundHalfOeso else 0)): + for e1 in range(elementsCountAround1 - (1 if e2 == elementsAroundHalfEso else 0)): scaleFactors = [] eft1 = eftStandard elementtemplate1 = elementtemplateStandard - if e2 == elementsAroundHalfOeso: - bni11 = startNode + e3 * elementsCountAround1 + e1 + ( - 0 if e1 < int(elementsCountAround1 * 0.5) else 1) - bni12 = startNode + e3 * elementsCountAround1 + (e1 + ( - 1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 + if e2 == elementsAroundHalfEso: + bni11 = startNode + e3 * elementsCountAround1 + e1 + (0 if e1 < int(elementsCountAround1 * 0.5) else 1) + bni12 = startNode + e3 * elementsCountAround1 + (e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 # Remap elements next to annulus if e1 == int(elementsCountAround1 * 0.5) - 1: scaleFactors = [-1.0] @@ -2737,7 +2111,7 @@ def generateBaseMesh(cls, region, options): bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2, bni22 + elementsCountAround2] - if e2 == elementsAroundHalfOeso + 1: + if e2 == elementsAroundHalfEso + 1: if e1 == int(elementsCountAround1 * 0.5) - 1: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() @@ -2765,110 +2139,68 @@ def generateBaseMesh(cls, region, options): meshGroup = annotationGroup.getMeshGroup(mesh) meshGroup.addElement(element) - # Annulus - # Assemble endPoints for annulus - endPoints_x = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] - endPoints_d1 = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] - endPoints_d2 = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] - endNode_Id = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] - endDerivativesMap = [[None] * elementsCountAroundOeso, [None] * elementsCountAroundOeso] - endProportions = [] - - thicknessIdx = [0, -1] - for nAround in range(elementsCountAroundOeso): - for n3 in range(len(thicknessIdx)): - if nAround == 0: - idx = idxMat[nAround][thicknessIdx[n3]][0] - elif nAround <= elementsAroundQuarterOeso: - idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] - elif elementsAroundQuarterOeso < nAround < elementsAroundHalfOeso: - idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] - elif nAround == elementsAroundHalfOeso: - idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] - elif nAround > elementsAroundHalfOeso: - idx = endNode_Id[n3][elementsAroundHalfOeso - (nAround - elementsAroundHalfOeso)] + 1 - - endPoints_x[n3][nAround] = xList[idx - bodyStartNode] - endPoints_d1[n3][nAround] = d1List[idx - bodyStartNode] - endPoints_d2[n3][nAround] = d2List[idx - bodyStartNode] - endNode_Id[n3][nAround] = idx - - if n3 == len(thicknessIdx) - 1: # outer layer - endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) - # xCheck = trackSurfaceStomach.evaluateCoordinates(endPosition) # KM - # print(xCheck, endPoints_x[n3][nAround]) # KM - endProportions.append(trackSurfaceStomach.getProportion(endPosition)) - - for nAround in range(elementsCountAroundOeso): + # Annulus + # Assemble endPoints for annulus + endPoints_x = [[None] * elementsCountAroundEso, [None] * elementsCountAroundEso] + endPoints_d1 = [[None] * elementsCountAroundEso, [None] * elementsCountAroundEso] + endPoints_d2 = [[None] * elementsCountAroundEso, [None] * elementsCountAroundEso] + endNode_Id = [[None] * elementsCountAroundEso, [None] * elementsCountAroundEso] + endDerivativesMap = [[None] * elementsCountAroundEso, [None] * elementsCountAroundEso] + endProportions = [] + + thicknessIdx = [0, -1] + for nAround in range(elementsCountAroundEso): + for n3 in range(len(thicknessIdx)): if nAround == 0: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) - elif nAround == elementsAroundQuarterOeso: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) - elif 0 < nAround < elementsAroundHalfOeso: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == elementsAroundHalfOeso: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - elif nAround == int(elementsCountAroundOeso * 0.75): - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - elif elementsAroundHalfOeso < nAround < elementsCountAroundOeso: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) - - startProportions = [] - for n in range(elementsCountAroundOeso): - startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) - - cardiaGroup = AnnotationGroup(region, get_stomach_term("cardia of stomach")) - cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) - stomachMeshGroup = stomachGroup.getMeshGroup(mesh) - allAnnotationGroups.append(cardiaGroup) - - 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 = elementsCountAnnulus, meshGroups= [stomachMeshGroup, cardiaMeshGroup], - tracksurface=trackSurfaceStomach, startProportions = startProportions, endProportions = endProportions, - rescaleStartDerivatives = True, rescaleEndDerivatives = True) - - if showTrackSurface: - for n2 in range(len(xTrackSurface)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - nodeIdentifier += 1 - - if showCentralPath: - for n2 in range(len(sx)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd2[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, sd3[n2]) - nodeIdentifier += 1 - - # nodeIdentifier = 10000 - # for n1 in range(len(xStarts)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xStarts[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Starts[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # for n1 in range(len(xEnds)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xEnds[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2Ends[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - + idx = idxMat[nAround][thicknessIdx[n3]][0] + elif nAround <= elementsAroundQuarterEso: + idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] + elif elementsAroundQuarterEso < nAround < elementsAroundHalfEso: + idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] + elif nAround == elementsAroundHalfEso: + idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] + elif nAround > elementsAroundHalfEso: + idx = endNode_Id[n3][elementsAroundHalfEso - (nAround - elementsAroundHalfEso)] + 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 == len(thicknessIdx) - 1: # outer layer + endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) + endProportions.append(trackSurfaceStomach.getProportion(endPosition)) + + for nAround in range(elementsCountAroundEso): + if nAround == 0: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + elif nAround == elementsAroundQuarterEso: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) + elif 0 < nAround < elementsAroundHalfEso: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) + elif nAround == elementsAroundHalfEso: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) + elif nAround == int(elementsCountAroundEso * 0.75): + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) + elif elementsAroundHalfEso < nAround < elementsCountAroundEso: + endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) + + startProportions = [] + for n in range(elementsCountAroundEso): + startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) + + cardiaGroup = AnnotationGroup(region, get_stomach_term("cardia of stomach")) + cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) + stomachMeshGroup = stomachGroup.getMeshGroup(mesh) + allAnnotationGroups.append(cardiaGroup) + + 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 = elementsCountAnnulus, meshGroups= [stomachMeshGroup, cardiaMeshGroup], + tracksurface=trackSurfaceStomach, startProportions = startProportions, endProportions = endProportions, + rescaleStartDerivatives = True, rescaleEndDerivatives = True) fm.endChange() @@ -2894,7 +2226,6 @@ def findClosestPositionAndDerivativeOnTrackSurface(x, nx, trackSurface, nxPropor Find the closest position and derivative around the tracksurface of a point sitting near the fundus of stomach. Use a startPosition to improve the search for nearest position on the track surface as the fundus has a curved and complex track surface. - :param x: coordinates of point of interest :param nx: coordinates of points along curve where point of interest lies. :param trackSurface: track surface where point sits @@ -2911,9 +2242,9 @@ def findClosestPositionAndDerivativeOnTrackSurface(x, nx, trackSurface, nxPropor def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, startProportion2, endProportion1, endProportion2, elementsOut, startDerivative = None, endDerivative = None, - startDerivativeMagnitude = None, endDerivativeMagnitude = None, curveMode = 1): + startDerivativeMagnitude = None, endDerivativeMagnitude = None, + curveMode = 1): """ - EDIT Create smoothly spaced out hermite curve points between two points a and b on the surface, each defined by their proportions over the surface in directions 1 and 2. :param trackSurface: track surface @@ -2922,9 +2253,9 @@ def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, start :param elementsOut: number of elements out :param startDerivative, endDerivative: optional derivative vectors in 3-D world coordinates to match at the start and end of the curves. If omitted, fits in with other derivative or is - in a straight line from a to b. + in a straight line from a to b :param derivativeMagnitudeStart, derivativeMagnitudeEnd: optional magnitude of derivatives to match at the start and - end of the curves. + end of the curves :return: coordinates and derivative of sampled points """ @@ -2932,18 +2263,57 @@ def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, start trackSurface.createHermiteCurvePoints(startProportion1, startProportion2, endProportion1, endProportion2, elementsOut, startDerivative, endDerivative, curveMode) - xSampled, dSampled = trackSurface.resampleHermiteCurvePointsSmooth(mx, md2, md1, md3, mProportions, startDerivativeMagnitude, endDerivativeMagnitude)[0:2] return xSampled, dSampled -def findDerivativeBetweenPoints(v1, v2): +def smoothD1Around(xAround, d1Around): + """ + Rearrange points around so that 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 derivative smoothing. + Smoothed derivatives are 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. + :return: smoothed derivatives 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)] + d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, + fixEndDerivative=True) + # Rearrange to correct order + d1Around = d1LoopSmooth[int(len(xAround) * 0.5) : ] + d1LoopSmooth[: int(len(xAround) * 0.5) : ] + + return d1Around + +def findD1CurvatureAround(xAround, d1Around, normsAround): + """ + Rearrange points around so that 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. + Curvatures are 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):] - :param v1: - :param v2: - :return: + 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) @@ -2953,11 +2323,11 @@ def findDerivativeBetweenPoints(v1, v2): def findCurvatureAroundLoop(nx, nd, radialVectors): """ - - :param nx: - :param nd: - :param radialVectors: - :return: + Calculate curvature for points lying along a loop. + :param nx: points on loop + :param nd: derivative of points on loop + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on loop """ curvature = [] for n in range(len(nx)): @@ -2971,11 +2341,11 @@ def findCurvatureAroundLoop(nx, nd, radialVectors): def findCurvatureAlongLine(nx, nd, radialVectors): """ - - :param nx: - :param nd: - :param radialVectors: - :return: + Calculate curvature for points lying along a line. + :param nx: points on line + :param nd: derivative of points on line + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on line """ curvature = [] for n in range(len(nx)): @@ -2989,4 +2359,3 @@ def findCurvatureAlongLine(nx, nd, radialVectors): interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) return curvature - From 849119e8863e0f1b7eb37ee5afd62fa876665ca8 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 16 Apr 2021 13:18:51 +1200 Subject: [PATCH 09/38] Allow for linear through wall --- .../utils/eftfactory_bicubichermitelinear.py | 92 +++++++++++++++++++ .../utils/eftfactory_tricubichermite.py | 1 - 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py index ed7c5146..9b9f3cb7 100644 --- a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py +++ b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py @@ -249,6 +249,70 @@ def createEftWedgeXi1Zero(self): assert eft.validate(), 'eftfactory_tricubichermite.createEftWedgeXi1Zero: Failed to validate eft' return eft + def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): + ''' + Create a bicubic hermite linear element field for a wedge element, where xi1 collapsed on xi3 = 0 or xi3 = 1. + :return: Element field template + ''' + eft = self.createEftBasic() + setEftScaleFactorIds(eft, [1], []) + + valid = True + if collapseNodes in [[1, 3], [2, 4]]: + nodes = [1, 2, 3, 4] + if collapseNodes == [1, 3]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + elif collapseNodes == [2, 4]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + else: + valid = False + ln_map = [1, 1, 2, 2, 3, 4, 5, 6] + elif collapseNodes in [[5, 7], [6, 8]]: + nodes = [5, 6, 7, 8] + if collapseNodes == [5, 7]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + elif collapseNodes == [6, 8]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + else: + valid = False + ln_map = [1, 2, 3, 4, 5, 5, 6, 6] + elif collapseNodes in [[1, 5], [2, 6]]: + nodes = [1, 2, 5, 6] + # remap parameters on xi2 = 0 before collapsing nodes + if collapseNodes == [1, 5]: + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + elif collapseNodes == [2, 6]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + else: + valid = False + ln_map = [1, 1, 2, 3, 4, 4, 5, 6] + elif collapseNodes in [[3, 7], [4, 8]]: + nodes = [3, 4, 7, 8] + # remap parameters on xi2 = 1 before collapsing nodes + if collapseNodes == [3, 7]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elif collapseNodes == [4, 8]: + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) + else: + valid = False + ln_map = [1, 2, 3, 3, 4, 5, 6, 6] + else: + valid = False + + if not valid: + assert False, "createEftWedgeCollapseXi1Quadrant. Not implemented for collapse nodes " + str(collapseNodes) + + # zero cross derivative parameters + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) + + remapEftLocalNodes(eft, 6, ln_map) + assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftWedgeCollapseXi1Quadrant: Failed to validate eft' + return eft + def createEftWedgeXi1ZeroOpenTube(self): ''' Create a basic bicubic hermite linear element template for elements @@ -431,3 +495,31 @@ def createEftPyramidBottomSimple(self, nodeScaleFactorOffset0, nodeScaleFactorOf assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftPyramidBottomSimple: Failed to validate eft' return eft + + def createEftWedgeCollapseXi2(self, collapseNodes): + ''' + Create a bicubic hermite linear element field for a wedge element, where xi2 collapsed on xi1 = 1. + :return: Element field template + ''' + eft = self.createEftBasic() + + if collapseNodes in [[4, 8]]: + setEftScaleFactorIds(eft, [1], []) + nodes = [2, 4, 6, 8] + remapEftNodeValueLabel(eft, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + ln_map = [1, 2, 3, 2, 4, 5, 6, 5] + + elif collapseNodes in [[3, 7]]: + nodes = [1, 3, 5, 7] + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + remapEftNodeValueLabel(eft, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + ln_map = [1, 2, 1, 3, 4, 5, 4, 6] + + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) + + remapEftLocalNodes(eft, 6, ln_map) + assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftWedgeCollapseXi2: Failed to validate eft' + + return eft + \ No newline at end of file diff --git a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py index 0d9e1c37..38bc122d 100644 --- a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py +++ b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py @@ -1660,7 +1660,6 @@ def replaceTwoElementWithInlet6(self, origElement1, origElement2, startElementId def createEftWedgeCollapseXi2(self, collapseNodes): ''' - EDIT Create a tricubic hermite element field for a wedge element, where xi2 collapsed on xi1 = 1. :return: Element field template ''' From 84b7e7f5b937da581b9b9216cd346f4348f274ff Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 16 Apr 2021 15:23:38 +1200 Subject: [PATCH 10/38] Add unit test for stomach and update tests for colon and small intestine --- .../meshtypes/meshtype_3d_stomach2.py | 2563 ----------------- src/scaffoldmaker/scaffolds.py | 2 - .../utils/eftfactory_bicubichermitelinear.py | 1 - tests/test_colon.py | 10 +- tests/test_smallintestine.py | 2 +- tests/test_stomach.py | 84 + 6 files changed, 90 insertions(+), 2572 deletions(-) delete mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py create mode 100644 tests/test_stomach.py diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py deleted file mode 100644 index 13a15908..00000000 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach2.py +++ /dev/null @@ -1,2563 +0,0 @@ -""" -Generates a 3-D stomach mesh along the central line, with variable -numbers of elements around oesophagus and duodenum, along and through -wall, with variable radius and thickness along. -""" - -from __future__ import division -import math -import copy -from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates -from opencmiss.zinc.element import Element -from opencmiss.zinc.field import Field -from opencmiss.zinc.node import Node -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1, extractPathParametersFromRegion -from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1, generateOstiumMesh -from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base -from scaffoldmaker.scaffoldpackage import ScaffoldPackage -from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d -from scaffoldmaker.utils.bifurcation import get_bifurcation_triple_point -from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear -from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite -from scaffoldmaker.utils.eft_utils import scaleEftNodeValueLabels, setEftScaleFactorIds, remapEftNodeValueLabel -from scaffoldmaker.utils.geometry import createEllipsePoints -from scaffoldmaker.utils.tracksurface import TrackSurface -from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues -from scaffoldmaker.utils import interpolation as interp -from scaffoldmaker.utils import matrix -from scaffoldmaker.utils import vector - - -class MeshType_3d_stomach2(Scaffold_base): - """ - Generates a 3-D stomach mesh with variable numbers of elements around the oesophagus and duodenum, - along the central line, and through wall. The stomach is created by a function that generates a bean - volume defined by a central path as its longitudinal axis. D2 of the central path points to the greater - curvature of the stomach and magnitude of D2 and D3 are the radii of the stomach in the respective - direction. - """ - centralPathDefaultScaffoldPackages = { - 'Generic 1': ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 4 - }, - 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[17.0, 14.0, 0.0], [-17.9, -22.1, 0.0], [7.0, -5.7, 0.0], [-3.3, -6.2, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, 1.4]], - [[0.0, 0.0, 0.0], [-15.4, -5.0, 0.0], [2.8, -8.5, 0.0], [-5.2, 0.6, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, -1.4]], - [[-9.7, 0.7, 0.0], [-8.6, 3.8, 0.0], [-2.8, -6.4, 0.0], [-2.1, 3.7, 0.0], [0.0, 0.0, 7.0], - [0.0, 0.0, -3.3]], - [[-15.9, 6.6, 0.0], [-4.8, 6.8, 0.0], [-2.0, -1.4, 0.0], [-0.3, 2.7, 0.0], [0.0, 0.0, 2.5], - [0.0, 0.0, -1.6]], - [[-19.2, 13.9, 0.0], [-1.7, 7.6, 0.0], [-3.4, -0.8, 0.0], [-2.5, -1.4, 0.0], [0.0, 0.0, 3.5], - [0.0, 0.0, 3.6]]]) - }), - 'Human 1': ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 7 - }, - 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[54.2, 76.2, 0.0], [9.4, -43.5, 0.0], [29.0, 0.8, 0.0], [15.9, -22.3, 0.0], [0.0, 0.0, 40.7], - [0.0, 0.0, 1.4]], - [[51.1, 30.7, 0.0], [-18.5, -35.9, 0.0], [33.9, -17.5, 0.0], [-6.1, -14.3, 0.0], [0.0, 0.0, 41.4], - [0.0, 0.0, 0.0]], - [[27.8, 2.7, 0.0], [-27.7, -18.4, 0.0], [19.0, -28.6, 0.0], [-16.3, -6.6, 0.0], [0.0, 0.0, 40.9], - [0.0, 0.0, -5.0]], - [[-0.3, -5.8, 0.0], [-29.4, -1.4, 0.0], [1.5, -31.5, 0.0], [-13.5, 4.5, 0.0], [0.0, 0.0, 32.3], - [0.0, 0.0, -9.4]], - [[-26.5, -2.9, 0.0], [-22.4, 9.4, 0.0], [-8.5, -20.3, 0.0], [-8.1, 10.9, 0.0], [0.0, 0.0, 22.1], - [0.0, 0.0, -6.8]], - [[-40.6, 7.4, 0.0], [-9.9, 11.2, 0.0], [-15.3, -9.6, 0.0], [-0.1, 8.5, 0.0], [0.0, 0.0, 17.6], - [0.0, 0.0, -5.9]], - [[-48.1, 21.0, 0.0], [-5.7, 14.7, 0.0], [-9.4, -3.0, 0.2], [2.3, 3.1, 0.0], [0.0, 0.0, 10.5], - [0.0, 0.0, -3.1]], - [[-52.9, 38.6, 0.0], [-5.0, 19.8, 0.0], [-11.3, -4.0, 0.0], [-6.1, -5.1, 0.0], [0.0, 0.0, 12.0], - [0.0, 0.0, 6.1]]]) - - }), - 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 6 - }, - 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[10.7, 13.3, 0.0], [3.3, -16.0, 0.0], [8.7, -1.4, 0.0], [0.5, -3.7, 0.0], [0.0, 0.0, 7.4], - [0.0, 0.0, 1.6]], - [[9.5, -0.2, 0.0], [-6.0, -9.6, 0.0], [6.6, -5.1, 0.0], [-3.9, -4.3, 0.0], [0.0, 0.0, 8.5], - [0.0, 0.0, 0.7]], - [[2.3, -5.2, 0.0], [-9.3, -2.2, 0.0], [2.1, -9.1, -0.0], [-6.4, -1.6, 0.0], [0.0, 0.0, 9.0], - [0.0, 0.0, -0.1]], - [[-7.8, -3.9, 0.0], [-7.5, 4.2, 0.0], [-6.0, -8.0, 0.0], [-3.4, 3.4, 0.0], [0.0, 0.0, 8.1], - [0.0, 0.0, -1.5]], - [[-11.7, 1.7, 0.0], [-1.7, 7.2, 0.0], [-6.4, -3.5, 0.0], [1.4, 4.0, 0.0], [0.0, 0.0, 6.2], - [0.0, 0.0, -2.8]], - [[-10.7, 9.4, 0.0], [0.1, 6.6, 0.0], [-2.9, 0.0, 0.0], [1.1, 1.3, 0.0], [0.0, 0.0, 2.4], - [0.0, 0.0, -1.0]], - [[-11.3, 14.8, 0.0], [-1.2, 4.1, 0.0], [-3.5, -0.3, 0.0], [-2.3, -1.9, 0.0], [0.0, 0.0, 3.4], - [0.0, 0.0, 3.0]]]) - }), - 'Stomach coordinates': ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 4 - }, - 'meshEdits': exnodeStringFromNodeValues( - [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], [ - [[17.9, 0.0, 0.0], [-21.6, 0.0, 0.0], [0.0, -9.0, -0.7], [0.0, -1.0, 1.2], [0.0, -0.7, 9.0], - [0.0, 1.2, 1.2]], - [[0.0, 0.0, 0.0], [-14.2, 0.0, 0.0], [0.0, -8.9, -0.1], [0.0, 1.2, 0.0], [0.0, -0.1, 9.0], - [0.0, 0.0, -1.3]], - [[-10.5, 0.0, 0.0], [-9.2, 0.0, 0.0], [0.0, -7.0, -0.4], [0.0, 3.4, 0.0], [0.0, -0.4, 7.0], - [0.0, 0.0, -3.4]], - [[-18.4, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -2.4, -0.1], [0.0, 1.7, 0.2], [0.0, -0.1, 2.5], - [0.0, 0.2, -1.7]], - [[-26.2, 0.0, 0.0], [-7.8, 0.0, 0.0], [0.0, -3.6, 0.1], [0.0, -4.1, 0.2], [0.0, 0.1, 3.5], - [0.0, 0.2, 3.7]]]) - }), - } - - ostiumDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_3d_ostium1, { - 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, - 'Number of elements around ostium': 8, - 'Number of elements along': 2, - 'Number of elements through wall': 1, # not implemented for > 1 - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium diameter': 25.0, - 'Ostium length': 10.0, - 'Ostium wall thickness': 5.0, - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, - 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 5.0, - 'Vessel wall thickness': 5.0, - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Rat 1': ScaffoldPackage(MeshType_3d_ostium1, { - 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, - 'Number of elements around ostium': 8, - 'Number of elements along': 2, - 'Number of elements through wall': 1, # not implemented for > 1 - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium diameter': 5.0, - 'Ostium length': 5.0, - 'Ostium wall thickness': 0.5, - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, - 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 1.25, - 'Vessel wall thickness': 0.5, - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - } - - @staticmethod - def getName(): - return '3D Stomach 2' - - @staticmethod - def getParameterSetNames(): - return [ - 'Default', - 'Generic 1', - 'Human 1', - 'Rat 1', - 'Stomach coordinates',] - - @classmethod - def getDefaultOptions(cls, parameterSetName='Default'): - if 'Rat 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] - elif 'Generic 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Generic 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] - elif 'Stomach coordinates' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Stomach coordinates'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] - else: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - - options = { - 'Central path': copy.deepcopy(centralPathOption), - 'Number of elements around oesophagus': 8, - 'Number of elements around duodenum': 12, - 'Number of elements along': 8, - 'Number of elements through wall': 1, - 'Wall thickness': 5.0, - 'Gastro-oesophagal junction': copy.deepcopy(ostiumOption), - 'Gastro-oesophagal junction position along factor': 0.25, - 'Annulus derivative factor': 1.0, - 'Number of radial elements in annulus': 1, # KM - 'Show track surface': False, # KM - 'Make stomach': True, # KM - 'Show central path': False, # KM - 'Use cross derivatives': False, - 'Use linear through wall' : False, # need to deal with wedge not available in bicubichermite - 'Refine': False, - 'Refine number of elements around': 1, - 'Refine number of elements along': 1, - 'Refine number of elements through wall': 1 - } - if ('Generic 1' or 'Rat 1' or 'Stomach coordinates') in parameterSetName: - options['Wall thickness'] = 0.5 - options['Gastro-oesophagal junction position along factor'] = 0.55 - - cls.updateSubScaffoldOptions(options) - return options - - @staticmethod - def getOrderedOptionNames(): - return [ - 'Central path', - 'Number of elements around oesophagus', - 'Number of elements around duodenum', - 'Number of elements along', - 'Number of elements through wall', - 'Wall thickness', - 'Gastro-oesophagal junction', - 'Gastro-oesophagal junction position along factor', - 'Annulus derivative factor', - 'Number of radial elements in annulus', - 'Show track surface', - 'Make stomach', - 'Show central path', - 'Use cross derivatives', - 'Use linear through wall', - 'Refine', - 'Refine number of elements around', - 'Refine number of elements along', - 'Refine number of elements through wall'] - - @classmethod - def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': - return [MeshType_1d_path1] - if optionName == 'Gastro-oesophagal junction': - return [MeshType_3d_ostium1] - return [] - - @classmethod - def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) - if optionName == 'Gastro-oesophagal junction': - return list(cls.ostiumDefaultScaffoldPackages.keys()) - assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ - cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ - 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() - return scaffoldType.getParameterSetNames() - - @classmethod - def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): - ''' - :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. - :return: ScaffoldPackage. - ''' - if parameterSetName: - assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ - 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ - ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': - if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) - if optionName == 'Gastro-oesophagal junction': - if not parameterSetName: - parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) - assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' - - @classmethod - 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-oesophagal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( - 'Gastro-oesophagal junction'): - options['Gastro-oesophagal junction'] = cls.getOptionScaffoldPackage('Gastro-oesophagal junction', - MeshType_3d_ostium1) - if options['Number of elements around oesophagus'] < 8: - options['Number of elements around oesophagus'] = 8 - if options['Number of elements around oesophagus'] % 4 > 0: - options['Number of elements around oesophagus'] = options['Number of elements around oesophagus'] // 4 * 4 - if options['Number of elements around duodenum'] < 12: - options['Number of elements around duodenum'] = 12 - for key in [ - 'Number of elements around oesophagus', - 'Number of elements around duodenum']: - if options[key] % 2: - options[key] += 1 - if options['Number of elements along'] < 8: - options['Number of elements along'] = 8 - if options['Annulus derivative factor'] < 0: - options['Annulus derivative factor'] = 0.0 - for key in [ - 'Number of elements through wall', - 'Refine number of elements around', - 'Refine number of elements along', - 'Refine number of elements through wall']: - if options[key] < 1: - options[key] = 1 - - cls.updateSubScaffoldOptions(options) - - @classmethod - def updateSubScaffoldOptions(cls, options): - ''' - Update ostium sub-scaffold options which depend on parent options. - ''' - wallThickness = options['Wall thickness'] - ostiumOptions = options['Gastro-oesophagal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - ostiumSettings['Ostium wall thickness'] = wallThickness - - @classmethod - def generateBaseMesh(cls, region, options): - """ - Generate the base tricubic Hermite mesh. See also generateMesh(). - :param region: Zinc region to define model in. Must be empty. - :param options: Dict containing options. See getDefaultOptions(). - :return: None - """ - cls.updateSubScaffoldOptions(options) - centralPath = options['Central path'] - elementsCountAroundOesophagus = options['Number of elements around oesophagus'] - elementsCountAroundDuodenum = options['Number of elements around duodenum'] - elementsCountAlong = options['Number of elements along'] - elementsCountThroughWall = options['Number of elements through wall'] - wallThickness = options['Wall thickness'] - useCrossDerivatives = options['Use cross derivatives'] - useCubicHermiteThroughWall = not (options['Use linear through wall']) - - GOJPositionAlongFactor = options['Gastro-oesophagal junction position along factor'] - GOJOptions = options['Gastro-oesophagal junction'] - GOJSettings = GOJOptions.getScaffoldSettings() - oesophagusDiameter = GOJSettings['Ostium diameter'] - annulusDerivativeFactor = options['Annulus derivative factor'] - elementsCountAnnulus = options['Number of radial elements in annulus'] - - trackSurface = options['Show track surface'] - makeStomach = options['Make stomach'] - showCentralPath = options['Show central path'] - - elementsCountAlongTrackSurface = 20 - - ############################################################################################ - zero = [0.0, 0.0, 0.0] - - fm = region.getFieldmodule() - fm.beginChange() - - coordinates = findOrCreateFieldCoordinates(fm) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - nodetemplate = nodes.createNodetemplate() - nodetemplate.defineField(coordinates) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - if useCrossDerivatives: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) - if useCubicHermiteThroughWall: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) - if useCrossDerivatives: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) - - cache = fm.createFieldcache() - ########################################################################################### - - firstNodeIdentifier = 1 - firstElementIdentifier = 1 - - # Central path - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - cx, cd1, cd2, cd3, cd12, cd13 = extractPathParametersFromRegion(tmpRegion, - [Node.VALUE_LABEL_VALUE, - Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, - Node.VALUE_LABEL_D_DS3, - Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS1DS3]) - del tmpRegion - # for i in range(len(cx)): - # cd3New = vector.setMagnitude(cd3[i], vector.magnitude(cd2[i])) - # print(i, vector.magnitude(cd2[i]), vector.magnitude(cd3[i]), cd3New) - # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') - - sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongTrackSurface) - sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) - sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) - - # Make sampled d2 and d3 normal to central path - # d2Check = [] - # for c in range(len(sx)): - # td2 = vector.vectorRejection(sd2[c], sd1[c]) - # sd2[c] = vector.setMagnitude(td2, vector.magnitude(sd2[c])) - # d2Check.append(matrix.rotateAboutZAxis(sd2[c], math.pi)) - # td3 = vector.vectorRejection(sd3[c], sd1[c]) - # sd3[c] = vector.setMagnitude(td3, vector.magnitude(sd3[c])) - - # Calculate length of central path - stomachCentralPathLength = 0.0 - for e in range(len(sx) - 1): - arcLength = interp.getCubicHermiteArcLength(sx[e], sd1[e], sx[e + 1], sd1[e + 1]) - # print(e+1, arcLength) - stomachCentralPathLength += arcLength - lengthElementAlong = stomachCentralPathLength / elementsCountAlongTrackSurface - - nodeIdentifier = firstNodeIdentifier - elementIdentifier = firstElementIdentifier - - # Fundus diameter - fundusRadius = vector.magnitude(sd2[0]) - elementsAlongFundus = int(fundusRadius / lengthElementAlong) - - d2Apex = [] - d2 = sd2[0] - for n1 in range(elementsCountAroundDuodenum): - rotAngle = n1 * 2.0 * math.pi / elementsCountAroundDuodenum - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) # vector.normalise(sd1[0]) - 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)] - d2Apex.append(d2Rot) - - xEllipses = [] - d1Ellipses = [] - for n in range(elementsAlongFundus + 1, len(sx)): - px, pd1 = createEllipsePoints(sx[n], 2 * math.pi, sd2[n], sd3[n], elementsCountAroundDuodenum, - startRadians=0.0) - xEllipses.append(px) - d1Ellipses.append(pd1) - - # Find d2 - d2Raw = [] - for n1 in range(elementsCountAroundDuodenum): - xAlong = [] - d2Along = [] - for n2 in range(len(xEllipses) - 1): - v1 = xEllipses[n2][n1] - v2 = xEllipses[n2 + 1][n1] - d2 = findDerivativeBetweenPoints(v1, v2) - xAlong.append(v1) - d2Along.append(d2) - xAlong.append(xEllipses[-1][n1]) - d2Along.append(d2) - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) - d2Raw.append(d2Smoothed) - - # Rearrange d2 - d2Ellipses = [] - for n2 in range(len(xEllipses)): - d2Around = [] - for n1 in range(elementsCountAroundDuodenum): - d2 = d2Raw[n1][n2] - d2Around.append(d2) - d2Ellipses.append(d2Around) - - # for n2 in range(len(xEllipses)): - # for n1 in range(elementsCountAroundDuodenum): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xEllipses[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Ellipses[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Ellipses[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # for n1 in range(len(sx)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd1[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd2[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Check[n1]) - # nodeIdentifier += 1 - - # Merge fundus and body - xAll = [[sx[0]] * elementsCountAroundDuodenum] + xEllipses - d2All = [d2Apex] + d2Ellipses - - # for n2 in range(len(xAll)): - # for n1 in range(elementsCountAroundDuodenum): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2All[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Spread out elements - xRaw = [] - d2Raw = [] - for n1 in range(elementsCountAroundDuodenum): - xAlong = [] - d2Along = [] - for n2 in range(len(xAll)): - xAlong.append(xAll[n2][n1]) - d2Along.append(d2All[n2][n1]) - xSampledAlong, d2SampledAlong = interp.sampleCubicHermiteCurves(xAlong, d2Along, - elementsCountAlongTrackSurface, - arcLengthDerivatives=True)[0:2] - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlong, d2SampledAlong) - xRaw.append(xSampledAlong) - d2Raw.append(d2Smoothed) - - # Rearrange x and d2 - xSampledAll = [] - d1SampledAll = [] - d2SampledAll = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - xAround = [] - d1Around = [] - d2Around = [] - for n1 in range(elementsCountAroundDuodenum): - x = xRaw[n1][n2] - d2 = d2Raw[n1][n2] - xAround.append(x) - d2Around.append(d2) - - # Calculate d1 - if n2 > 0: - v1 = xRaw[n1][n2] - v2 = xRaw[n1 + 1 if n1 < elementsCountAroundDuodenum - 2 else 0][n2] - d1 = findDerivativeBetweenPoints(v1, v2) - d1Around.append(d1) - else: - d1Around.append(d2Raw[int(elementsCountAroundDuodenum * 0.75)][0]) - - if n2 > 0: - d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - else: - d1Smoothed = d1Around - - xSampledAll.append(xAround) - d1SampledAll.append(d1Smoothed) - d2SampledAll.append(d2Around) - - # for n2 in range(elementsCountAlongTrackSurface + 1): - # for n1 in range(elementsCountAroundDuodenum): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Create tracksurface - xTrackSurface = [] - d1TrackSurface = [] - d2TrackSurface = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - for n1 in range(elementsCountAroundDuodenum): - xTrackSurface.append(xSampledAll[n2][n1]) - d1TrackSurface.append(d1SampledAll[n2][n1]) - d2TrackSurface.append(d2SampledAll[n2][n1]) - - trackSurfaceStomach = TrackSurface(elementsCountAroundDuodenum, elementsCountAlongTrackSurface, - xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) - - if makeStomach: - # Set up gastro-oesophagal junction - GOJSettings['Number of elements around ostium'] = elementsCountAroundOesophagus - GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) - xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) - axis1 = d1Centre - - # fm = region.getFieldmodule() - mesh = fm.findMeshByDimension(3) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - - nextNodeIdentifier = nodeIdentifier - nextElementIdentifier = elementIdentifier - nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, - nextNodeIdentifier, nextElementIdentifier) - bodyStartNode = nextNodeIdentifier - - # From oesophagus to duodenum along lesser curvature (LC) - elementsOesoToDuodLC = elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) # CHECK - startProportion1, startProportion2 = trackSurfaceStomach.getProportion( - o1_Positions[int(elementsCountAroundOesophagus * 0.5)]) - d1Start = o1_d2[1][int(elementsCountAroundOesophagus * 0.5)] - - xOesoToDuodLC, d2OesoToDuodLC = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, 0.5, 1.0, - elementsOesoToDuodLC, startDerivative=d1Start, - startDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude(d1Start)) - - # From oesophagus to duodenum along greater curvature (GC) - xAlongGC = [] - d2AlongGC = [] - xAlongGC.append(o1_x[1][0]) - d2AlongGC.append(o1_d2[1][0]) - - oesoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] - elementsAlongUpstreamOfOeso = int(elementsCountAlongTrackSurface * oesoStartProportion2) - - # From oesophagus to fundus apex - arcLengthOesoApex = 0.0 - for n2 in range(elementsAlongUpstreamOfOeso): - nAlong = elementsAlongUpstreamOfOeso - n2 - v1 = xSampledAll[nAlong][int(elementsCountAroundDuodenum * 0.5)] - v2 = xSampledAll[nAlong - 1][int(elementsCountAroundDuodenum * 0.5)] - d = [v2[c] - v1[c] for c in range(3)] - arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) - arcLengthOesoApex += arcLengthAround - d2 = [c * arcLengthAround for c in vector.normalise(d)] - xAlongGC.append(v1) - d2AlongGC.append(d2) - - # From fundus apex to duodenum - for n2 in range(len(xSampledAll)): - xAlongGC.append(xSampledAll[n2][0]) - d2AlongGC.append(d2SampledAll[n2][0]) - - elementsOesoToDuodGC = elementsCountAlong + int(elementsCountAroundDuodenum * 0.5) - 2 # Check - xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurvesSmooth(xAlongGC, d2AlongGC, elementsOesoToDuodGC, - derivativeMagnitudeStart=annulusDerivativeFactor * vector.magnitude( - d2AlongGC[0]))[0:2] - # xOesoToDuodGC, d2OesoToDuodGC = interp.sampleCubicHermiteCurves(xAlongGC, d2AlongGC, elementsOesoToDuodGC, - # addLengthStart= vector.magnitude( - # d2AlongGC[0]), lengthFractionStart=0.5)[0:2] - - d2OesoToDuodGC = interp.smoothCubicHermiteDerivativesLine(xOesoToDuodGC, d2OesoToDuodGC) - # curvature - DONE - - arcLength = 0.0 - for e in range(len(xOesoToDuodGC) - 1): - arcLength += interp.getCubicHermiteArcLength(xOesoToDuodGC[e], d2OesoToDuodGC[e], - xOesoToDuodGC[e + 1], d2OesoToDuodGC[e + 1]) - if arcLength > arcLengthOesoApex: - nodesCountFromOesoToApex = e + 2 - break - - nodeIdentifier = nextNodeIdentifier - - # for n2 in range(len(xOesoToDuodLC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodLC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # for n2 in range(len(xOesoToDuodGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOesoToDuodGC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2OesoToDuodGC[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Spread out elements around for each egroup around - # Elements around oesophagus - # Decide where to put extra elements if elementsOesophagus/2 is odd number. - # Right now, extra elements go downstream of bifurcation - # For even numbers, we split elements at bifurcation - - ptsOnTrackSurfaceGC = [] - xAlongAround = [] - d1AlongAround = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) - - # Ring adjacent to LC - # First half - for n2 in range(int(elementsCountAroundOesophagus * 0.25 + 1), int(elementsCountAroundOesophagus * 0.5)): - ostiumIdx = n2 - GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + n2 - GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, elementsCountAlongTrackSurface) - GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) - - endPosition = o1_Positions[ostiumIdx] - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) - d2 = o1_d2[1][ostiumIdx] - d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - d1EndTrackSurface = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] - - xFirstHalf, d1FirstHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, - endProportion2, int(0.5 * elementsCountAroundDuodenum + 1), - startDerivative=d1GC, endDerivative= d1EndOstium, - endDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1EndOstium)) - - # for n2 in range(len(xFirstHalf)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstHalf[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1FirstHalf[n2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Second half - ostiumIdx2 = -n2 - startPosition = o1_Positions[ostiumIdx2] - d1StartOstium = o1_d2[1][ostiumIdx2] - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - d1StartTrackSurface = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[1] - - xSecondHalf, d1SecondHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, - GCProportion2, int(0.5 * elementsCountAroundDuodenum + 1), - startDerivative=d1StartOstium, endDerivative=d1GC, - startDerivativeMagnitude= annulusDerivativeFactor * vector.magnitude(d1StartOstium)) - - xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] - d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] - - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - - # Elements downstream of oesophagus - for idx in range(-(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1), 0): - startPosition, d1Start = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[idx], - ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, - elementsCountAlongTrackSurface) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - - endPosition = trackSurfaceStomach.findNearestPosition(xOesoToDuodLC[idx]) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - d1End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[1] - - xFirstHalf, d1FirstHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, startProportion2, endProportion1, - endProportion2, int(0.5 * elementsCountAroundDuodenum), - startDerivative=d1Start, endDerivative=d1End) - - xSecondHalf, d1SecondHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, endProportion1, endProportion2, 1.0, - startProportion2, int(0.5 * elementsCountAroundDuodenum), - startDerivative=d1End, endDerivative=d1Start) - - # Average adjacent ring with first downstream ring that is not adjacent to oesophagus - if idx == -(elementsCountAlong - int(elementsCountAroundOesophagus * 0.5) - 1): - xAve = [] - dAve = [] - xAve.append(xOesoToDuodGC[idx - 1]) - for n in range(1, int(elementsCountAroundDuodenum * 0.5)): - # nx = [xAround[n], xFirstHalf[n]] - # d = [xFirstHalf[n][c] - xAround[n][c] for c in range(3)] - # nd1 = [d, d] - # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] - # xAve.append(xSampled[1]) - - startPosition = trackSurfaceStomach.findNearestPosition(xAround[n]) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - endPosition = trackSurfaceStomach.findNearestPosition(xFirstHalf[n]) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - xSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, endProportion1, endProportion2, 2)[0] - xAve.append(xSampled[1]) - - xAve.append(xOesoToDuodLC[idx - 1]) - - for n in range(1, int(elementsCountAroundDuodenum * 0.5)): - # nx = [xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1], xSecondHalf[n]] - # d = [xSecondHalf[n][c] - xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1][c] for c in range(3)] - # nd1 = [d, d] - # xSampled = interp.sampleCubicHermiteCurves(nx, nd1, 2)[0] - # xAve.append(xSampled[1]) - - startPosition = trackSurfaceStomach.findNearestPosition(xAround[n + int(elementsCountAroundDuodenum * 0.5) + 1]) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - endPosition = trackSurfaceStomach.findNearestPosition(xSecondHalf[n]) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - xSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, endProportion1, endProportion2, 2)[0] - xAve.append(xSampled[1]) - - for n in range(len(xAve)): - v1 = xAve[n] - v2 = xAve[(n+1) % len(xAve)] - d1 = findDerivativeBetweenPoints(v1, v2) - dAve.append(d1) - dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) - - xAlongAround.append(xAve) - d1AlongAround.append(dAve) - - xAround = xFirstHalf + xSecondHalf[1:-1] - d1Around = d1FirstHalf + d1SecondHalf[1:-1] - d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - # calculate curvature - - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - - # for n2 in range(len(xAlongAround)): - # for n1 in range(len(xAlongAround[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1AlongAround[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround - ptsOnTrackSurfaceOesoToFundus = [] - for n2 in range(elementsCountAlongTrackSurface + 1): - ptsOnTrackSurfaceOesoToFundus.append(xSampledAll[n2][int(elementsCountAroundDuodenum * 0.5)]) - - xFirstTwoLoopsRight = [] - xFirstTwoLoopsLeft = [] - d2FirstTwoLoopsRight = [] #KM - d2FirstTwoLoopsLeft = [] # KM - - for nLoop in range(1, 3): - GCIdx = nLoop + 1 - if GCIdx < nodesCountFromOesoToApex: - ptsOnTrackSurface = ptsOnTrackSurfaceOesoToFundus - proportion1 = 0.5 - else: - ptsOnTrackSurface = ptsOnTrackSurfaceGC - proportion1 = 0.0 - d2GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], - ptsOnTrackSurface, - trackSurfaceStomach, proportion1, - elementsCountAlongTrackSurface)[1] - - if GCIdx < nodesCountFromOesoToApex: - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) - d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in - range(3)] - d2GC = d2GCRot - - for nSide in range(2): - if nSide == 0: - xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop] - d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] - - xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) - nLoop][c] for c in range(3)] - else: - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d2OesoToDuodGC[GCIdx]), math.pi) - d2GCRot = [rotFrame[j][0] * d2GC[0] + rotFrame[j][1] * d2GC[1] + rotFrame[j][2] * d2GC[2] for j in - range(3)] - d2GC = d2GCRot - - xEnd = xAlongAround[0][int(elementsCountAroundDuodenum * 0.5 + 1) + nLoop] - d2End = [xAlongAround[1][int(elementsCountAroundDuodenum * 0.5) + nLoop][c] - - xAlongAround[0][int(elementsCountAroundDuodenum * 0.5) + (0 if elementsCountAroundOesophagus > 8 else 1) + nLoop][c] for c in range(3)] - - nx = [xOesoToDuodGC[GCIdx], xEnd] - nd2 = [d2GC, d2End] - x, d2 = interp.sampleCubicHermiteCurves(nx, nd2, int(elementsCountAroundOesophagus * 0.25 + 2), - arcLengthDerivatives=True)[0:2] - - # Find closest sampled points onto track surface - xProjectedPoints = [] - d2ProjectedPoints = [] - for n2 in range(len(x)): - projectedPosition = trackSurfaceStomach.findNearestPosition(x[n2]) - xProjected = trackSurfaceStomach.evaluateCoordinates(projectedPosition) - xProjectedPoints.append(xProjected) - - for n2 in range(len(xProjectedPoints) - 1): - d2 = findDerivativeBetweenPoints(xProjectedPoints[n2], xProjectedPoints[n2 + 1]) - d2ProjectedPoints.append(d2) - d2ProjectedPoints.append(d2) - - # Sample points again - xLoop, d2Loop = interp.sampleCubicHermiteCurves(xProjectedPoints, d2ProjectedPoints, - int(elementsCountAroundOesophagus * 0.25 + 2))[0:2] - - (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft).append(xLoop) - (d2FirstTwoLoopsRight if nSide == 0 else d2FirstTwoLoopsLeft).append(d2Loop) - - # for n2 in range(len(xFirstTwoLoopsRight)): - # for n1 in range(len(xFirstTwoLoopsRight[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsRight[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsRight[n2][n1]) - # nodeIdentifier += 1 - # - # for n2 in range(len(xFirstTwoLoopsLeft)): - # for n1 in range(len(xFirstTwoLoopsLeft[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xFirstTwoLoopsLeft[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2FirstTwoLoopsLeft[n2][n1]) - # nodeIdentifier += 1 - - # Find triple point - xTriplePts = [[None], [None]] # Right, left - d1TriplePts = [[None], [None]] - d2TriplePts = [[None], [None]] - d3TriplePtsNorm = [[None], [None]] - - for nSide in range(2): - ostiumIdx = int(elementsCountAroundOesophagus * 0.25) if nSide == 0 else -int(elementsCountAroundOesophagus * 0.25) - p1x = o1_x[1][ostiumIdx] - d = o1_d2[1][ostiumIdx] - rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][ostiumIdx], math.pi) - p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - p1d = [annulusDerivativeFactor * c for c in p1d] - - xFirstTwoLoops = xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft - p2x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)] # downstream bifurcation - p2d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25 + 1)], - xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25 + 1)]) - - p3x = xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)] - p3d = findDerivativeBetweenPoints(xFirstTwoLoops[0][int(elementsCountAroundOesophagus * 0.25)], - xFirstTwoLoops[1][int(elementsCountAroundOesophagus * 0.25)]) - - xTriplePts[nSide], d1TriplePts[nSide], d2TriplePts[nSide] = get_bifurcation_triple_point(p1x, p1d, p2x, p2d, p3x, p3d) - d3TriplePtsNorm[nSide] = vector.normalise( - vector.crossproduct3(vector.normalise(d1TriplePts[nSide]), vector.normalise(d2TriplePts[nSide]))) - - # Make sure triple point is on track surface - triplePointPosition = trackSurfaceStomach.findNearestPosition(xTriplePts[nSide]) - xTriplePts[nSide] = trackSurfaceStomach.evaluateCoordinates(triplePointPosition) - - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p1x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p1d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p2x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p2d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - # - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, p3x) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, p3d) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1TriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2TriplePts[nSide]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3TriplePtsNorm[nSide]) - # nodeIdentifier += 1 - - # Use track surface to sample point on GC to loop 1 (includes bifurcation rings and additional upstream rings) - xBifurcationRings = [] - d1BifurcationRings = [] - xUp = [] - d1Up = [] - for n2 in range(int(elementsCountAroundOesophagus * 0.25)): - xAround = [] - d1Around = [] - loopIdx = n2 + 2 - ostiumIdx = loopIdx + (0 if n2 < int(elementsCountAroundOesophagus * 0.25 - 1) else -1) - GCIdx = int(elementsCountAroundDuodenum * 0.5 - 1) + 1 + n2 - GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xOesoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, - elementsCountAlongTrackSurface) - GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) - - if loopIdx < int(elementsCountAroundOesophagus * 0.25): # additional elements upstream of triple point - for nSide in range(2): - if nSide == 0: - xLoop = xFirstTwoLoopsRight[0][loopIdx] - xOstium = o1_x[1][ostiumIdx] - ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) - ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) - d = findDerivativeBetweenPoints(xLoop, xOstium) - endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, - GCProportion2, ostiumProportion1, ostiumProportion2, - int(elementsCountAroundDuodenum * 0.5 + 1), - startDerivative=d1GC, endDerivative=d, - endDerivativeMagnitude=endDerivativeMag)[0:2] - - else: - xLoop = xFirstTwoLoopsLeft[0][loopIdx] - xOstium = o1_x[1][-ostiumIdx] - ostiumPosition = trackSurfaceStomach.findNearestPosition(xOstium) - ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) - d = findDerivativeBetweenPoints(xOstium, xLoop) - startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, - 1.0, GCProportion2, - int(elementsCountAroundDuodenum * 0.5 + 1), - startDerivative= d, endDerivative=d1GC, - startDerivativeMagnitude=startDerivativeMag)[0:2] - - xAround += xSampled[:-1] if nSide == 0 else xSampled[1:-1] - d1Around += dSampled[:-1] if nSide == 0 else dSampled[1:-1] - - # for n1 in range(len(xAround)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Around[n1]) - # nodeIdentifier += 1 - - # xBifurcationRings.append(xAround) - # d1BifurcationRings.append(d1Around) - xUp.append(xAround) - d1Up.append(d1Around) - - else: # connected to triple point - for nSide in range(2): - xLoop = (xFirstTwoLoopsRight if nSide == 0 else xFirstTwoLoopsLeft)[0][loopIdx] - loopPosition = trackSurfaceStomach.findNearestPosition(xLoop) - loopProportion1, loopProportion2 = trackSurfaceStomach.getProportion(loopPosition) - - if nSide == 0: - d = findDerivativeBetweenPoints(xLoop, o1_x[1][ostiumIdx]) - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, - GCProportion2, loopProportion1, loopProportion2, - int(elementsCountAroundDuodenum * 0.5) - 1, - startDerivative=d1GC, endDerivative = d)[0:2] - xSampled.append(xTriplePts[0]) - dSampled.append(d1TriplePts[0]) - - else: - d = findDerivativeBetweenPoints(o1_x[1][-ostiumIdx], xLoop) - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, loopProportion1, - loopProportion2, 1.0, GCProportion2, - int(elementsCountAroundDuodenum * 0.5) - 1, - startDerivative = d, endDerivative=d1GC)[0:2] - xSampled.insert(0, xTriplePts[1]) - dSampled.insert(0, d1TriplePts[1]) - - xAround += xSampled if nSide == 0 else xSampled[:-1] - d1Around += dSampled if nSide == 0 else dSampled[:-1] - - xUp.append(xAround) - d1Up.append(d1Around) - xBifurcationRings.append(xAround) - d1BifurcationRings.append(d1Around) - - # for n2 in range(len(xBifurcationRings)): - # for n1 in range(len(xBifurcationRings[n2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xBifurcationRings[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1BifurcationRings[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Row 2 - for nSide in range(2): - if nSide == 0: - xStart = xUp[0][1] - dStart = findDerivativeBetweenPoints(xUp[1][1], xUp[0][1]) - startDerivativeMag = None - xEnd = o1_x[1][1] - dEnd = findDerivativeBetweenPoints(xFirstTwoLoopsRight[0][1], o1_x[1][1]) - endDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) - - else: - xStart = o1_x[1][-1] - dStart = findDerivativeBetweenPoints(o1_x[1][-1], xFirstTwoLoopsLeft[0][1]) - startDerivativeMag = annulusDerivativeFactor * vector.magnitude(o1_d2[1][1]) - xEnd = xUp[0][-1] - dEnd = findDerivativeBetweenPoints(xUp[0][-1], xUp[1][-1]) - endDerivativeMag = None - - startPosition = trackSurfaceStomach.findNearestPosition(xStart) - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - endPosition = trackSurfaceStomach.findNearestPosition(xEnd) - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - - xSampled, dSampled = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, - endProportion1, endProportion2, - int(elementsCountAroundDuodenum * 0.5), - startDerivative=dStart, endDerivative=dEnd, - startDerivativeMagnitude=startDerivativeMag, - endDerivativeMagnitude=endDerivativeMag)[0:2] - - if nSide == 0: - xRow2Right = xSampled[:-1] - d1Row2Right = dSampled[:-1] - else: - xRow2Left = xSampled[1:] - d1Row2Left = dSampled[1:] - - # for n1 in range(len(xRow2Right)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Right[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Right[n1]) - # nodeIdentifier += 1 - - # for n1 in range(len(xRow2Left)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRow2Left[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d1Row2Left[n1]) - # nodeIdentifier += 1 - - # Smooth derivatives from triple point to 6 point junction - # Start from GC at upstream bifurcation ring to annulus to 6 point junction ring on right then left - xLoopTripleTo6Pt = [] - dLoopTripleTo6Pt = [] - - xLoopTripleTo6Pt += xBifurcationRings[0][0:int(len(xBifurcationRings[0]) * 0.5) + 1] - for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): - xLoopTripleTo6Pt.append(xAlongAround[n2][int(len(xAlongAround[n2]) * 0.5)]) - junctionIdx = n2 + 1 - xLoopTripleTo6Pt += xAlongAround[junctionIdx][int(len(xAlongAround[junctionIdx]) * 0.5):] + \ - xAlongAround[junctionIdx][0: int(len(xAlongAround[junctionIdx]) * 0.5 + 1)] - for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): # Note order here - going upstream - idx = junctionIdx - 1 - n2 - xLoopTripleTo6Pt.append(xAlongAround[idx][int(len(xAlongAround[idx]) * 0.5) + 1]) - xLoopTripleTo6Pt += xBifurcationRings[0][int(len(xBifurcationRings[0]) * 0.5 + 1):] - - for n in range(len(xLoopTripleTo6Pt)): - d = findDerivativeBetweenPoints(xLoopTripleTo6Pt[n], xLoopTripleTo6Pt[(n+1) % len(xLoopTripleTo6Pt)]) - dLoopTripleTo6Pt.append(d) - dSmoothLoopTripleTo6Pt = interp.smoothCubicHermiteDerivativesLoop(xLoopTripleTo6Pt, dLoopTripleTo6Pt) - # curvature - DONE - - # for n1 in range(len(xLoopTripleTo6Pt)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopTripleTo6Pt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopTripleTo6Pt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) - # nodeIdentifier += 1 - - # Smooth derivatives around top loop - # Starts from GC at downstream bifurcation ring to annulus and back - xLoopGCTriplePt = [] - dLoopGCTriplePt = [] - - xLoopGCTriplePt += xBifurcationRings[1][:int(len(xBifurcationRings[1]) * 0.5) + 1] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): - idx = -(3 + n2) - xLoopGCTriplePt.append(xUp[idx][int(len(xUp[idx]) * 0.5)]) - - xLoopGCTriplePt += [xRow2Right[-1]] + [xOesoToDuodGC[1]] + [xRow2Left[0]] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25 - 2)): - xLoopGCTriplePt.append(xUp[n2][int(len(xUp[n2]) * 0.5) + 1]) - - xLoopGCTriplePt += xBifurcationRings[1][int(len(xBifurcationRings[1]) * 0.5) + 1:] - - for n in range(len(xLoopGCTriplePt)): - d = findDerivativeBetweenPoints(xLoopGCTriplePt[n], xLoopGCTriplePt[(n+1) % len(xLoopGCTriplePt)]) - dLoopGCTriplePt.append(d) - dSmoothLoopGCTriplePt = interp.smoothCubicHermiteDerivativesLoop(xLoopGCTriplePt, dLoopGCTriplePt) - # curvature - DONE - - # for n1 in range(len(xLoopGCTriplePt)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoopGCTriplePt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dSmoothLoopGCTriplePt[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #dLoopGCTriplePt[n1]) - # nodeIdentifier += 1 - - # Assemble nodes and d1 - xOuter = [] - d1Outer = [] - countUp = 0 - countDown = 0 - for n2 in range(elementsCountAlong + 1): - xAround = [] - d1Around = [] - d2Around = [] - if n2 == 0: - # print(n2, 'GC') - for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): - xAround.append(xOesoToDuodGC[i + 1]) - d1Around.append(d2OesoToDuodGC[i + 1]) - - elif n2 == 1: - # print(n2, 'Row 2') - xAround = [xOesoToDuodGC[i + n2 + 1]] + xRow2Right[1:] + xRow2Left[:-1] - d1Around = [d2OesoToDuodGC[i + n2 + 1]] + d1Row2Right[1:] + d1Row2Left[:-1] # need to replace d1Row2 after smoothing - DONE - - elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): - # print(n2, 'Before triple point + triple point') - xAround = xUp[countUp] - if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt - # smooth d1 around - Make into function? - d1Around = d1Up[countUp] - 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)] - d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, - fixEndDerivative=True) - # Need to do curvature and rearrange to correct order - d1Around = [] - d1Around = d1LoopSmooth[int(len(xAround) * 0.5) : ] + d1LoopSmooth[: int(len(xAround) * 0.5) : ] - - elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation - # take smoothed d1 from dSmoothTripleTo6Pt - d1Around = dSmoothLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ - dSmoothLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5) : ] - - elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation - # take smoothed d1 from dSmoothGCToTriplePt - d1Around = dSmoothLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ - dSmoothLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5) : ] - countUp += 1 - - elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): - # print(n2, 'Downstream of triple point') - xAround = xAlongAround[countDown] - d1Around = d1AlongAround[countDown] - - # smooth d1 around - Make into function? - if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): - 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)] - d1LoopSmooth = interp.smoothCubicHermiteDerivativesLine(xLoop, d1Loop, fixStartDerivative=True, - fixEndDerivative=True) - # Need to do curvature and rearrange to correct order - d1Around = [] - d1Around = d1LoopSmooth[int(len(xAround) * 0.5):] + d1LoopSmooth[: int(len(xAround) * 0.5):] - - elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring - # take smoothed d1 from dSmoothedTripleTo6Pt - startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len(xAlongAround[junctionIdx]) * 0.5) - endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - d1Around = dSmoothLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ - dSmoothLoopTripleTo6Pt[startLeftIdx : startRightIdx] - countDown += 1 - - xOuter.append(xAround) - d1Outer.append(d1Around) - - # for m2 in range(len(xOuter)): - # for m1 in range(len(xOuter[m2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Calculate d2 - xRegularLoops = [] - d2RegularLoops = [] - d2RegularOrderedLoops = [] - - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): - xRegularLoop = [] - d1RegularRightLoop = [] - d2RegularLoop = [] - for n2 in range(elementsCountAlong): - idx = -(1 + n2) - xRegularLoop.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - d1RegularRightLoop.append(d1Outer[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - xRegularLoop.append(xOesoToDuodGC[n1 + 2]) - for n2 in range(elementsCountAlong): - xRegularLoop.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) - - for n in range(len(xRegularLoop) - 1): - d = findDerivativeBetweenPoints(xRegularLoop[n], xRegularLoop[n+1]) - d2RegularLoop.append(d) - d2RegularLoop.append(d) - - d2SmoothRegularLoop = interp.smoothCubicHermiteDerivativesLine(xRegularLoop, d2RegularLoop) - d2SmoothRegularOrderedLoop = copy.deepcopy(d2SmoothRegularLoop) - # curvature - DONE - - # Switch direction on right side - for n2 in range(elementsCountAlong): - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1RegularRightLoop[n2]), d2SmoothRegularLoop[n2])) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d = d2SmoothRegularLoop[n2] - d2SmoothRegularLoop[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - - xRegularLoops.append(xRegularLoop) - d2RegularLoops.append(d2SmoothRegularLoop) - d2RegularOrderedLoops.append(d2SmoothRegularOrderedLoop) - - # for m1 in range(len(xRegularLoops)): - # for m2 in range(len(xRegularLoops[m1])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xRegularLoops[m1][m2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2RegularOrderedLoops[m1][m2]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) #d2RegularLoops[m1][m2]) - # nodeIdentifier += 1 - - # Smooth d2 along row 2 - xLoop2Right = [] - d1Loop2Right = [] - d2Loop2Right = [] - - for n2 in range(len(xAlongAround) + len(xUp) - 1): - idx = -(1 + n2) - xLoop2Right.append(xOuter[idx][1]) - d1Loop2Right.append(d1Outer[idx][1]) - xLoop2Right += xRow2Right - d1Loop2Right += d1Row2Right - - for n in range(len(xLoop2Right) - 1): - d = findDerivativeBetweenPoints(xLoop2Right[n], xLoop2Right[n + 1]) - d2Loop2Right.append(d) - d2Loop2Right.append(d1Row2Right[-1]) - - d2Loop2Right = interp.smoothCubicHermiteDerivativesLine(xLoop2Right, d2Loop2Right, fixEndDirection=True) - # curvature - USING LEFT SIDE - DONE - - # Switch direction of d2 for downstream nodes - for n2 in range(len(xAlongAround) + len(xUp)): - rotAxis = vector.normalise( - vector.crossproduct3(vector.normalise(d1Loop2Right[n2]), d2Loop2Right[n2])) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d = d2Loop2Right[n2] - d2Loop2Right[n2] = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - idxSwitchToD1 = n2 - - # for m in range(len(xLoop2Right)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Right[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) #d2Loop2Right[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Loop2Right[m]) - # nodeIdentifier += 1 - - # Left - xLoop2Left = [] - d2Loop2Left = [] - - xLoop2Left += xRow2Left - for n2 in range(3, len(xOuter)): - xLoop2Left.append(xOuter[n2][-1]) - - d2Loop2Left.append(d1Row2Left[0]) - for n in range(1, len(xLoop2Left) - 1): - d = findDerivativeBetweenPoints(xLoop2Left[n], xLoop2Left[n + 1]) - d2Loop2Left.append(d) - d2Loop2Left.append(d) - - d2Loop2Left = interp.smoothCubicHermiteDerivativesLine(xLoop2Left, d2Loop2Left, fixStartDirection=True) - # curvature - DONE - - # for m in range(len(xLoop2Left)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLoop2Left[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Loop2Left[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Smooth lower curvature - xLC = [] - d2LC = [] - for n2 in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): - xLC.append(xOuter[n2][int(len(xOuter[n2]) * 0.5)]) - - for n in range(len(xLC) - 1): - d = findDerivativeBetweenPoints(xLC[n], xLC[n + 1]) - d2LC.append(d) - d2LC.append(d) - - d2LC = interp.smoothCubicHermiteDerivativesLine(xLC, d2LC, fixStartDirection=True) - # curvature - DONE - - # for m in range(len(xLC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xLC[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2LC[m]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Update d1 for upstream nodes - for n1 in range(1, len(xRow2Right)): - d1Outer[1][n1] = d2Loop2Right[idxSwitchToD1 + n1] - for n1 in range(1, len(xRow2Left)): - d1Outer[1][int(len(d1Outer[1]) * 0.5) + n1] = d2Loop2Left[n1 - 1] - - # Assemble d2 - d2Outer = [] - for n2 in range(elementsCountAlong + 1): - d2Around = [] - xAround = [] # KM - if n2 == 0: - # print(n2, 'GC') - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5)]) #KM - d2Around.append(dSmoothLoopGCTriplePt[int(len(dSmoothLoopGCTriplePt) * 0.5)]) - - for n1 in range(len(xOuter[0]) - 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) - d2Around.append(d2RegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5)]) - nextIdx = n1 + 1 - - elif n2 == 1: - # print(n2, 'Row 2') - xAround.append(xRegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) - d2Around.append(d2RegularLoops[nextIdx][int(len(xRegularLoops[nextIdx]) * 0.5)]) - - for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) - - # right point on annulus - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2]) # KM - d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2] - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), vector.normalise(d2))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d2Around.append([rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) - - # left point on annulus - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) # KM - d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2]) - - for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) - - elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): - # print(n2, 'Before triple point + triple point') - # GC - xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) - d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) - - # Row 2 right - xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) - d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) - - # Regular up right - for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) - - # Annulus right - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM - d2 = dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)] - if n2 <= int(elementsCountAroundOesophagus * 0.25): # Rotate to point towards duodenum - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5)]), - vector.normalise(d2))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d2Around.append( - [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)]) - else: # just take d2 as-is cos we are going to remove this point later - d2Around.append(d2) - - # Annulus left - xAround.append(xLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) # KM - d2Around.append(dSmoothLoopGCTriplePt[int(len(xLoopGCTriplePt) * 0.5) + n2 - (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) - - # Regular down left - for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) - - # Row 2 left - xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) - d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) - - # for m1 in range(len(d2Around)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAround[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d2Around[m1]) - # nodeIdentifier += 1 - - elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): - # print(n2, 'Downstream of triple point') - # GC - xAround.append(xOesoToDuodGC[len(xOuter[0]) + n2]) - d2Around.append(d2OesoToDuodGC[len(xOuter[0]) + n2]) - - # Row 2 right - xAround.append(xLoop2Right[-(len(xOuter[0]) + n2)]) - d2Around.append(d2Loop2Right[-(len(xOuter[0]) + n2)]) - - # Regular up right - for n1 in range(nextIdx, -1, -1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) - n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) - n2]) - - if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: - # Annulus right - # print('between triple and 6 pt') - idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) - xAround.append(xLoopTripleTo6Pt[idx]) - if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: - d1 = dSmoothLoopTripleTo6Pt[idx] - d1Outer[n2][int(len(d1Outer[n2]) * 0.5)] = d1 - else: - d2Around.append(dSmoothLoopTripleTo6Pt[idx]) - - # Annulus left - need to rotate to point towards duodenum - xAround.append(xLoopTripleTo6Pt[-idx]) - # d2Around.append(dSmoothLoopTripleTo6Pt[-idx]) - d2 = dSmoothLoopTripleTo6Pt[-idx] - if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): - rotAxis = vector.normalise( - vector.crossproduct3(vector.normalise(d1Outer[n2][int(len(d1Outer[n2]) * 0.5 + 1)]), - vector.normalise(d2))) - else: # use d2 on previous overlapping point to rotate - rotAxis = vector.normalise( - vector.crossproduct3(vector.normalise(d1), vector.normalise(d2))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) - d2Around.append( - [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in - range(3)]) - - elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: - # print('beyond 6 pt') - # LC - xAround.append(xLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) - d2Around.append(d2LC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1)]) - - # Regular down left - for n1 in range(nextIdx + 1): - xAround.append(xRegularLoops[n1][int(len(xRegularLoops[n1]) * 0.5) + n2]) - d2Around.append(d2RegularLoops[n1][int(len(d2RegularLoops[n1]) * 0.5) + n2]) - - # Row 2 left - xAround.append(xLoop2Left[len(xOuter[0]) + n2 - 1]) - d2Around.append(d2Loop2Left[len(xOuter[0]) + n2 - 1]) - - d2Outer.append(d2Around) - - # remove triple point on both sides from downstream ring - n2Idx = int(elementsCountAroundOesophagus * 0.25 + 1) - n1Idx = int(len(xOuter[n2Idx]) * 0.5) - del xOuter[n2Idx][n1Idx: n1Idx + 2], d1Outer[n2Idx][n1Idx: n1Idx + 2], d2Outer[n2Idx][n1Idx: n1Idx + 2] - - d3UnitOuter = [] - for n2 in range(elementsCountAlong + 1): - d3Around = [] - for n1 in range(len(xOuter[n2])): - d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1Outer[n2][n1]), vector.normalise(d2Outer[n2][n1])))) - d3UnitOuter.append(d3Around) - - # for m2 in range(len(xOuter)): - # for m1 in range(len(xOuter[m2])): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xOuter[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Outer[m2][m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitOuter[m2][m1]) - # nodeIdentifier += 1 - - # Calculate curvatures - # Curvatures along GC - xGC = [] - dGC = [] - norms = [] - for n1 in range(len(xOuter[0])): - xGC.append(xOuter[0][n1]) - dGC.append(d1Outer[0][n1]) - norms.append(d3UnitOuter[0][n1]) - for n2 in range(1, elementsCountAlong + 1): - xGC.append(xOuter[n2][0]) - dGC.append(d1Outer[n2][0] if n2 == 1 else d2Outer[n2][0]) - norms.append(d3UnitOuter[n2][0]) - curvatureAlongGC = findCurvatureAlongLine(xGC, dGC, norms) # 1st len(xOuter[0]) + 1 are for d1, the rest for d2 - - # for m1 in range(len(xGC)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dGC[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - # nodeIdentifier += 1 - - # Curvature along rows adjacent to GC - calculate with left and use the same for right - norms = [] - xTest = [] - for n in range(int(len(xOuter[1]) * 0.5)): # d1s - xTest.append(xOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) # KM - norms.append(d3UnitOuter[1][n + int(len(xOuter[1]) * 0.5) + 1]) - for n2 in range(2, elementsCountAlong + 1): # d2s - xTest.append(xOuter[n2][-1]) # KM - norms.append(d3UnitOuter[n2][-1]) - curvatureAlong2Left = findCurvatureAlongLine(xLoop2Left, d2Loop2Left, norms) - - # for m1 in range(len(xTest)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTest[m1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, norms[m1]) - # nodeIdentifier += 1 - - # Curvature along LC - xTest = [] # KM - norms = [] - for n in range(int(elementsCountAroundOesophagus * 0.5) + 1, elementsCountAlong + 1): - xTest.append(xOuter[n][int(len(xOuter[n]) * 0.5)]) - norms.append(d3UnitOuter[n][int(len(xOuter[n]) * 0.5)]) - curvatureAlongLC = findCurvatureAlongLine(xLC[1:], d2LC[1:], norms) - - # Curvature along path from triple point to 6 point junction - xTest = [] # KM - norms = [] - idxToAnnulus = int(elementsCountAroundDuodenum * 0.5 + 1) - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][: idxToAnnulus] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][:idxToAnnulus] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25)): - idx = int(elementsCountAroundOesophagus * 0.25) + 2 + n2 - if idx < (elementsCountAroundOesophagus * 0.5) + 1: - xTest.append(xOuter[idx][idxToAnnulus - 1]) - norms.append(d3UnitOuter[idx][idxToAnnulus - 1]) - xTest += xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ - xOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][idxToAnnulus - 1:] + \ - d3UnitOuter[int(elementsCountAroundOesophagus * 0.5 + 1)][: idxToAnnulus] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25) - 1): - idx = int(elementsCountAroundOesophagus * 0.5) - n2 - xTest.append(xOuter[idx][idxToAnnulus]) - norms.append(d3UnitOuter[idx][idxToAnnulus]) - - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25)][idxToAnnulus:] - - curvatureLoopTripleTo6Pt = findCurvatureAroundLoop(xLoopTripleTo6Pt, dSmoothLoopTripleTo6Pt, norms) - - # Curvature along path from GC to triple point - xTest = [] # KM - norms = [] - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][:idxToAnnulus - 1] - - for n2 in range(int(elementsCountAroundOesophagus * 0.25)): - idx = int(elementsCountAroundOesophagus * 0.25 - n2) - xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5)]) - norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5)]) - xTest.append(xOuter[0][0]) - norms.append(d3UnitOuter[0][0]) - for n2 in range(1, int(elementsCountAroundOesophagus * 0.25) + 1): - xTest.append(xOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) - norms.append(d3UnitOuter[n2][int(len(xOuter[n2]) * 0.5) + 1]) - xTest += xOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] - norms += d3UnitOuter[int(elementsCountAroundOesophagus * 0.25) + 1][idxToAnnulus - 1:] - curvatureLoopGCTriplePt = findCurvatureAroundLoop(xLoopGCTriplePt, dSmoothLoopGCTriplePt, norms) - - # Curvature around regular loops - curvatureRegularLoops = [] - for n1 in range(int(elementsCountAroundDuodenum * 0.5) - 2): - xTest = [] - norms = [] - for n2 in range(elementsCountAlong): - idx = -(1 + n2) - xTest.append(xOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - norms.append(d3UnitOuter[idx][int(len(xOuter[idx]) * 0.5 - 1 - n1)]) - if n1 < int(elementsCountAroundDuodenum * 0.5) - 3: - xTest.append(xOuter[0][(n1 + 1)]) - norms.append(d3UnitOuter[0][n1 + 1]) - else: - xTest.append(xOuter[idx][0]) - norms.append(d3UnitOuter[idx][0]) - for n2 in range(elementsCountAlong): - xTest.append(xOuter[n2 + 1][int(len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) - norms.append(d3UnitOuter[n2 + 1][int( - len(xOuter[n2 + 1]) * 0.5 + n1 + (1 if n2 >= int(elementsCountAroundOesophagus * 0.5) else 2))]) - curvatureLoop = findCurvatureAlongLine(xRegularLoops[n1], d2RegularOrderedLoops[n1], norms) - curvatureRegularLoops.append(curvatureLoop) - - # Assemble curvatures - d1Curvature = [] - d2Curvature = [] - countUp = 0 - countDown = 0 - for n2 in range(elementsCountAlong + 1): - d1CurvatureAround = [] - d2CurvatureAround = [] - if n2 == 0: - # print(n2, 'GC') - for i in range(int(elementsCountAroundDuodenum * 0.5) - 2): - d1CurvatureAround.append(curvatureAlongGC[i]) - - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5)]) - for n1 in range(len(xOuter[0]) - 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5)]) - nextIdx = n1 + 1 - - elif n2 == 1: - # print(n2, 'Row 2') - d1CurvatureAround.append(curvatureAlongGC[i + n2]) - xTest = [] - dTest = [] - for n in range(int(len(xOuter[1]) * 0.5) - 1, -1, -1): - d1CurvatureAround.append(curvatureAlong2Left[n]) - d1CurvatureAround += curvatureAlong2Left[:int(len(xOuter[1]) * 0.5)] - xTest = xLoop2Left[:int(len(xOuter[1]) * 0.5)] - dTest = d2Loop2Left[:int(len(xOuter[1]) * 0.5)] - - d2CurvatureAround.append(curvatureRegularLoops[nextIdx][int(len(curvatureRegularLoops[nextIdx]) * 0.5)]) - for n1 in range(nextIdx, -1, -1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) - # right point on annulus - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) - n2]) - # left point on annulus - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2]) - for n1 in range(nextIdx + 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) - - elif n2 > 1 and n2 < int(elementsCountAroundOesophagus * 0.25 + 2): - # print(n2, 'Before triple point + triple point') - xAround = xOuter[n2] - if n2 < int(elementsCountAroundOesophagus * 0.25): # upstream of triple pt - # smooth d1 around - Make into function? - d1Around = d1Outer[n2] - norms = d3UnitOuter[n2] - 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 = norms[int(len(d1Around) * 0.5 + 1):] + norms[: 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):] - - elif n2 == int(elementsCountAroundOesophagus * 0.25): # upstream bifurcation - # take smoothed d1 from dSmoothTripleTo6Pt - d1CurvatureAround = curvatureLoopTripleTo6Pt[: int(len(xBifurcationRings[0]) * 0.5) + 1] + \ - curvatureLoopTripleTo6Pt[-int(len(xBifurcationRings[0]) * 0.5):] - - elif n2 > int(elementsCountAroundOesophagus * 0.25): # downstream bifurcation - # take smoothed d1 from dSmoothGCToTriplePt - d1CurvatureAround = curvatureLoopGCTriplePt[: int(len(xBifurcationRings[1]) * 0.5) + 1] + \ - curvatureLoopGCTriplePt[-int(len(xBifurcationRings[1]) * 0.5):] - - # GC - d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) - # Row 2 right - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - # Regular up right - for n1 in range(nextIdx, -1, -1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) - # Annulus right - d2CurvatureAround.append(curvatureLoopGCTriplePt[ - int(len(curvatureLoopGCTriplePt) * 0.5) - n2 + (1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) - # Annulus left - d2CurvatureAround.append(curvatureLoopGCTriplePt[int(len(curvatureLoopGCTriplePt) * 0.5) + n2 - ( - 1 if n2 > elementsCountAroundOesophagus * 0.25 else 0)]) - # Regular down left - for n1 in range(nextIdx + 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) - # Row 2 left - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - - elif n2 > int(elementsCountAroundOesophagus * 0.25 + 1): - # print(n2, 'Downstream of triple point') - xAround = xOuter[n2] - d1Around = d1Outer[n2] - normsAround = d3UnitOuter[n2] - - # smooth d1 around - Make into function? - if n2 < int(elementsCountAroundOesophagus * 0.5 + 1): - 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(normsAround) * 0.5 + 1):] + normsAround[: int(len(normsAround) * 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):] - - elif n2 == int(elementsCountAroundOesophagus * 0.5 + 1): # 6 point junction ring - # take smoothed d1 from dSmoothedTripleTo6Pt - startRightIdx = int(len(xBifurcationRings[0]) * 0.5 + elementsCountAroundOesophagus * 0.25 + len( - xAlongAround[junctionIdx]) * 0.5) - endRightIdx = startRightIdx + int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - startLeftIdx = startRightIdx - int(len(xAlongAround[junctionIdx]) * 0.5) + 1 - d1CurvatureAround = curvatureLoopTripleTo6Pt[startRightIdx: endRightIdx] + \ - curvatureLoopTripleTo6Pt[startLeftIdx: startRightIdx] - - if n2 > int(elementsCountAroundOesophagus * 0.5 + 1): # closed rings beyond 6 point junction - 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(normsAround) * 0.5 + 1):] + normsAround[ : int(len(normsAround) * 0.5 + 1)] - curvature = findCurvatureAroundLoop(xLoop, d1Loop, normsLoop) - # Rearrange to correct order - d1CurvatureAround = curvature[int(len(xLoop) * 0.5) - 1:] + curvature[: int(len(xAround) * 0.5) - 1] - - # GC - d2CurvatureAround.append(curvatureAlongGC[len(xOuter[0]) + n2 - 1]) - # Row 2 right - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - # Regular up right - for n1 in range(nextIdx, -1, -1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) - n2]) - if n2 <= int(elementsCountAroundOesophagus * 0.5) + 1: - # Annulus right - # print('between triple and 6 pt') - idx = int(len(xBifurcationRings[0]) * 0.5 + n2 - elementsCountAroundOesophagus * 0.25 - 1) - if n2 == int(elementsCountAroundOesophagus * 0.5) + 1: - d1CurvatureAround[int(len(d1Outer[n2]) * 0.5)] = curvatureLoopTripleTo6Pt[idx] - else: - d2CurvatureAround.append(curvatureLoopTripleTo6Pt[idx]) - # Annulus left - d2CurvatureAround.append(curvatureLoopTripleTo6Pt[-idx]) - elif n2 > int(elementsCountAroundOesophagus * 0.5) + 1: - # print('beyond 6 pt') - # LC - d2CurvatureAround.append(curvatureAlongLC[n2 - (int(elementsCountAroundOesophagus * 0.5) + 1) - 1]) - # Regular down left - for n1 in range(nextIdx + 1): - d2CurvatureAround.append(curvatureRegularLoops[n1][int(len(curvatureRegularLoops[n1]) * 0.5) + n2]) - # Row 2 left - d2CurvatureAround.append(curvatureAlong2Left[len(xOuter[0]) + n2 - 1]) - - d1Curvature.append(d1CurvatureAround) - d2Curvature.append(d2CurvatureAround) - - # Create inner nodes - xList = [] - d1List = [] - d2List = [] - d3List = [] - nodeIdx = bodyStartNode - - idxMat = [] - - for n2 in range(elementsCountAlong + 1): - idxThroughWall = [] - for n3 in range(elementsCountThroughWall + 1): - xi3 = 1 / elementsCountThroughWall * n3 - idxAround = [] - for n1 in range(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 * xi3 * d1Curvature[n2][n1] - d1 = [factor * c for c in d1Outer[n2][n1]] - d1List.append(d1) - - # d2 - factor = 1.0 - wallThickness * xi3 * d2Curvature[n2][n1] - d2 = [factor * c for c in d2Outer[n2][n1]] - d2List.append(d2) - - # d3 - d3 = [c * wallThickness / elementsCountThroughWall for c in norm] - d3List.append(d3) - - idxAround.append(nodeIdx) - nodeIdx += 1 - - idxThroughWall.append(idxAround) - idxMat.append(idxThroughWall) - - 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 - - # Create element - mesh = fm.findMeshByDimension(3) - - 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) - result = elementtemplateStandard.defineField(coordinates, -1, eftStandard) - - elementtemplateX = mesh.createElementtemplate() - elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) - - elementIdentifier = nextElementIdentifier - - for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2): - # Row 1 - if e2 == 0: - startNode = bodyStartNode - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(int(elementsCountAround1) * 2 + 1): - if e1 != elementsCountAround1: - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - if e1 < elementsCountAround1: - # scaleFactors = [-1.0] - if e1 == 0: - bni11 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 + e1 - bni12 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - 1 - else: - bni11 = startNode + elementsCountAround1 - e1 + e3 * elementsCountAround1 - bni12 = bni11 - 1 - bni21 = startNode + elementsAroundThroughWall + 1 + e1 + e3 * elementsCountAround2 - bni22 = bni21 + 1 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + ( - elementsCountAround2 if e1 == 0 else elementsCountAround1), - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - scaleFactors = [-1.0] - setEftScaleFactorIds(eft1, [1], []) - scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], - [Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS1DS3, - Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) - scaleEftNodeValueLabels(eft1, [1, 2, 5, 6], - [Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D2_DS2DS3, - Node.VALUE_LABEL_D3_DS1DS2DS3], [1]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > elementsCountAround1: - if e1 < elementsCountAround1 * 2: - bni11 = startNode + e1 - elementsCountAround1 - 1 + elementsCountAround1 * e3 - bni12 = bni11 + 1 - else: - bni11 = startNode + elementsCountAround1 + e3 * elementsCountAround1 - 1 - bni12 = startNode + elementsAroundThroughWall + e3 * elementsCountAround2 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 - bni22 = bni21 + 1 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, - bni12 + ( - elementsCountAround1 if e1 < elementsCountAround1 * 2 else elementsCountAround2), - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Row 2 - elif e2 == 1: - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 + 2): - if e1 != int(elementsCountAround1 * 0.5 + 1): - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - - if e1 < 2: - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + ( - e1 + 1) # % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + e1 - bni22 = startNode + elementsAroundThroughWall + elementsCountAround2 * e3 + ( - e1 + 1) # % elementsCountAround2 - if e1 == 0: # Remap derivatives of element adjacent to GC - scaleFactors = [-1.0] - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 5], 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, [])]) - 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_DS2, [])]) - elif e1 == 1: # Bottom right wedge - nodeIdentifiers = [bni11, bni21, bni22, - bni11 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([1, 5]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > 1 and e1 < elementsCountAround1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 - bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - elif e1 >= elementsCountAround1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 2 - bni12 = startNode + e3 * elementsCountAround1 + (e1 - 1) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - if e1 == elementsCountAround1: # Bottom left wedge - nodeIdentifiers = [bni12, bni21, bni22, - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi1Quadrant([2, 6]) - elif e1 == elementsCountAround1 + 1: # Remap derivatives of element adjacent to GC - scaleFactors = [-1.0] - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, - bni12 + elementsCountAround1, - bni21 + elementsCountAround2, - bni22 + elementsCountAround2] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Additional elements between second and upstream bifurcation ring - elif e2 > 1 and e2 < int(elementsCountAroundOesophagus * 0.25): - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1): - if e1 != int(elementsCountAround1 * 0.5): - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Upstream bifurcation - elif e2 == int(elementsCountAroundOesophagus * 0.25): - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1): - if e1 != int(elementsCountAround1 * 0.5): - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - - if e1 < int(elementsCountAround1 * 0.5) - 1: - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - elif e1 == int(elementsCountAround1 * 0.5) - 1: # right wedge - nodeIdentifiers = [bni11, bni12, bni21, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(elementsCountAround1 * 0.5) + 1: # left wedge - bni21 = bni21 - 1 - nodeIdentifiers = [bni11, bni12, bni21, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 > int(elementsCountAround1 * 0.5) + 1: - bni21 = bni21 - 2 - bni22 = startNode + elementsAroundThroughWall + ( - e1 - 1) % elementsCountAround2 + elementsCountAround2 * e3 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Downstream bifurcation - elif e2 == int(elementsCountAroundOesophagus * 0.25) + 1: - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 + 1): - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - if e1 < int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - elif e1 == int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( - xOuter[e2 - 1]) + e1 + 1 - elif e1 > int(elementsCountAround1 * 0.5) + 1: - bni11 = startNode + e3 * elementsCountAround1 + e1 - 1 - - if e1 < int(elementsCountAround1 * 0.5): - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - elif e1 == int(elementsCountAround1 * 0.5): - bni12 = startNode - len(xOuter[e2 - 1]) * (elementsCountThroughWall + 1) + e3 * len( - xOuter[e2 - 1]) + e1 + 1 - elif e1 > int(elementsCountAround1 * 0.5): - bni12 = startNode + e3 * elementsCountAround1 + e1 % elementsCountAround1 - - if e1 > int(elementsCountAround1 * 0.5): - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + 1 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 2) % elementsCountAround2 + elementsCountAround2 * e3 - else: - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + (len(xOuter[e2 - 1]) if e1 == int( - elementsCountAround1 * 0.5) + 1 else elementsCountAround1), - bni12 + (len(xOuter[e2 - 1]) if e1 == int( - elementsCountAround1 * 0.5) else elementsCountAround1), - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - if e1 == int(elementsCountAround1 * 0.5): - 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, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e1 == int(elementsCountAround1 * 0.5) + 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, [ ])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - element = mesh.createElement(elementIdentifier, elementtemplate1) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Rows between downstream and penultimate ring - for e2 in range(int(elementsCountAroundOesophagus * 0.25) + 2, - int(elementsCountAroundOesophagus * 0.5)): - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range(elementsCountAround1 - 1): - bni11 = startNode + e3 * elementsCountAround1 + e1 + ( - 0 if e1 < int(elementsCountAround1 * 0.5) else 1) - bni12 = startNode + e3 * elementsCountAround1 + ( - e1 + (1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 + ( - 0 if e1 < int(elementsCountAround1 * 0.5) else 1) - bni22 = startNode + elementsAroundThroughWall + (e1 + (1 if e1 < int( - elementsCountAround1 * 0.5) else 2)) % elementsCountAround2 + elementsCountAround2 * e3 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - element = mesh.createElement(elementIdentifier, elementtemplateStandard) - result = element.setNodesByIdentifier(eftStandard, nodeIdentifiers) - elementIdentifier = elementIdentifier + 1 - - # Penultimate row connecting to annulus and beyond - for e2 in range(int(elementsCountAroundOesophagus * 0.5), elementsCountAlong): - startNode = bodyStartNode - for e in range(e2): - startNode += len(xOuter[e]) * (elementsCountThroughWall + 1) - - elementsCountAround1 = len(xOuter[e2]) - elementsAroundThroughWall = elementsCountAround1 * (elementsCountThroughWall + 1) - elementsCountAround2 = len(xOuter[e2 + 1]) - - for e3 in range(elementsCountThroughWall): - for e1 in range( - elementsCountAround1 - (1 if e2 == int(elementsCountAroundOesophagus * 0.5) else 0)): - scaleFactors = [] - eft1 = eftStandard - elementtemplate1 = elementtemplateStandard - if e2 == int(elementsCountAroundOesophagus * 0.5): - bni11 = startNode + e3 * elementsCountAround1 + e1 + ( - 0 if e1 < int(elementsCountAround1 * 0.5) else 1) - bni12 = startNode + e3 * elementsCountAround1 + (e1 + ( - 1 if e1 < int(elementsCountAround1 * 0.5) else 2)) % elementsCountAround1 - # Remap elements next to annulus - if e1 == int(elementsCountAround1 * 0.5) - 1: - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - 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 - else: - bni11 = startNode + e3 * elementsCountAround1 + e1 - bni12 = startNode + e3 * elementsCountAround1 + (e1 + 1) % elementsCountAround1 - bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 - bni22 = startNode + elementsAroundThroughWall + ( - e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 - nodeIdentifiers = [bni11, bni12, bni21, bni22, - bni11 + elementsCountAround1, bni12 + elementsCountAround1, - bni21 + elementsCountAround2, bni22 + elementsCountAround2] - - if e2 == int(elementsCountAroundOesophagus * 0.5) + 1: - if e1 == int(elementsCountAround1 * 0.5) - 1: - 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 == int(elementsCountAround1 * 0.5): - 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) - result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - result3 = element.setScaleFactors(eft1, scaleFactors) - elementIdentifier += 1 - - # Annulus - # Assemble endPoints for annulus - endPoints_x = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endPoints_d1 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endPoints_d2 = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endNode_Id = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endDerivativesMap = [[None] * elementsCountAroundOesophagus, [None] * elementsCountAroundOesophagus] - endProportions = [] - - thicknessIdx = [0, -1] - for nAround in range(elementsCountAroundOesophagus): - for n3 in range(len(thicknessIdx)): - if nAround == 0: - idx = idxMat[nAround][thicknessIdx[n3]][0] - elif nAround <= int(elementsCountAroundOesophagus * 0.25): - idx = idxMat[nAround][thicknessIdx[n3]][int((len(xOuter[nAround]) - 1) * 0.5)] - elif int(elementsCountAroundOesophagus * 0.25) < nAround < int(elementsCountAroundOesophagus * 0.5): - idx = idxMat[nAround + 1][thicknessIdx[n3]][int((len(xOuter[nAround + 1]) - 1) * 0.5)] - elif nAround == int(elementsCountAroundOesophagus * 0.5): - idx = idxMat[nAround + 1][thicknessIdx[n3]][int(len(xOuter[nAround + 1]) * 0.5)] - elif nAround > int(elementsCountAroundOesophagus * 0.5): - idx = endNode_Id[n3][int(elementsCountAroundOesophagus * 0.5) - (nAround - int(elementsCountAroundOesophagus * 0.5))] + 1 - - endPoints_x[n3][nAround] = xList[idx - bodyStartNode] - endPoints_d1[n3][nAround] = d1List[idx - bodyStartNode] - endPoints_d2[n3][nAround] = d2List[idx - bodyStartNode] - endNode_Id[n3][nAround] = idx - - if n3 == len(thicknessIdx) - 1: # outer layer - endPosition = trackSurfaceStomach.findNearestPosition(endPoints_x[n3][nAround]) - # xCheck = trackSurfaceStomach.evaluateCoordinates(endPosition) # KM - # print(xCheck, endPoints_x[n3][nAround]) # KM - endProportions.append(trackSurfaceStomach.getProportion(endPosition)) - - for nAround in range(elementsCountAroundOesophagus): - if nAround == 0: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) - elif nAround == int(elementsCountAroundOesophagus * 0.25): - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) - elif 0 < nAround < int(elementsCountAroundOesophagus * 0.5): - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == int(elementsCountAroundOesophagus * 0.5): - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - elif nAround == int(elementsCountAroundOesophagus * 0.75): - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - elif int(elementsCountAroundOesophagus * 0.5) < nAround < elementsCountAroundOesophagus: - endDerivativesMap[0][nAround] = endDerivativesMap[1][nAround] = ((0, -1, 0), (1, 0, 0), None) - - startProportions = [] - for n in range(elementsCountAroundOesophagus): - startProportions.append(trackSurfaceStomach.getProportion(o1_Positions[n])) - - 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 = elementsCountAnnulus, tracksurface=trackSurfaceStomach, - startProportions = startProportions, endProportions = endProportions, - rescaleStartDerivatives = True, rescaleEndDerivatives = True) - - if trackSurface: - for n2 in range(len(xTrackSurface)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, zero) - nodeIdentifier += 1 - - if showCentralPath: - for n2 in range(len(sx)): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, sx[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, sd2[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, sd1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, sd3[n2]) - nodeIdentifier += 1 - - fm.endChange() - - annotationGroup = [] - return annotationGroup - - @classmethod - def refineMesh(cls, meshrefinement, options): - """ - Refine source mesh into separate region, with change of basis. - :param meshrefinement: MeshRefinement, which knows source and target region. - :param options: Dict containing options. See getDefaultOptions(). - """ - refineElementsCountAround = options['Refine number of elements around'] - refineElementsCountAlong = options['Refine number of elements along'] - refineElementsCountThroughWall = options['Refine number of elements through wall'] - - meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, - refineElementsCountThroughWall) - return - -def findClosestPositionAndDerivativeOnTrackSurface(x, nx, trackSurface, nxProportion1, elementsCountAlongTrackSurface): - """ - Find the closest position and derivative around the tracksurface of a point sitting near the fundus of stomach. - Use a startPosition to improve the search for nearest position on the track surface as the fundus has a curved - and complex track surface. - - :param x: coordinates of point of interest - :param nx: coordinates of points along curve where point of interest lies. - :param trackSurface: track surface where point sits - :param nxProportion1: proportion around track surface of curve - :param elementsCountAlongTrackSurface: number of elements along track surface - :return: position and derivative of point around track surface - """ - closestIdxOnNx = interp.getNearestPointIndex(nx, x) - closestPositionToPoint = trackSurface.createPositionProportion(nxProportion1, closestIdxOnNx / elementsCountAlongTrackSurface) - xPosition = trackSurface.findNearestPosition(x, closestPositionToPoint) - d = trackSurface.evaluateCoordinates(xPosition, derivatives=True)[1] - - return xPosition, d - -def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, startProportion2, endProportion1, - endProportion2, elementsOut, startDerivative = None, endDerivative = None, - startDerivativeMagnitude = None, endDerivativeMagnitude = None, curveMode = 1): - """ - EDIT - Create smoothly spaced out hermite curve points between two points a and b on the surface, - each defined by their proportions over the surface in directions 1 and 2. - :param trackSurface: track surface - :param startProportion1, startProportion2: proportion of start point in direction around and along track surface - :param endProportion1, endProportion2: proportion of end point in direction around and along track surface - :param elementsOut: number of elements out - :param startDerivative, endDerivative: optional derivative vectors in 3-D world coordinates - to match at the start and end of the curves. If omitted, fits in with other derivative or is - in a straight line from a to b. - :param derivativeMagnitudeStart, derivativeMagnitudeEnd: optional magnitude of derivatives to match at the start and - end of the curves. - :return: coordinates and derivative of sampled points - """ - - mx, md2, md1, md3, mProportions = \ - trackSurface.createHermiteCurvePoints(startProportion1, startProportion2, endProportion1, endProportion2, - elementsOut, startDerivative, endDerivative, curveMode) - - xSampled, dSampled = trackSurface.resampleHermiteCurvePointsSmooth(mx, md2, md1, md3, mProportions, - startDerivativeMagnitude, - endDerivativeMagnitude)[0:2] - return xSampled, dSampled - -def findDerivativeBetweenPoints(v1, v2): - """ - - :param v1: - :param v2: - :return: - """ - 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): - """ - - :param nx: - :param nd: - :param radialVectors: - :return: - """ - curvature = [] - for n in range(len(nx)): - prevIdx = n - 1 if n > 0 else -1 - nextIdx = n + 1 if n < len(nx) - 1 else 0 - kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) - kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) - curvature.append(0.5 * (kappam + kappap)) - - return curvature - -def findCurvatureAlongLine(nx, nd, radialVectors): - """ - - :param nx: - :param nd: - :param radialVectors: - :return: - """ - curvature = [] - for n in range(len(nx)): - if n == 0: - curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) - elif n == len(nx) - 1: - curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) - else: - curvature.append(0.5 * ( - interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + - interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) - - return curvature - diff --git a/src/scaffoldmaker/scaffolds.py b/src/scaffoldmaker/scaffolds.py index 99542422..c421b029 100644 --- a/src/scaffoldmaker/scaffolds.py +++ b/src/scaffoldmaker/scaffolds.py @@ -38,7 +38,6 @@ from scaffoldmaker.meshtypes.meshtype_3d_sphereshellseptum1 import MeshType_3d_sphereshellseptum1 from scaffoldmaker.meshtypes.meshtype_3d_stellate1 import MeshType_3d_stellate1 from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1 -from scaffoldmaker.meshtypes.meshtype_3d_stomach2 import MeshType_3d_stomach2 from scaffoldmaker.meshtypes.meshtype_3d_stomachhuman1 import MeshType_3d_stomachhuman1 from scaffoldmaker.meshtypes.meshtype_3d_tube1 import MeshType_3d_tube1 from scaffoldmaker.meshtypes.meshtype_3d_tubeseptum1 import MeshType_3d_tubeseptum1 @@ -84,7 +83,6 @@ def __init__(self): MeshType_3d_sphereshellseptum1, MeshType_3d_stellate1, MeshType_3d_stomach1, - MeshType_3d_stomach2, MeshType_3d_stomachhuman1, MeshType_3d_tube1, MeshType_3d_tubeseptum1, diff --git a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py index 9b9f3cb7..dfced2db 100644 --- a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py +++ b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py @@ -522,4 +522,3 @@ def createEftWedgeCollapseXi2(self, collapseNodes): assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftWedgeCollapseXi2: Failed to validate eft' return eft - \ No newline at end of file diff --git a/tests/test_colon.py b/tests/test_colon.py index 6a6671d2..cafa05f7 100644 --- a/tests/test_colon.py +++ b/tests/test_colon.py @@ -112,14 +112,14 @@ def test_colon1(self): coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [ 108.03959866945482, -36.876103983560014, -25.93217903595996 ], 1.0E-6) - assertAlmostEqualList(self, maximums, [ 185.43446761757468, 48.07433517752282, 34.995316052158934 ], 1.0E-6) + assertAlmostEqualList(self, minimums, [ 108.02506479907721, -36.876103983560014, -25.89741158484918 ], 1.0E-6) + assertAlmostEqualList(self, maximums, [ 185.46457506076914, 48.1011574894518, 34.995316052158934 ], 1.0E-6) flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement() self.assertTrue(flatCoordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(flatCoordinates, nodes) assertAlmostEqualList(self, minimums, [ 0.0, 0.0, 0.0 ], 1.0E-6) - assertAlmostEqualList(self, maximums, [ 186.72988844629867, 75.79769125771575, 3.2000000000000006 ], 1.0E-6) + assertAlmostEqualList(self, maximums, [ 186.72988844629867, 77.41781871321301, 3.2000000000000006 ], 1.0E-6) textureCoordinates = fieldmodule.findFieldByName("texture coordinates").castFiniteElement() minimums, maximums = evaluateFieldNodesetRange(textureCoordinates, nodes) @@ -136,10 +136,10 @@ def test_colon1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 14623.340352853866, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 14612.416789097502, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 26869.74823158621, delta=1.0E-6) + self.assertAlmostEqual(volume, 26826.06954301569, delta=1.0E-6) def test_mousecolon1(self): """ diff --git a/tests/test_smallintestine.py b/tests/test_smallintestine.py index 7cdbc96c..dad7a4d1 100644 --- a/tests/test_smallintestine.py +++ b/tests/test_smallintestine.py @@ -20,7 +20,7 @@ def test_smallintestine1(self): Test creation of small intestine scaffold. """ parameterSetNames = MeshType_3d_smallintestine1.getParameterSetNames() - self.assertEqual(parameterSetNames, ["Default", "Mouse 1"]) + self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Mouse 1"]) centralPathDefaultScaffoldPackages = { 'Test line': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { diff --git a/tests/test_stomach.py b/tests/test_stomach.py new file mode 100644 index 00000000..66e7698a --- /dev/null +++ b/tests/test_stomach.py @@ -0,0 +1,84 @@ +import unittest +from opencmiss.utils.zinc.finiteelement import evaluateFieldNodesetRange +from opencmiss.utils.zinc.general import ChangeManager +from opencmiss.zinc.context import Context +from opencmiss.zinc.element import Element +from opencmiss.zinc.field import Field +from opencmiss.zinc.result import RESULT_OK +from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1 +from scaffoldmaker.utils.zinc_utils import createFaceMeshGroupExteriorOnFace +from testutils import assertAlmostEqualList + +class StomachScaffoldTestCase(unittest.TestCase): + + def test_stomach1(self): + """ + Test creation of stomach scaffold. + """ + parameterSetNames = MeshType_3d_stomach1.getParameterSetNames() + self.assertEqual(parameterSetNames, [ "Default", "Human 1", "Rat 1" ]) + options = MeshType_3d_stomach1.getDefaultOptions("Rat 1") + self.assertEqual(17, len(options)) + self.assertEqual(12, options.get("Number of elements around esophagus")) + self.assertEqual(14, options.get("Number of elements around duodenum")) + self.assertEqual(2, options.get("Number of elements between annulus and duodenum")) + self.assertEqual(1, options.get("Number of elements through wall")) + self.assertEqual(1, options.get("Number of radial elements in annulus")) + self.assertEqual(0.5, options.get("Wall thickness")) + self.assertEqual(True, options.get("Limiting ridge")) + ostiumOptions = options['Gastro-esophagal junction'] + ostiumSettings = ostiumOptions.getScaffoldSettings() + self.assertEqual(1, ostiumSettings.get("Number of vessels")) + self.assertEqual(8, ostiumSettings.get("Number of elements around ostium")) + self.assertEqual(1, ostiumSettings.get("Number of elements through wall")) + self.assertEqual(4.0, ostiumSettings.get("Ostium diameter")) + self.assertEqual(3.5, ostiumSettings.get("Ostium length")) + self.assertEqual(0.5, ostiumSettings.get("Ostium wall thickness")) + self.assertEqual(1.25, ostiumSettings.get("Vessel inner diameter")) + self.assertEqual(0.5, ostiumSettings.get("Vessel wall thickness")) + self.assertEqual(0.0, ostiumSettings.get("Vessel angle 1 degrees")) + self.assertEqual(0.55, options.get("Gastro-esophagal junction position along factor")) + self.assertEqual(0.2, options.get("Annulus derivative factor")) + + context = Context("Test") + region = context.getDefaultRegion() + self.assertTrue(region.isValid()) + annotationGroups = MeshType_3d_stomach1.generateBaseMesh(region, options) + self.assertEqual(8, len(annotationGroups)) + + fieldmodule = region.getFieldmodule() + self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) + mesh3d = fieldmodule.findMeshByDimension(3) + self.assertEqual(158, mesh3d.getSize()) + mesh2d = fieldmodule.findMeshByDimension(2) + self.assertEqual(643, mesh2d.getSize()) + mesh1d = fieldmodule.findMeshByDimension(1) + self.assertEqual(823, mesh1d.getSize()) + nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + self.assertEqual(338, 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, [-17.977095466754566, -15.437578891036395, -8.706694306455596], 1.0E-6) + assertAlmostEqualList(self, maximums, [17.943222678234513, 15.166959982968175, 8.725549026319936], 1.0E-6) + + with ChangeManager(fieldmodule): + one = fieldmodule.createFieldConstant(1.0) + faceMeshGroup = createFaceMeshGroupExteriorOnFace(fieldmodule, Element.FACE_TYPE_XI3_1) + surfaceAreaField = fieldmodule.createFieldMeshIntegral(one, coordinates, faceMeshGroup) + surfaceAreaField.setNumbersOfPoints(4) + volumeField = fieldmodule.createFieldMeshIntegral(one, coordinates, mesh3d) + volumeField.setNumbersOfPoints(3) + fieldcache = fieldmodule.createFieldcache() + result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(surfaceArea, 2436.587011786455, delta=1.0E-6) + result, volume = volumeField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(volume, 1168.9736652790561, delta=1.0E-6) + +if __name__ == "__main__": + unittest.main() From 3a79f6159d53760867c579a35ec38a53e5fee428 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 16 Apr 2021 16:39:01 +1200 Subject: [PATCH 11/38] Add markers --- .../meshtypes/meshtype_3d_stomach1.py | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index b319c098..12cce726 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -9,7 +9,8 @@ import copy from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups from scaffoldmaker.annotation.stomach_terms import get_stomach_term -from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates +from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates, findOrCreateFieldGroup, \ + findOrCreateFieldStoredString, findOrCreateFieldStoredMeshLocation, findOrCreateFieldNodeGroup from opencmiss.zinc.element import Element from opencmiss.zinc.field import Field from opencmiss.zinc.node import Node @@ -384,9 +385,9 @@ def generateBaseMesh(cls, region, options): useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not (options['Use linear through wall']) - GOJPositionAlongFactor = options['Gastro-esophagal junction position along factor'] - GOJOptions = options['Gastro-esophagal junction'] - GOJSettings = GOJOptions.getScaffoldSettings() + GEJPositionAlongFactor = options['Gastro-esophagal junction position along factor'] + GEJOptions = options['Gastro-esophagal junction'] + GEJSettings = GEJOptions.getScaffoldSettings() limitingRidge = options['Limiting ridge'] elementsCountAnnulus = options['Number of radial elements in annulus'] annulusDerivativeFactor = options['Annulus derivative factor'] @@ -418,6 +419,7 @@ def generateBaseMesh(cls, region, options): nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) cache = fm.createFieldcache() + mesh = fm.findMeshByDimension(3) nodeIdentifier = 1 elementIdentifier = 1 @@ -477,6 +479,17 @@ def generateBaseMesh(cls, region, options): [stomachGroup, pylorusGroup], [stomachGroup, duodenumGroup]] + # annotation fiducial points + markerGroup = findOrCreateFieldGroup(fm, "marker") + markerName = findOrCreateFieldStoredString(fm, name="marker_name") + markerLocation = findOrCreateFieldStoredMeshLocation(fm, mesh, name="marker_location") + + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() + markerTemplateInternal = nodes.createNodetemplate() + markerTemplateInternal.defineField(markerName) + markerTemplateInternal.defineField(markerLocation) + # Fundus diameter fundusRadius = vector.magnitude(sd2[0]) lengthElementAlongTrackSurface = stomachCentralPathLength / elementsCountAlongTrackSurface @@ -590,12 +603,11 @@ def generateBaseMesh(cls, region, options): xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) # Set up gastro-esophagal junction - GOJSettings['Number of elements around ostium'] = elementsCountAroundEso - GOJPosition = trackSurfaceStomach.createPositionProportion(0.5, GOJPositionAlongFactor) - xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GOJPosition, derivatives=True) + GEJSettings['Number of elements around ostium'] = elementsCountAroundEso + GEJPosition = trackSurfaceStomach.createPositionProportion(0.5, GEJPositionAlongFactor) + xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GEJPosition, derivatives=True) axis1 = d1Centre - mesh = fm.findMeshByDimension(3) esophagusGroup = AnnotationGroup(region, get_stomach_term("esophagus")) esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) esophagogastricJunctionGroup = AnnotationGroup(region, get_stomach_term("esophagogastric junction")) @@ -603,11 +615,12 @@ def generateBaseMesh(cls, region, options): allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup] nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GOJSettings, trackSurfaceStomach, GOJPosition, axis1, + generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, nodeIdentifier, elementIdentifier, vesselMeshGroups=[[esophagusMeshGroup]], ostiumMeshGroups=[esophagogastricJunctionMeshGroup]) stomachStartNode = nextNodeIdentifier + stomachStartElement = nextElementIdentifier nodeIdentifier = nextNodeIdentifier elementIdentifier = nextElementIdentifier @@ -1991,6 +2004,8 @@ def generateBaseMesh(cls, region, options): result2 = element.setNodesByIdentifier(eft1, nodeIdentifiers) if scaleFactors: result3 = element.setScaleFactors(eft1, scaleFactors) + if e1 == 0: + fundusBodyJunctionElementIdentifier = elementIdentifier elementIdentifier += 1 annotationGroups = annotationGroupsAlong[e2] if annotationGroups: @@ -2202,6 +2217,27 @@ def generateBaseMesh(cls, region, options): tracksurface=trackSurfaceStomach, startProportions = startProportions, endProportions = endProportions, rescaleStartDerivatives = True, rescaleEndDerivatives = True) + nodeIdentifier = nextNodeIdentifier + + # annotation fiducial points + GEJLCElement = mesh.findElementByIdentifier(stomachStartElement - elementsAroundHalfEso) + GEJLCXi = [0.0, 1.0, 1.0] + cache.setMeshLocation(GEJLCElement, GEJLCXi) + markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) + nodeIdentifier += 1 + cache.setNode(markerPoint) + markerName.assignString(cache, "gastro-esophagal junction on lesser curvature") + markerLocation.assignMeshLocation(cache, GEJLCElement, GEJLCXi) + + fundusBodyJunctionElement = mesh.findElementByIdentifier(fundusBodyJunctionElementIdentifier) + fundusBodyJunctionXi = [0.0, 0.0 if limitingRidge else 1.0, 1.0] + cache.setMeshLocation(fundusBodyJunctionElement, fundusBodyJunctionXi) + markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) + nodeIdentifier += 1 + cache.setNode(markerPoint) + markerName.assignString(cache, "limiting ridge on greater curvature" if limitingRidge else "junction between fundus and body on greater curvature") + markerLocation.assignMeshLocation(cache, fundusBodyJunctionElement, fundusBodyJunctionXi) + fm.endChange() return allAnnotationGroups From e2103d8672151afe33754d548874c27d1d14d49c Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Wed, 21 Apr 2021 16:03:28 +1200 Subject: [PATCH 12/38] Calculate position of 6 point junction using triple points function --- .../meshtypes/meshtype_3d_stomach1.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 12cce726..cd224afe 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -249,7 +249,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Gastro-esophagal junction position along factor': 0.35, 'Annulus derivative factor': 1.0, 'Use cross derivatives': False, - 'Use linear through wall' : False, # need to deal with wedge not available in bicubichermite + 'Use linear through wall' : False, 'Refine': False, 'Refine number of elements around': 1, 'Refine number of elements along': 1, @@ -894,10 +894,25 @@ def generateBaseMesh(cls, region, options): endPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[-1][n + (0 if n < elementsAroundHalfDuod else 1)]) endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) xSampled = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, - startProportion2, endProportion1, endProportion2, - 2)[0] + startProportion2, endProportion1, endProportion2, 2)[0] xAve.append(xSampled[1]) + # Find 6 pt junction + p1x_6pt = o1_x[1][elementsAroundHalfEso] + d = o1_d2[1][elementsAroundHalfEso] + rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][elementsAroundHalfEso], math.pi) + p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] + p1d_6pt = [annulusDerivativeFactor * c for c in p1d] + + p2x_6pt = xAve[int(len(xAve)*0.5) + 1] + p2d_6pt = findDerivativeBetweenPoints(p2x_6pt, xAve[int(len(xAve) * 0.5) + 2]) + + p3x_6pt = xAve[int(len(xAve) * 0.5) - 1] + p3d_6pt = findDerivativeBetweenPoints(p3x_6pt, xAve[int(len(xAve) * 0.5) - 2]) + + x6pt = get_bifurcation_triple_point(p1x_6pt, p1d_6pt, p2x_6pt, p2d_6pt, p3x_6pt, p3d_6pt)[0] + xAve[int(len(xAve) * 0.5)] = x6pt + for n in range(len(xAve)): v1 = xAve[n] v2 = xAve[(n + 1) % len(xAve)] From 59e3875f73dfb63216acefd3836143edf4d6ec03 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Wed, 21 Apr 2021 16:08:51 +1200 Subject: [PATCH 13/38] Add annotation groups for limiting ridge --- src/scaffoldmaker/annotation/stomach_terms.py | 3 ++ .../meshtypes/meshtype_3d_stomach1.py | 51 ++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/scaffoldmaker/annotation/stomach_terms.py b/src/scaffoldmaker/annotation/stomach_terms.py index 73bab181..972fa443 100644 --- a/src/scaffoldmaker/annotation/stomach_terms.py +++ b/src/scaffoldmaker/annotation/stomach_terms.py @@ -9,6 +9,9 @@ ( "duodenum", "UBERON:0002114", " FMA:7206", "ILX:0726125"), ( "esophagus", "UBERON:0001043", "FMA: 7131", "ILX:0735017"), ( "esophagogastric junction", "UBERON:0007650", "FMA: 9434", "ILX:0733910"), + ( "forestomach-glandular stomach junction", "UBERON:0012270", "ILX:0729974"), + ( "forestomach-glandular stomach junction on inner wall", None), + ( "forestomach-glandular stomach junction on outer wall", None), ( "fundus of stomach", "UBERON:0001160", " FMA:14559", "ILX:0724443"), ( "pyloric antrum", "UBERON:0001165", " FMA:14579", "ILX:0728672"), ( "pylorus", "UBERON:0001166", " FMA:14581", "ILX:0734150"), diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index cd224afe..a733b5f1 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -7,7 +7,8 @@ from __future__ import division import math import copy -from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups, \ + getAnnotationGroupForTerm, findOrCreateAnnotationGroupForTerm from scaffoldmaker.annotation.stomach_terms import get_stomach_term from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates, findOrCreateFieldGroup, \ findOrCreateFieldStoredString, findOrCreateFieldStoredMeshLocation, findOrCreateFieldNodeGroup @@ -2272,6 +2273,54 @@ 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'] + + if limitingRidge: + fm = region.getFieldmodule() + fundusGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("fundus of stomach")) + bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("body of stomach")) + cardiaGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("cardia of stomach")) + antrumGroup = getAnnotationGroupForTerm(annotationGroups, get_stomach_term("pyloric antrum")) + + limitingRidgeGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term("forestomach-glandular stomach junction")) + innerLimitingRidgeGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term("forestomach-glandular stomach junction on inner wall")) + outerLimitingRidgeGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_stomach_term("forestomach-glandular stomach junction on outer wall")) + + mesh2d = fm.findMeshByDimension(2) + is_fundus = fundusGroup.getGroup() + is_body = bodyGroup.getGroup() + is_cardia = cardiaGroup.getGroup() + is_antrum = antrumGroup.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) + limitingRidgeGroup.getMeshGroup(mesh2d).addElementsConditional(is_limitingRidge) + + 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_limitingRidgeInner = fm.createFieldAnd(is_limitingRidge, is_exterior_face_inner) + innerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeInner) + + is_limitingRidgeOuter = fm.createFieldAnd(is_limitingRidge, is_exterior_face_outer) + outerLimitingRidgeGroup.getMeshGroup(mesh1d).addElementsConditional(is_limitingRidgeOuter) + def findClosestPositionAndDerivativeOnTrackSurface(x, nx, trackSurface, nxProportion1, elementsCountAlongTrackSurface): """ Find the closest position and derivative around the tracksurface of a point sitting near the fundus of stomach. From 7081afb491c37b1e3e2da89d5c16d14338f98ece Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Wed, 21 Apr 2021 16:11:56 +1200 Subject: [PATCH 14/38] Add third marker on duodenum end on greater curvature --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index a733b5f1..7b0a46e9 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -2225,6 +2225,8 @@ def generateBaseMesh(cls, region, options): stomachMeshGroup = stomachGroup.getMeshGroup(mesh) allAnnotationGroups.append(cardiaGroup) + lastDuodenumElementIdentifier = elementIdentifier + nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( nodes, mesh, nodeIdentifier, elementIdentifier, o1_x, o1_d1, o1_d2, None, o1_NodeId, None, @@ -2235,7 +2237,7 @@ def generateBaseMesh(cls, region, options): nodeIdentifier = nextNodeIdentifier - # annotation fiducial points + # annotation fiducial points for embedding in whole body GEJLCElement = mesh.findElementByIdentifier(stomachStartElement - elementsAroundHalfEso) GEJLCXi = [0.0, 1.0, 1.0] cache.setMeshLocation(GEJLCElement, GEJLCXi) @@ -2254,6 +2256,15 @@ def generateBaseMesh(cls, region, options): markerName.assignString(cache, "limiting ridge on greater curvature" if limitingRidge else "junction between fundus and body on greater curvature") markerLocation.assignMeshLocation(cache, fundusBodyJunctionElement, fundusBodyJunctionXi) + duodenumGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - elementsCountAroundDuod) + duodenumGCXi = [0.0, 1.0, 1.0] + cache.setMeshLocation(duodenumGCElement, duodenumGCXi) + markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) + nodeIdentifier += 1 + cache.setNode(markerPoint) + markerName.assignString(cache, "duodenum on greater curvature") + markerLocation.assignMeshLocation(cache, duodenumGCElement, duodenumGCXi) + fm.endChange() return allAnnotationGroups From 7ecffce5c14824fdee022a534cc418a8247ca1d8 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Wed, 21 Apr 2021 16:18:53 +1200 Subject: [PATCH 15/38] Update unit tests --- tests/test_stomach.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_stomach.py b/tests/test_stomach.py index 66e7698a..954f0c57 100644 --- a/tests/test_stomach.py +++ b/tests/test_stomach.py @@ -55,7 +55,7 @@ def test_stomach1(self): mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(823, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(338, nodes.getSize()) + self.assertEqual(341, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) @@ -63,7 +63,7 @@ def test_stomach1(self): self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) assertAlmostEqualList(self, minimums, [-17.977095466754566, -15.437578891036395, -8.706694306455596], 1.0E-6) - assertAlmostEqualList(self, maximums, [17.943222678234513, 15.166959982968175, 8.725549026319936], 1.0E-6) + assertAlmostEqualList(self, maximums, [17.943222678234513, 15.191836205539767, 8.725549026319936], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -75,10 +75,10 @@ def test_stomach1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 2436.587011786455, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 2436.4955183926895, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 1168.9736652790561, delta=1.0E-6) + self.assertAlmostEqual(volume, 1168.9418891341106, delta=1.0E-6) if __name__ == "__main__": unittest.main() From cd703d5a1b6ad9d5df0d97a1067cc24a685bcbdd Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Wed, 21 Apr 2021 16:55:13 +1200 Subject: [PATCH 16/38] Remove redundant lines and edit comments to improve clarity --- .../meshtypes/meshtype_3d_stomach1.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 7b0a46e9..a04ccd87 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -37,8 +37,8 @@ class MeshType_3d_stomach1(Scaffold_base): Generates a 3-D stomach mesh with variable numbers of elements around the esophagus and duodenum, along the central line, and through wall. The stomach is created using a central path as the longitudinal axis of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 - are the radii of the stomach in the respective direction. D2 and D3 on the first node of the central path provide - the radii of the fundus dome. + are the radii of the stomach in the respective direction. D2 on the first node of the central path provide + the radius of the fundus dome. """ centralPathDefaultScaffoldPackages = { 'Human 1': ScaffoldPackage(MeshType_1d_path1, { @@ -461,9 +461,7 @@ def generateBaseMesh(cls, region, options): stomachCentralPathLength = sum(arcLengthOfGroupsAlong[1:]) fundusEndPositionAlongFactor = arcLengthOfGroupsAlong[1]/stomachCentralPathLength arcLengthRatioForGroupsFromFundusEnd = [] - checkLength = 0.0 for i in range(2, len(stomachTermsAlong)): - checkLength += arcLengthOfGroupsAlong[i] arcLengthRatio = (arcLengthOfGroupsAlong[i])/(stomachCentralPathLength - arcLengthOfGroupsAlong[1]) arcLengthRatioForGroupsFromFundusEnd.append(arcLengthRatio) @@ -538,7 +536,7 @@ def generateBaseMesh(cls, region, options): d2Around.append(d2) d2Ellipses.append(d2Around) - # Merge fundus and body + # Merge fundus apex and body xAll = [[sx[0]] * elementsCountAroundDuod] + xEllipses d2All = [d2Apex] + d2Ellipses @@ -2381,9 +2379,9 @@ def getSmoothedSampledPointsOnTrackSurface(trackSurface, startProportion1, start def smoothD1Around(xAround, d1Around): """ - Rearrange points around so that points starts from left side of the annulus to the greater curvature + 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 derivative smoothing. - Smoothed derivatives are re-arranged such that it starts from the greater curvature and goes to the right + The smoothed derivatives 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. @@ -2400,9 +2398,9 @@ def smoothD1Around(xAround, d1Around): def findD1CurvatureAround(xAround, d1Around, normsAround): """ - Rearrange points around so that points starts from left side of the annulus to the greater curvature + 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. - Curvatures are re-arranged such that it starts from the greater curvature and goes to the right + 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. From 70bc33ca21988211bcb1863522cbc7f2b8187de7 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Thu, 22 Apr 2021 15:50:22 +1200 Subject: [PATCH 17/38] Add scale factor for wedges --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index a04ccd87..3919f6b3 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1892,6 +1892,7 @@ def generateBaseMesh(cls, region, options): 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_DS2, [])]) elif e1 == 1: # Bottom right wedge + scaleFactors = [-1.0] nodeIdentifiers = [bni11, bni21, bni22, bni11 + elementsCountAround1, bni21 + elementsCountAround2, @@ -1915,6 +1916,7 @@ def generateBaseMesh(cls, region, options): bni21 = startNode + elementsAroundThroughWall + e1 + elementsCountAround2 * e3 bni22 = startNode + elementsAroundThroughWall + (e1 + 1) % elementsCountAround2 + elementsCountAround2 * e3 if e1 == elementsCountAround1: # Bottom left wedge + scaleFactors = [-1.0] nodeIdentifiers = [bni12, bni21, bni22, bni12 + elementsCountAround1, bni21 + elementsCountAround2, @@ -1994,6 +1996,7 @@ def generateBaseMesh(cls, region, options): nodeIdentifiers = [bni11, bni12, bni21, bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2] + scaleFactors = [-1.0] eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX From 8c4aa1ed50bc71cca124d391ae0efec6eb9e49a8 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 23 Apr 2021 12:03:41 +1200 Subject: [PATCH 18/38] Annotate part of esophagus as stomach --- 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 3919f6b3..0265c4ad 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -611,12 +611,13 @@ def generateBaseMesh(cls, region, options): esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) esophagogastricJunctionGroup = AnnotationGroup(region, get_stomach_term("esophagogastric junction")) esophagogastricJunctionMeshGroup = esophagogastricJunctionGroup.getMeshGroup(mesh) + stomachMeshGroup = stomachGroup.getMeshGroup(mesh) allAnnotationGroups += [esophagusGroup, esophagogastricJunctionGroup] nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, nodeIdentifier, elementIdentifier, vesselMeshGroups=[[esophagusMeshGroup]], - ostiumMeshGroups=[esophagogastricJunctionMeshGroup]) + ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup]) stomachStartNode = nextNodeIdentifier stomachStartElement = nextElementIdentifier @@ -2223,7 +2224,6 @@ def generateBaseMesh(cls, region, options): cardiaGroup = AnnotationGroup(region, get_stomach_term("cardia of stomach")) cardiaMeshGroup = cardiaGroup.getMeshGroup(mesh) - stomachMeshGroup = stomachGroup.getMeshGroup(mesh) allAnnotationGroups.append(cardiaGroup) lastDuodenumElementIdentifier = elementIdentifier From a850565cb29cb5d71f163781b94e9bde02ce1364 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Fri, 23 Apr 2021 14:38:54 +1200 Subject: [PATCH 19/38] Update central path for rat stomach to show duodenum group --- .../meshtypes/meshtype_3d_stomach1.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 0265c4ad..cc1ee5c1 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -107,14 +107,14 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [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], [ - [ [ 12.4, 11.9, 0.0 ], [ -0.1, -14.5, 0.0 ], [ 8.7, -1.4, 0.0 ], [ -0.7, -3.5, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.5 ] ], - [ [ 9.5, -0.2, 0.0 ], [ -5.7, -9.0, 0.0 ], [ 6.6, -5.1, 0.0 ], [ -3.5, -3.9, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], - [ [ 2.8, -5.5, 0.0 ], [ -6.5, -2.5, 0.0 ], [ 2.1, -9.1, 0.0 ], [ -4.0, -1.5, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, 0.0 ] ], - [ [ -2.4, -5.9, 0.0 ], [ -5.5, 0.8, 0.0 ], [ -1.6, -9.2, 0.0 ], [ -4.0, 0.5, 0.0 ], [ 0.0, 0.0, 8.8 ], [ 0.0, 0.0, -0.4 ] ], - [ [ -7.8, -3.9, 0.0 ], [ -5.0, 3.9, 0.0 ], [ -6.0, -8.0, 0.0 ], [ -2.5, 2.7, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.2 ] ], - [ [ -11.7, 1.7, 0.0 ], [ -1.7, 7.2, 0.0 ], [ -6.4, -3.5, 0.0 ], [ 1.4, 4.0, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], - [ [ -10.7, 9.4, 0.0 ], [ 0.3, 5.3, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 0.5, 0.7, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -0.3 ] ], - [ [ -10.7, 12.2, 0.0 ], [ -0.3, 2.7, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -0.3, -0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 0.5 ] ], + [ [ 12.4, 11.9, 0.0 ], [ -0.1, -14.5, 0.0 ], [ 8.7, -1.4, 0.0 ], [ -0.7, -3.5, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.5 ] ], + [ [ 9.5, -0.2, 0.0 ], [ -5.7, -9.0, 0.0 ], [ 6.6, -5.1, 0.0 ], [ -3.5, -3.9, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], + [ [ 2.8, -5.5, 0.0 ], [ -6.5, -2.5, 0.0 ], [ 2.1, -9.1, 0.0 ], [ -4.0, -1.5, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, 0.0 ] ], + [ [ -2.6, -6.0, 0.0 ], [ -5.5, 0.8, 0.0 ], [ -1.6, -9.2, 0.0 ], [ -4.0, 0.5, 0.0 ], [ 0.0, 0.0, 8.8 ], [ 0.0, 0.0, -0.4 ] ], + [ [ -8.2, -4.1, 0.0 ], [ -5.0, 3.9, 0.0 ], [ -6.0, -8.0, 0.0 ], [ -2.5, 2.7, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.2 ] ], + [ [ -12.3, 1.5, 0.0 ], [ -1.7, 7.2, 0.0 ], [ -6.4, -3.5, 0.0 ], [ 1.4, 4.0, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], + [ [ -10.8, 8.5, 0.0 ], [ 0.3, 5.3, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 0.5, 0.7, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -0.3 ] ], + [ [ -10.7, 12.2, 0.0 ], [ -0.3, 2.7, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -0.3, -0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 0.5 ] ], [ [ -11.3, 14.8, 0.0 ], [ -0.9, 2.5, 0.0 ], [ -3.5, -0.3, 0.0 ], [ 0.3, 0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, -0.5 ] ] ] ), 'userAnnotationGroups': [ From 5ee25ac59fa978425d723e21dcd2ae390b68ef26 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 09:47:22 +1200 Subject: [PATCH 20/38] Make None into string for colon annotation terms without termIDs --- src/scaffoldmaker/annotation/colon_terms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/annotation/colon_terms.py b/src/scaffoldmaker/annotation/colon_terms.py index 8250e7de..0c4fc010 100644 --- a/src/scaffoldmaker/annotation/colon_terms.py +++ b/src/scaffoldmaker/annotation/colon_terms.py @@ -10,8 +10,8 @@ ( "colon", "UBERON:0001155", "FMA:14543", "ILX:0736005"), ( "colonic mucosa", "UBERON:0000317", "FMA:14984", "ILX:0731046"), ( "distal colon", "UBERON:0008971", "ILX:0727523"), - ( "mesenteric zone", None), - ( "non-mesenteric zone", None), + ( "mesenteric zone", "None"), + ( "non-mesenteric zone", "None"), ( "proximal colon", "UBERON:0008972", "ILX:0733240"), ( "serosa of colon", "UBERON:0003335", "FMA:14990", "ILX:0736932"), ( "spiral colon", "UBERON:0010239", "ILX:0735018"), From e9364b9200c1740f7e4a559eb80fc1a09b8d36ee Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 09:54:01 +1200 Subject: [PATCH 21/38] Update description of functions for creating wedges with collapse nodes --- src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py | 4 ++-- src/scaffoldmaker/utils/eftfactory_tricubichermite.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py index dfced2db..36c4391f 100644 --- a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py +++ b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py @@ -251,7 +251,7 @@ def createEftWedgeXi1Zero(self): def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): ''' - Create a bicubic hermite linear element field for a wedge element, where xi1 collapsed on xi3 = 0 or xi3 = 1. + Create a bicubic hermite linear element field for a wedge element collapsed in xi1. :return: Element field template ''' eft = self.createEftBasic() @@ -498,7 +498,7 @@ def createEftPyramidBottomSimple(self, nodeScaleFactorOffset0, nodeScaleFactorOf def createEftWedgeCollapseXi2(self, collapseNodes): ''' - Create a bicubic hermite linear element field for a wedge element, where xi2 collapsed on xi1 = 1. + Create a bicubic hermite linear element field for a wedge element collapsed in xi2. :return: Element field template ''' eft = self.createEftBasic() diff --git a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py index b55ea3bb..73dc1995 100644 --- a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py +++ b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py @@ -821,7 +821,7 @@ def createEftWedgeXi1Zero(self): def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): ''' - Create a tricubic hermite element field for a wedge element, where xi1 collapsed on xi3 = 0 or xi3 = 1. + Create a tricubic hermite element field for a wedge element collapsed in xi1. :return: Element field template ''' eft = self.createEftBasic() @@ -897,7 +897,7 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): def createEftWedgeCollapseXi2Quadrant(self, collapseNodes): ''' - Create a tricubic hermite element field for a wedge element, where xi2 collapsed on xi3 = 0 or Xi3 = 1. + Create a tricubic hermite element field for a wedge element collapsed in xi2. :return: Element field template ''' eft = self.createEftBasic() @@ -1666,7 +1666,7 @@ def replaceTwoElementWithInlet6(self, origElement1, origElement2, startElementId def createEftWedgeCollapseXi2(self, collapseNodes): ''' - Create a tricubic hermite element field for a wedge element, where xi2 collapsed on xi1 = 1. + Create a tricubic hermite element field for a wedge element collapsed in xi2. :return: Element field template ''' eft = self.createEftBasic() From d776722582e93dda08cba812456f05cbfed66e90 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 10:39:57 +1200 Subject: [PATCH 22/38] Merge createEftWedgeCollapseXi2 with createEFTWedgeCollapseXi2Quadrant --- .../meshtypes/meshtype_3d_stomach1.py | 4 +- .../utils/eftfactory_bicubichermitelinear.py | 102 +++++++++++------- .../utils/eftfactory_tricubichermite.py | 54 ++++------ 3 files changed, 86 insertions(+), 74 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index cc1ee5c1..9fae14b6 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1998,7 +1998,7 @@ def generateBaseMesh(cls, region, options): bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2] scaleFactors = [-1.0] - eft1 = eftfactory.createEftWedgeCollapseXi2([4, 8]) + eft1 = eftfactory.createEftWedgeCollapseXi2Quadrant([4, 8]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2007,7 +2007,7 @@ def generateBaseMesh(cls, region, options): nodeIdentifiers = [bni11, bni12, bni21, bni11 + elementsCountAround1, bni12 + elementsCountAround1, bni21 + elementsCountAround2] - eft1 = eftfactory.createEftWedgeCollapseXi2([3, 7]) + eft1 = eftfactory.createEftWedgeCollapseXi2Quadrant([3, 7]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX diff --git a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py index 36c4391f..485fcd4d 100644 --- a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py +++ b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py @@ -258,28 +258,19 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): setEftScaleFactorIds(eft, [1], []) valid = True - if collapseNodes in [[1, 3], [2, 4]]: + if collapseNodes in [[1, 3], [2, 4]]: # xi3 = 0 nodes = [1, 2, 3, 4] - if collapseNodes == [1, 3]: - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) - elif collapseNodes == [2, 4]: - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) - else: - valid = False + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) ln_map = [1, 1, 2, 2, 3, 4, 5, 6] - elif collapseNodes in [[5, 7], [6, 8]]: + elif collapseNodes in [[5, 7], [6, 8]]: # xi3 = 1 nodes = [5, 6, 7, 8] - if collapseNodes == [5, 7]: - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) - elif collapseNodes == [6, 8]: - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) - else: - valid = False + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) ln_map = [1, 2, 3, 4, 5, 5, 6, 6] elif collapseNodes in [[1, 5], [2, 6]]: nodes = [1, 2, 5, 6] # remap parameters on xi2 = 0 before collapsing nodes if collapseNodes == [1, 5]: + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) elif collapseNodes == [2, 6]: @@ -295,6 +286,7 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elif collapseNodes == [4, 8]: + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, []) else: @@ -313,6 +305,61 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftWedgeCollapseXi1Quadrant: Failed to validate eft' return eft + def createEftWedgeCollapseXi2Quadrant(self, collapseNodes): + ''' + Create a bicubic hermite linear element field for a wedge element collapsed in xi2. + :return: Element field template + ''' + eft = self.createEftBasic() + + valid = True + if collapseNodes in [[1, 2], [3, 4]]: # xi3 = 0 + nodes = [1, 2, 3, 4] + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + ln_map = [1, 2, 1, 2, 3, 4, 5, 6] + elif collapseNodes in [[5, 6], [7, 8]]: # xi3 = 1 + nodes = [5, 6, 7, 8] + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + ln_map = [1, 2, 3, 4, 5, 6, 5, 6] + + elif collapseNodes in [[3, 7]]: + nodes = [1, 3, 5, 7] + # remap parameters on xi1 = 0 before collapsing nodes + if collapseNodes == [3, 7]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + else: + valid = False + ln_map = [1, 2, 1, 3, 4, 5, 4, 6] + + elif collapseNodes in [[2, 6], [4, 8]]: + nodes = [2, 4, 6, 8] + # remap parameters on xi1 = 1 before collapsing nodes + if collapseNodes == [2, 6]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + elif collapseNodes == [4, 8]: + setEftScaleFactorIds(eft, [1], []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + else: + valid = False + ln_map = [1, 2, 3, 2, 4, 5, 6, 5] + + else: + valid = False + + if not valid: + assert False, "createEftWedgeCollapseXi2Quadrant. Not implemented for collapse nodes " + str(collapseNodes) + + # zero cross derivative parameters + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) + + remapEftLocalNodes(eft, 6, ln_map) + if not eft.validate(): + print('eftfactory_bicubichermitelinear.createEftWedgeCollapseXi2Quadrant: Failed to validate eft for collapseNodes', collapseNodes) + return eft + def createEftWedgeXi1ZeroOpenTube(self): ''' Create a basic bicubic hermite linear element template for elements @@ -495,30 +542,3 @@ def createEftPyramidBottomSimple(self, nodeScaleFactorOffset0, nodeScaleFactorOf assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftPyramidBottomSimple: Failed to validate eft' return eft - - def createEftWedgeCollapseXi2(self, collapseNodes): - ''' - Create a bicubic hermite linear element field for a wedge element collapsed in xi2. - :return: Element field template - ''' - eft = self.createEftBasic() - - if collapseNodes in [[4, 8]]: - setEftScaleFactorIds(eft, [1], []) - nodes = [2, 4, 6, 8] - remapEftNodeValueLabel(eft, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) - ln_map = [1, 2, 3, 2, 4, 5, 6, 5] - - elif collapseNodes in [[3, 7]]: - nodes = [1, 3, 5, 7] - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) - remapEftNodeValueLabel(eft, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) - ln_map = [1, 2, 1, 3, 4, 5, 4, 6] - - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) - - remapEftLocalNodes(eft, 6, ln_map) - assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftWedgeCollapseXi2: Failed to validate eft' - - return eft diff --git a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py index 73dc1995..b996a7d8 100644 --- a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py +++ b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py @@ -929,11 +929,31 @@ def createEftWedgeCollapseXi2Quadrant(self, collapseNodes): else: valid = False ln_map = [1, 2, 3, 4, 5, 6, 5, 6] - elif collapseNodes in [[4, 8]]: + + elif collapseNodes in [[3, 7]]: + nodes = [1, 3, 5, 7] + # remap parameters on xi1 = 0 before collapsing nodes + if collapseNodes == [3, 7]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + else: + valid = False + ln_map = [1, 2, 1, 3, 4, 5, 4, 6] + + elif collapseNodes in [[2, 6], [4, 8]]: nodes = [2, 4, 6, 8] - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) - remapEftNodeValueLabel(eft, [2, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + # remap parameters on xi1 = 1 before collapsing nodes + if collapseNodes == [2, 6]: + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + elif collapseNodes == [4, 8]: + setEftScaleFactorIds(eft, [1], []) + remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) + else: + valid = False ln_map = [1, 2, 3, 2, 4, 5, 6, 5] + else: valid = False @@ -1663,31 +1683,3 @@ def replaceTwoElementWithInlet6(self, origElement1, origElement2, startElementId self._mesh.destroyElement(origElement1) self._mesh.destroyElement(origElement2) fm.endChange() - - def createEftWedgeCollapseXi2(self, collapseNodes): - ''' - Create a tricubic hermite element field for a wedge element collapsed in xi2. - :return: Element field template - ''' - eft = self.createEftBasic() - - if collapseNodes in [[4, 8]]: - setEftScaleFactorIds(eft, [1], []) - nodes = [2, 4, 6, 8] - remapEftNodeValueLabel(eft, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) - ln_map = [1, 2, 3, 2, 4, 5, 6, 5] - - elif collapseNodes in [[3, 7]]: - nodes = [1, 3, 5, 7] - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, []) - remapEftNodeValueLabel(eft, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) - ln_map = [1, 2, 1, 3, 4, 5, 4, 6] - - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS2DS3, []) - remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D3_DS1DS2DS3, []) - - remapEftLocalNodes(eft, 6, ln_map) - assert eft.validate(), 'eftfactory_tricubichermite.createEftWedgeCollapseXi2: Failed to validate eft' - return eft From 9a2b482ef2614770f16447bca4fa4ef9707b03cc Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 10:48:18 +1200 Subject: [PATCH 23/38] Replace eft.validate assert with print calls --- src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py index 485fcd4d..a8ffe6c4 100644 --- a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py +++ b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py @@ -302,7 +302,8 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, []) remapEftLocalNodes(eft, 6, ln_map) - assert eft.validate(), 'eftfactory_bicubichermitelinear.createEftWedgeCollapseXi1Quadrant: Failed to validate eft' + if not eft.validate(): + print('eftfactory_bicubichermitelinear.createEftWedgeCollapseXi1Quadrant: Failed to validate eft for collapseNodes', collapseNodes) return eft def createEftWedgeCollapseXi2Quadrant(self, collapseNodes): From 17d0ab0037101ba3835d8ef38e8c291846cbc8df Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 11:15:12 +1200 Subject: [PATCH 24/38] Add description for argument collapseNodes --- src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py | 6 ++++++ src/scaffoldmaker/utils/eftfactory_tricubichermite.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py index a8ffe6c4..ee22dfd6 100644 --- a/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py +++ b/src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py @@ -252,6 +252,9 @@ def createEftWedgeXi1Zero(self): def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): ''' Create a bicubic hermite linear element field for a wedge element collapsed in xi1. + :param collapseNodes: As the element can be collapsed in xi1 at either ends of xi2 or xi3, collapseNodes + are the local indices of nodes whose d2 (for elements collapse at either ends of xi2) or + d3 (for elements collapse at either ends of xi3) are remapped with d1 before collapsing the nodes. :return: Element field template ''' eft = self.createEftBasic() @@ -309,6 +312,9 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): def createEftWedgeCollapseXi2Quadrant(self, collapseNodes): ''' Create a bicubic hermite linear element field for a wedge element collapsed in xi2. + :param collapseNodes: As the element can be collapsed in xi2 at either ends of xi1 or xi3, collapseNodes + are the local indices of nodes whose d1 (for elements collapse at either ends of xi1) or + d3 (for elements collapse at either ends of xi3) are remapped with d2 before collapsing the nodes. :return: Element field template ''' eft = self.createEftBasic() diff --git a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py index b996a7d8..bf83f9b1 100644 --- a/src/scaffoldmaker/utils/eftfactory_tricubichermite.py +++ b/src/scaffoldmaker/utils/eftfactory_tricubichermite.py @@ -822,6 +822,9 @@ def createEftWedgeXi1Zero(self): def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): ''' Create a tricubic hermite element field for a wedge element collapsed in xi1. + :param collapseNodes: As the element can be collapsed in xi1 at either ends of xi2 or xi3, collapseNodes + are the local indices of nodes whose d2 (for elements collapse at either ends of xi2) or + d3 (for elements collapse at either ends of xi3) are remapped with d1 before collapsing the nodes. :return: Element field template ''' eft = self.createEftBasic() @@ -898,6 +901,9 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes): def createEftWedgeCollapseXi2Quadrant(self, collapseNodes): ''' Create a tricubic hermite element field for a wedge element collapsed in xi2. + :param collapseNodes: As the element can be collapsed in xi2 at either ends of xi1 or xi3, collapseNodes + are the local indices of nodes whose d1 (for elements collapse at either ends of xi1) or + d3 (for elements collapse at either ends of xi3) are remapped with d2 before collapsing the nodes. :return: Element field template ''' eft = self.createEftBasic() From 7c7f8692708db1f4ce1d811a8483cd045f5ec53a Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 11:26:26 +1200 Subject: [PATCH 25/38] Merge parameters to Refine number of elements surface --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 9fae14b6..19cb21e1 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -252,8 +252,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Use cross derivatives': False, 'Use linear through wall' : False, 'Refine': False, - 'Refine number of elements around': 1, - 'Refine number of elements along': 1, + 'Refine number of elements surface': 1, 'Refine number of elements through wall': 1 } if 'Rat 1' in parameterSetName: @@ -285,8 +284,7 @@ def getOrderedOptionNames(): 'Use cross derivatives', 'Use linear through wall', 'Refine', - 'Refine number of elements around', - 'Refine number of elements along', + 'Refine number of elements surface', 'Refine number of elements through wall'] @classmethod @@ -350,8 +348,7 @@ def checkOptions(cls, options): options['Annulus derivative factor'] = 0.1 for key in [ 'Number of elements through wall', - 'Refine number of elements around', - 'Refine number of elements along', + 'Refine number of elements surface', 'Refine number of elements through wall']: if options[key] < 1: options[key] = 1 @@ -2277,8 +2274,8 @@ def refineMesh(cls, meshrefinement, options): :param meshrefinement: MeshRefinement, which knows source and target region. :param options: Dict containing options. See getDefaultOptions(). """ - refineElementsCountAround = options['Refine number of elements around'] - refineElementsCountAlong = options['Refine number of elements along'] + refineElementsCountAround = options['Refine number of elements surface'] + refineElementsCountAlong = options['Refine number of elements surface'] refineElementsCountThroughWall = options['Refine number of elements through wall'] meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, From 92f089ff2f0713263ac9d33c2190acdfaaab82b4 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 11:35:58 +1200 Subject: [PATCH 26/38] Add marker for pylorus on greater curvature --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 19cb21e1..f90e2ad8 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -2254,6 +2254,15 @@ def generateBaseMesh(cls, region, options): markerName.assignString(cache, "limiting ridge on greater curvature" if limitingRidge else "junction between fundus and body on greater curvature") markerLocation.assignMeshLocation(cache, fundusBodyJunctionElement, fundusBodyJunctionXi) + pylorusGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - (elementsCountAlongGroups[-1] +1) * elementsCountAroundDuod) + pylorusGCXi = [0.0, 1.0, 1.0] + cache.setMeshLocation(pylorusGCElement, pylorusGCXi) + markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) + nodeIdentifier += 1 + cache.setNode(markerPoint) + markerName.assignString(cache, "pylorus on greater curvature") + markerLocation.assignMeshLocation(cache, pylorusGCElement, pylorusGCXi) + duodenumGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - elementsCountAroundDuod) duodenumGCXi = [0.0, 1.0, 1.0] cache.setMeshLocation(duodenumGCElement, duodenumGCXi) From 795f073e2a12e6eb5f8b7957e3ca946c4cb73a9d Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 12:10:55 +1200 Subject: [PATCH 27/38] Create annotation groups for markers --- src/scaffoldmaker/annotation/stomach_terms.py | 11 ++++++++--- .../meshtypes/meshtype_3d_stomach1.py | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/annotation/stomach_terms.py b/src/scaffoldmaker/annotation/stomach_terms.py index 972fa443..e5046dee 100644 --- a/src/scaffoldmaker/annotation/stomach_terms.py +++ b/src/scaffoldmaker/annotation/stomach_terms.py @@ -7,14 +7,19 @@ ( "body of stomach", "UBERON:0001161", " FMA:14560", "ILX:0724929"), ( "cardia of stomach", "UBERON:0001162", " FMA:14561", "ILX:0729096"), ( "duodenum", "UBERON:0002114", " FMA:7206", "ILX:0726125"), + ( "duodenum on greater curvature", "None"), ( "esophagus", "UBERON:0001043", "FMA: 7131", "ILX:0735017"), ( "esophagogastric junction", "UBERON:0007650", "FMA: 9434", "ILX:0733910"), ( "forestomach-glandular stomach junction", "UBERON:0012270", "ILX:0729974"), - ( "forestomach-glandular stomach junction on inner wall", None), - ( "forestomach-glandular stomach junction on outer wall", None), + ( "forestomach-glandular stomach junction on inner wall", "None"), + ( "forestomach-glandular stomach junction on outer wall", "None"), ( "fundus of stomach", "UBERON:0001160", " FMA:14559", "ILX:0724443"), - ( "pyloric antrum", "UBERON:0001165", " FMA:14579", "ILX:0728672"), + ( "gastro-esophagal junction on lesser curvature", "None"), + ( "junction between fundus and body on greater curvature", "None"), + ( "limiting ridge on greater curvature", "None"), ( "pylorus", "UBERON:0001166", " FMA:14581", "ILX:0734150"), + ( "pyloric antrum", "UBERON:0001165", " FMA:14579", "ILX:0728672"), + ( "pylorus on greater curvature", "None"), ( "stomach", "UBERON:0000945", "FMA:7148", "ILX:0736697") ] diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index f90e2ad8..8f73a816 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -2236,41 +2236,49 @@ def generateBaseMesh(cls, region, options): nodeIdentifier = nextNodeIdentifier # annotation fiducial points for embedding in whole body + GEJLCGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("gastro-esophagal junction on lesser curvature")) GEJLCElement = mesh.findElementByIdentifier(stomachStartElement - elementsAroundHalfEso) GEJLCXi = [0.0, 1.0, 1.0] cache.setMeshLocation(GEJLCElement, GEJLCXi) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) - markerName.assignString(cache, "gastro-esophagal junction on lesser curvature") + markerName.assignString(cache, GEJLCGroup.getName()) markerLocation.assignMeshLocation(cache, GEJLCElement, GEJLCXi) + GEJLCGroup.getNodesetGroup(nodes).addNode(markerPoint) + fundusBodyJunctionGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("limiting ridge on greater curvature" if limitingRidge else "junction between fundus and body on greater curvature")) fundusBodyJunctionElement = mesh.findElementByIdentifier(fundusBodyJunctionElementIdentifier) fundusBodyJunctionXi = [0.0, 0.0 if limitingRidge else 1.0, 1.0] cache.setMeshLocation(fundusBodyJunctionElement, fundusBodyJunctionXi) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) - markerName.assignString(cache, "limiting ridge on greater curvature" if limitingRidge else "junction between fundus and body on greater curvature") + markerName.assignString(cache, fundusBodyJunctionGroup.getName()) markerLocation.assignMeshLocation(cache, fundusBodyJunctionElement, fundusBodyJunctionXi) + fundusBodyJunctionGroup.getNodesetGroup(nodes).addNode(markerPoint) - pylorusGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - (elementsCountAlongGroups[-1] +1) * elementsCountAroundDuod) + pylorusGCGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("pylorus on greater curvature")) + pylorusGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - (elementsCountAlongGroups[-1] + 1) * elementsCountAroundDuod) pylorusGCXi = [0.0, 1.0, 1.0] cache.setMeshLocation(pylorusGCElement, pylorusGCXi) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) - markerName.assignString(cache, "pylorus on greater curvature") + markerName.assignString(cache, pylorusGCGroup.getName()) markerLocation.assignMeshLocation(cache, pylorusGCElement, pylorusGCXi) + pylorusGCGroup.getNodesetGroup(nodes).addNode(markerPoint) + duodenumGCGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("duodenum on greater curvature")) duodenumGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - elementsCountAroundDuod) duodenumGCXi = [0.0, 1.0, 1.0] cache.setMeshLocation(duodenumGCElement, duodenumGCXi) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) - markerName.assignString(cache, "duodenum on greater curvature") + markerName.assignString(cache, duodenumGCGroup.getName()) markerLocation.assignMeshLocation(cache, duodenumGCElement, duodenumGCXi) + duodenumGCGroup.getNodesetGroup(nodes).addNode(markerPoint) fm.endChange() From 8bd8bd6fbcd0b18fc5d947825074fc5c90ba5d0e Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 14:55:44 +1200 Subject: [PATCH 28/38] Apply smoothing tools to central path for human stomach --- .../meshtypes/meshtype_3d_stomach1.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 8f73a816..7251c671 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -51,14 +51,14 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [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], [ - [ [ 70.8, 72.3, 0.0 ], [ -15.1, -43.8, 0.0 ], [ 37.3, -18.7, 0.0 ], [ 2.2, 7.2, 0.0 ], [ 0.0, 0.0, 38.7 ], [ 0.0, 0.0, 4.5 ] ], - [ [ 51.1, 30.7, 0.0 ], [ -21.4, -33.7, 0.0 ], [ 33.9, -17.5, 0.0 ], [ -9.0, -4.8, 0.0 ], [ 0.0, 0.0, 41.4 ], [ 0.0, 0.0, 0.9 ] ], - [ [ 27.8, 2.7, 0.0 ], [ -27.7, -18.4, 0.0 ], [ 20.5, -27.0, 0.0 ], [-17.1, -3.5, 0.0 ], [ 0.0, 0.0, 40.9 ], [ 0.0, 0.0, -5.0 ] ], - [ [ -0.3, -5.8, 0.0 ], [ -28.0, -2.6, 0.0 ], [ 0.4, -25.7, 0.0 ], [-12.6, 3.7, 0.0 ], [ 0.0, 0.0, 32.3 ], [ 0.0, 0.0, -9.4 ] ], - [ [ -26.5, -2.9, 0.0 ], [ -20.6, 8.0, 0.0 ], [ -5.4, -19.9, 0.0 ], [ -5.6, 7.7, 0.0 ], [ 0.0, 0.0, 22.1 ], [ 0.0, 0.0, -6.8 ] ], - [ [ -40.6, 7.4, 0.0 ], [ -11.0, 12.5, 0.0 ], [ -10.9, -10.9, 0.0 ], [ -1.3, 7.9, 0.0 ], [ 0.0, 0.0, 17.6 ], [ 0.0, 0.0, -5.9 ] ], - [ [ -48.1, 21.0, 0.0 ], [ -6.4, 15.7, 0.0 ], [ -8.4, -4.0, 0.0 ], [ 0.1, 4.9, 0.0 ], [ 0.0, 0.0, 10.5 ], [ 0.0, 0.0, -3.1 ] ], - [ [ -52.9, 38.6, 0.0 ], [ -3.2, 19.3, 0.0 ], [ -11.2, -1.5, 0.0 ], [ -5.7, 0.1, 0.0 ], [ 0.0, 0.0, 12.0 ], [ 0.0, 0.0, 6.1 ] ] ] ), + [ [ 70.8, 72.3, 0.0 ], [ -17.0, -47.9, 0.0 ], [ 39.3, -13.9, 0.0 ], [ -3.7, -5.9, 0.0 ], [ 0.0, 0.0, 38.7 ], [ 0.0, 0.0, 4.5] ], + [ [ 51.1, 30.7, 0.0 ], [ -22.3, -34.9, 0.0 ], [ 32.2, -20.5, 0.0 ], [ -10.6, -7.2, 0.0 ], [ 0.0, 0.0, 41.4 ], [ 0.0, 0.0, 0.9] ], + [ [ 27.8, 2.7, 0.0 ], [ -27.7, -18.4, 0.0 ], [ 18.7, -28.2, 0.0 ], [ -15.1, -2.0, 0.0 ], [ 0.0, 0.0, 40.9 ], [ 0.0, 0.0, -5.0] ], + [ [ -0.3, -5.8, 0.0 ], [ -28.0, -2.6, 0.0 ], [ 2.3, -25.6, 0.0 ], [ -12.9, 4.6, 0.0 ], [ 0.0, 0.0, 32.3 ], [ 0.0, 0.0, -9.4] ], + [ [ -26.5, -2.9, 0.0 ], [ -20.6, 8.0, 0.0 ], [ -7.5, -19.2, 0.0 ], [ -6.4, 8.0, 0.0 ], [ 0.0, 0.0, 22.1 ], [ 0.0, 0.0, -6.8] ], + [ [ -40.6, 7.4, 0.0 ], [ -11.0, 12.5, 0.0 ], [ -11.6, -10.2, 0.0 ], [ -0.4, 7.8, 0.0 ], [ 0.0, 0.0, 17.6 ], [ 0.0, 0.0, -5.9] ], + [ [ -48.1, 21.0, 0.0 ], [ -6.4, 15.7, 0.0 ], [ -8.6, -3.5, 0.0 ], [ 0.4, 4.4, 0.0 ], [ 0.0, 0.0, 10.5 ], [ 0.0, 0.0, -3.1] ], + [ [ -52.9, 38.6, 0.0 ], [ -3.2, 19.3, 0.0 ], [ -11.1, -1.9, 0.0 ], [ -5.5, -1.1, 0.0 ], [ 0.0, 0.0, 12.0 ], [ 0.0, 0.0, 6.1] ] ] ), 'userAnnotationGroups': [ { From 90deefcd8b11d202221563e5f0b5c721ab717418 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 15:56:38 +1200 Subject: [PATCH 29/38] Apply smoothing tools to central path of rat stomach --- .../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 7251c671..dac3e2d8 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -107,15 +107,15 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [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], [ - [ [ 12.4, 11.9, 0.0 ], [ -0.1, -14.5, 0.0 ], [ 8.7, -1.4, 0.0 ], [ -0.7, -3.5, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.5 ] ], - [ [ 9.5, -0.2, 0.0 ], [ -5.7, -9.0, 0.0 ], [ 6.6, -5.1, 0.0 ], [ -3.5, -3.9, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], - [ [ 2.8, -5.5, 0.0 ], [ -6.5, -2.5, 0.0 ], [ 2.1, -9.1, 0.0 ], [ -4.0, -1.5, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, 0.0 ] ], - [ [ -2.6, -6.0, 0.0 ], [ -5.5, 0.8, 0.0 ], [ -1.6, -9.2, 0.0 ], [ -4.0, 0.5, 0.0 ], [ 0.0, 0.0, 8.8 ], [ 0.0, 0.0, -0.4 ] ], - [ [ -8.2, -4.1, 0.0 ], [ -5.0, 3.9, 0.0 ], [ -6.0, -8.0, 0.0 ], [ -2.5, 2.7, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.2 ] ], - [ [ -12.3, 1.5, 0.0 ], [ -1.7, 7.2, 0.0 ], [ -6.4, -3.5, 0.0 ], [ 1.4, 4.0, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], - [ [ -10.8, 8.5, 0.0 ], [ 0.3, 5.3, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 0.5, 0.7, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -0.3 ] ], - [ [ -10.7, 12.2, 0.0 ], [ -0.3, 2.7, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -0.3, -0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 0.5 ] ], - [ [ -11.3, 14.8, 0.0 ], [ -0.9, 2.5, 0.0 ], [ -3.5, -0.3, 0.0 ], [ 0.3, 0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, -0.5 ] ] ] ), + [ [ 12.4, 11.9, 0.0 ], [ -0.1, -14.6, 0.0 ], [ 8.7, -1.4, 0.0 ], [ -0.7, -3.5, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.5] ], + [ [ 9.5, -0.2, 0.0 ], [ -5.7, -9.0, 0.0 ], [ 6.6, -5.1, 0.0 ], [ -3.5, -3.9, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7] ], + [ [ 2.8, -5.5, 0.0 ], [ -6.6, -2.6, 0.0 ], [ 2.1, -9.1, 0.0 ], [ -4.0, -1.6, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, 0.1] ], + [ [ -2.6, -6.0, 0.0 ], [ -5.7, 0.7, 0.0 ], [ -1.6, -9.2, 0.0 ], [ -4.0, 0.5, 0.0 ], [ 0.0, 0.0, 8.8 ], [ 0.0, 0.0, -0.4] ], + [ [ -8.2, -4.1, 0.0 ], [ -5.3, 3.9, 0.0 ], [ -6.0, -8.0, 0.0 ], [ -2.6, 2.7, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.2] ], + [ [ -12.3, 1.5, 0.0 ], [ -1.5, 7.0, 0.0 ], [ -6.4, -3.5, 0.0 ], [ 1.5, 4.0, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8] ], + [ [ -10.8, 8.5, 0.0 ], [ 0.6, 5.4, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 0.8, 1.0, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -0.6] ], + [ [ -10.7, 12.2, 0.0 ], [ -0.3, 3.2, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -0.3, -0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 0.4] ], + [ [ -11.3, 14.8, 0.0 ], [ -0.9, 2.0, 0.0 ], [ -3.5, -0.3, 0.0 ], [ 0.3, 0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, -0.4] ] ] ), 'userAnnotationGroups': [ { From b2c37141c711752a5e5dcd2420ce9eb8d3cc8278 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 16:01:53 +1200 Subject: [PATCH 30/38] Update refine number of elements surface to 4 --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index dac3e2d8..6802581c 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -252,7 +252,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Use cross derivatives': False, 'Use linear through wall' : False, 'Refine': False, - 'Refine number of elements surface': 1, + 'Refine number of elements surface': 4, 'Refine number of elements through wall': 1 } if 'Rat 1' in parameterSetName: From ff89deab54aff62dfea9fa9425243a5b4b2e0bd4 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 16:08:12 +1200 Subject: [PATCH 31/38] Remove number of elements through wall option until support for multiple elements through annulus wall --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 6802581c..600e6f34 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -242,7 +242,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements around esophagus': 8, 'Number of elements around duodenum': 12, 'Number of elements between annulus and duodenum': 6, - 'Number of elements through wall': 1, 'Number of radial elements in annulus': 1, 'Wall thickness': 5.0, 'Limiting ridge': False, @@ -274,7 +273,6 @@ def getOrderedOptionNames(): 'Number of elements around esophagus', 'Number of elements around duodenum', 'Number of elements between annulus and duodenum', - 'Number of elements through wall', 'Number of radial elements in annulus', 'Wall thickness', 'Limiting ridge', @@ -347,7 +345,6 @@ def checkOptions(cls, options): if options['Annulus derivative factor'] <= 0.0: options['Annulus derivative factor'] = 0.1 for key in [ - 'Number of elements through wall', 'Refine number of elements surface', 'Refine number of elements through wall']: if options[key] < 1: @@ -378,7 +375,7 @@ def generateBaseMesh(cls, region, options): elementsCountAroundEso = options['Number of elements around esophagus'] elementsCountAroundDuod = options['Number of elements around duodenum'] elementsAlongAnnulusToDuod = options['Number of elements between annulus and duodenum'] - elementsCountThroughWall = options['Number of elements through wall'] + elementsCountThroughWall = 1 wallThickness = options['Wall thickness'] useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not (options['Use linear through wall']) From 2aa5557418d81be913606fcf5fcc63c11f36fb94 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 16:38:16 +1200 Subject: [PATCH 32/38] Replace option names with annulus with cardia --- .../meshtypes/meshtype_3d_stomach1.py | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 600e6f34..81119211 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -241,13 +241,13 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Central path': copy.deepcopy(centralPathOption), 'Number of elements around esophagus': 8, 'Number of elements around duodenum': 12, - 'Number of elements between annulus and duodenum': 6, - 'Number of radial elements in annulus': 1, + 'Number of elements between cardia and duodenum': 6, + 'Number of elements across cardia': 1, 'Wall thickness': 5.0, 'Limiting ridge': False, 'Gastro-esophagal junction': copy.deepcopy(ostiumOption), 'Gastro-esophagal junction position along factor': 0.35, - 'Annulus derivative factor': 1.0, + 'Cardia derivative factor': 1.0, 'Use cross derivatives': False, 'Use linear through wall' : False, 'Refine': False, @@ -257,7 +257,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): if 'Rat 1' in parameterSetName: options['Number of elements around esophagus'] = 12 options['Number of elements around duodenum'] = 14 - options['Number of elements between annulus and duodenum'] = 2 + options['Number of elements between cardia and duodenum'] = 2 options['Wall thickness'] = 0.5 options['Gastro-esophagal junction position along factor'] = 0.55 options['Annulus derivative factor'] = 0.2 @@ -272,13 +272,13 @@ def getOrderedOptionNames(): 'Central path', 'Number of elements around esophagus', 'Number of elements around duodenum', - 'Number of elements between annulus and duodenum', - 'Number of radial elements in annulus', + 'Number of elements between cardia and duodenum', + 'Number of elements across cardia', 'Wall thickness', 'Limiting ridge', 'Gastro-esophagal junction', 'Gastro-esophagal junction position along factor', - 'Annulus derivative factor', + 'Cardia derivative factor', 'Use cross derivatives', 'Use linear through wall', 'Refine', @@ -340,10 +340,10 @@ def checkOptions(cls, options): options['Number of elements around duodenum'] = 12 if options['Number of elements around duodenum'] % 2: options['Number of elements around duodenum'] += 1 - if options['Number of elements between annulus and duodenum'] < 2: - options['Number of elements between annulus and duodenum'] = 2 - if options['Annulus derivative factor'] <= 0.0: - options['Annulus derivative factor'] = 0.1 + if options['Number of elements between cardia and duodenum'] < 2: + options['Number of elements between cardia and duodenum'] = 2 + if options['Cardia derivative factor'] <= 0.0: + options['Cardia derivative factor'] = 0.1 for key in [ 'Refine number of elements surface', 'Refine number of elements through wall']: @@ -374,7 +374,7 @@ def generateBaseMesh(cls, region, options): centralPath = options['Central path'] elementsCountAroundEso = options['Number of elements around esophagus'] elementsCountAroundDuod = options['Number of elements around duodenum'] - elementsAlongAnnulusToDuod = options['Number of elements between annulus and duodenum'] + elementsAlongCardiaToDuod = options['Number of elements between cardia and duodenum'] elementsCountThroughWall = 1 wallThickness = options['Wall thickness'] useCrossDerivatives = options['Use cross derivatives'] @@ -384,14 +384,14 @@ def generateBaseMesh(cls, region, options): GEJOptions = options['Gastro-esophagal junction'] GEJSettings = GEJOptions.getScaffoldSettings() limitingRidge = options['Limiting ridge'] - elementsCountAnnulus = options['Number of radial elements in annulus'] - annulusDerivativeFactor = options['Annulus derivative factor'] + elementsCountAcrossCardia = options['Number of elements across cardia'] + cardiaDerivativeFactor = options['Cardia derivative factor'] elementsCountAlongTrackSurface = 20 elementsAroundHalfEso = int(elementsCountAroundEso * 0.5) elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) elementsAroundHalfDuod = int(elementsCountAroundDuod * 0.5) - elementsCountAlong = elementsAlongAnnulusToDuod + elementsAroundHalfEso + 1 + elementsCountAlong = elementsAlongCardiaToDuod + elementsAroundHalfEso + 1 zero = [0.0, 0.0, 0.0] fm = region.getFieldmodule() @@ -639,7 +639,7 @@ def generateBaseMesh(cls, region, options): xAlongUpFundus = [] d2AlongUpFundus = [] xAlongUpFundus.append(o1_x[1][0]) - d2AlongUpFundus.append([annulusDerivativeFactor * c for c in o1_d2[1][0]]) + d2AlongUpFundus.append([cardiaDerivativeFactor * c for c in o1_d2[1][0]]) # From esophagus to fundus apex esoStartProportion2 = trackSurfaceStomach.getProportion(o1_Positions[0])[1] @@ -772,7 +772,7 @@ def generateBaseMesh(cls, region, options): getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, endProportion2, elementsAroundHalfDuod + 1, startDerivative=d1GC, endDerivative=d1EndOstium, - endDerivativeMagnitude=annulusDerivativeFactor * vector.magnitude(d2)) + endDerivativeMagnitude=cardiaDerivativeFactor * vector.magnitude(d2)) # Second half ostiumIdx2 = -n2 startPosition = o1_Positions[ostiumIdx2] @@ -782,7 +782,7 @@ def generateBaseMesh(cls, region, options): getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, GCProportion2, elementsAroundHalfDuod + 1, startDerivative=d1StartOstium, endDerivative=d1GC, - startDerivativeMagnitude=annulusDerivativeFactor * + startDerivativeMagnitude=cardiaDerivativeFactor * vector.magnitude(d1StartOstium)) xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] @@ -896,7 +896,7 @@ def generateBaseMesh(cls, region, options): d = o1_d2[1][elementsAroundHalfEso] rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][elementsAroundHalfEso], math.pi) p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - p1d_6pt = [annulusDerivativeFactor * c for c in p1d] + p1d_6pt = [cardiaDerivativeFactor * c for c in p1d] p2x_6pt = xAve[int(len(xAve)*0.5) + 1] p2d_6pt = findDerivativeBetweenPoints(p2x_6pt, xAve[int(len(xAve) * 0.5) + 2]) @@ -994,7 +994,7 @@ def generateBaseMesh(cls, region, options): d = o1_d2[1][ostiumIdx] rotFrame = matrix.getRotationMatrixFromAxisAngle(o1_d1[1][ostiumIdx], math.pi) p1d = [rotFrame[j][0] * d[0] + rotFrame[j][1] * d[1] + rotFrame[j][2] * d[2] for j in range(3)] - p1d = [annulusDerivativeFactor * c for c in p1d] + p1d = [cardiaDerivativeFactor * c for c in p1d] xLoops = xLoopsRight if nSide == 0 else xLoopsLeft p2x = xLoops[0][elementsAroundQuarterEso + 1] # downstream bifurcation @@ -1065,7 +1065,7 @@ def generateBaseMesh(cls, region, options): ostiumPosition = o1_Positions[ostiumIdx] ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) d = findDerivativeBetweenPoints(xLoop, xOstium) - endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor + endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * cardiaDerivativeFactor xSampled, dSampled = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, xLoopProportion1, xLoopProportion2, ostiumProportion1, @@ -1088,7 +1088,7 @@ def generateBaseMesh(cls, region, options): ostiumPosition = o1_Positions[-ostiumIdx] ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) d = findDerivativeBetweenPoints(xOstium, xLoop) - startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor + startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * cardiaDerivativeFactor xSampled, dSampled = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, xLoopProportion1, @@ -1155,7 +1155,7 @@ def generateBaseMesh(cls, region, options): ostiumPosition = o1_Positions[ostiumIdx] ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) d = findDerivativeBetweenPoints(xLoop, xOstium) - endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * annulusDerivativeFactor + endDerivativeMag = vector.magnitude(o1_d2[1][ostiumIdx]) * cardiaDerivativeFactor xSampled, dSampled = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, xLoopProportion1, xLoopProportion2, ostiumProportion1, @@ -1172,7 +1172,7 @@ def generateBaseMesh(cls, region, options): ostiumPosition = o1_Positions[-ostiumIdx] ostiumProportion1, ostiumProportion2 = trackSurfaceStomach.getProportion(ostiumPosition) d = findDerivativeBetweenPoints(xOstium, xLoop) - startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * annulusDerivativeFactor + startDerivativeMag = vector.magnitude(o1_d2[1][-ostiumIdx]) * cardiaDerivativeFactor xSampled, dSampled = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, ostiumProportion1, ostiumProportion2, @@ -1238,10 +1238,10 @@ def generateBaseMesh(cls, region, options): pass else: if elementsCountAroundEso > 8: - xStart = xAlongAround[-(elementsAlongAnnulusToDuod + 3)][n] + xStart = xAlongAround[-(elementsAlongCardiaToDuod + 3)][n] else: xStart = xUp[-1][n] - xEnd = xAlongAround[-(elementsAlongAnnulusToDuod + 1)][n - (1 if n > elementsAroundHalfDuod else 0)] + xEnd = xAlongAround[-(elementsAlongCardiaToDuod + 1)][n - (1 if n > elementsAroundHalfDuod else 0)] startPosition = trackSurfaceStomach.findNearestPosition(xStart) d2Start = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[2] @@ -1252,7 +1252,7 @@ def generateBaseMesh(cls, region, options): xSampled = interp.sampleCubicHermiteCurves([xStart, xEnd], [d2Start, d2End], 2)[0] xNewPosition = trackSurfaceStomach.findNearestPosition(xSampled[1]) xNew = trackSurfaceStomach.evaluateCoordinates(xNewPosition) - xAlongAround[-(elementsAlongAnnulusToDuod + 2)][n] = xNew + xAlongAround[-(elementsAlongCardiaToDuod + 2)][n] = xNew # Assemble nodes and d1 xOuter = [] @@ -2226,7 +2226,7 @@ def generateBaseMesh(cls, region, options): 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 = elementsCountAnnulus, meshGroups= [stomachMeshGroup, cardiaMeshGroup], + elementsCountRadial = elementsCountAcrossCardia, meshGroups= [stomachMeshGroup, cardiaMeshGroup], tracksurface=trackSurfaceStomach, startProportions = startProportions, endProportions = endProportions, rescaleStartDerivatives = True, rescaleEndDerivatives = True) From 6d967603bc9192c031783edc569969ec8d5467b3 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 16:51:39 +1200 Subject: [PATCH 33/38] Add esophagus to stomach annotation group --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 81119211..d6558e3b 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -610,7 +610,7 @@ def generateBaseMesh(cls, region, options): nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, - nodeIdentifier, elementIdentifier, vesselMeshGroups=[[esophagusMeshGroup]], + nodeIdentifier, elementIdentifier, vesselMeshGroups=[[stomachMeshGroup, esophagusMeshGroup]], ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup]) stomachStartNode = nextNodeIdentifier From 81b54f216df3978a451ddb41b35aa2d56d9ae3af Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Tue, 4 May 2021 17:06:00 +1200 Subject: [PATCH 34/38] Add markers to stomach group --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index d6558e3b..560dfc12 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -2242,7 +2242,8 @@ def generateBaseMesh(cls, region, options): cache.setNode(markerPoint) markerName.assignString(cache, GEJLCGroup.getName()) markerLocation.assignMeshLocation(cache, GEJLCElement, GEJLCXi) - GEJLCGroup.getNodesetGroup(nodes).addNode(markerPoint) + for group in [stomachGroup, GEJLCGroup]: + group.getNodesetGroup(nodes).addNode(markerPoint) fundusBodyJunctionGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("limiting ridge on greater curvature" if limitingRidge else "junction between fundus and body on greater curvature")) fundusBodyJunctionElement = mesh.findElementByIdentifier(fundusBodyJunctionElementIdentifier) @@ -2253,7 +2254,8 @@ def generateBaseMesh(cls, region, options): cache.setNode(markerPoint) markerName.assignString(cache, fundusBodyJunctionGroup.getName()) markerLocation.assignMeshLocation(cache, fundusBodyJunctionElement, fundusBodyJunctionXi) - fundusBodyJunctionGroup.getNodesetGroup(nodes).addNode(markerPoint) + for group in [stomachGroup, fundusBodyJunctionGroup]: + group.getNodesetGroup(nodes).addNode(markerPoint) pylorusGCGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("pylorus on greater curvature")) pylorusGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - (elementsCountAlongGroups[-1] + 1) * elementsCountAroundDuod) @@ -2264,7 +2266,8 @@ def generateBaseMesh(cls, region, options): cache.setNode(markerPoint) markerName.assignString(cache, pylorusGCGroup.getName()) markerLocation.assignMeshLocation(cache, pylorusGCElement, pylorusGCXi) - pylorusGCGroup.getNodesetGroup(nodes).addNode(markerPoint) + for group in [stomachGroup, pylorusGCGroup]: + group.getNodesetGroup(nodes).addNode(markerPoint) duodenumGCGroup = findOrCreateAnnotationGroupForTerm(allAnnotationGroups, region, get_stomach_term("duodenum on greater curvature")) duodenumGCElement = mesh.findElementByIdentifier(lastDuodenumElementIdentifier - elementsCountAroundDuod) @@ -2275,7 +2278,8 @@ def generateBaseMesh(cls, region, options): cache.setNode(markerPoint) markerName.assignString(cache, duodenumGCGroup.getName()) markerLocation.assignMeshLocation(cache, duodenumGCElement, duodenumGCXi) - duodenumGCGroup.getNodesetGroup(nodes).addNode(markerPoint) + for group in [stomachGroup, duodenumGCGroup]: + group.getNodesetGroup(nodes).addNode(markerPoint) fm.endChange() From 5e7809eaf72813afef5c05437424f732397f0ab6 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Wed, 5 May 2021 22:01:09 +1200 Subject: [PATCH 35/38] Vary cardia derivative factor to smooth transition around annulus from triple point to 6pt junction --- .../meshtypes/meshtype_3d_stomach1.py | 103 +++++++++++++----- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 560dfc12..62d8a862 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -260,7 +260,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Number of elements between cardia and duodenum'] = 2 options['Wall thickness'] = 0.5 options['Gastro-esophagal junction position along factor'] = 0.55 - options['Annulus derivative factor'] = 0.2 + options['Cardia derivative factor'] = 0.2 options['Limiting ridge'] = True cls.updateSubScaffoldOptions(options) @@ -768,6 +768,7 @@ def generateBaseMesh(cls, region, options): d2 = o1_d2[1][ostiumIdx] d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + xFirstHalf, d1FirstHalf = \ getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, endProportion2, elementsAroundHalfDuod + 1, @@ -918,6 +919,80 @@ def generateBaseMesh(cls, region, options): xAlongAround.append(xAround) d1AlongAround.append(d1Around) + # Re-sample rings from downstream of triple point (excluding triple point) to + # 6pt junction (excluding 6pt) so that the nodes around the cardia transit in a smooth curve + # from triple point to 6pt junction + distBetween6ptJunctionOstium = vector.magnitude([o1_x[1][elementsAroundHalfEso][c] - x6pt[c] for c in range(3)]) + distAnnulusAtQuarterEso = cardiaDerivativeFactor * vector.magnitude(o1_d2[1][elementsAroundQuarterEso]) + + n = 0 + for n2 in range(elementsAroundQuarterEso + 1, elementsAroundHalfEso): + xi = n/elementsAroundQuarterEso + derivativeMagnitude = xi * distBetween6ptJunctionOstium + (1-xi) * distAnnulusAtQuarterEso + ostiumIdx = n2 + GCIdx = elementsAroundHalfDuod - 1 + n2 + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xEsoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + endPosition = o1_Positions[ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) + d2 = o1_d2[1][ostiumIdx] + d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + + xFirstHalf, d1FirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, + endProportion2, elementsAroundHalfDuod + 1, + startDerivative=d1GC, endDerivative=d1EndOstium, + endDerivativeMagnitude=derivativeMagnitude) + # Second half + ostiumIdx2 = -n2 + startPosition = o1_Positions[ostiumIdx2] + d1StartOstium = o1_d2[1][ostiumIdx2] + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + xSecondHalf, d1SecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, + GCProportion2, elementsAroundHalfDuod + 1, + startDerivative=d1StartOstium, endDerivative=d1GC, + startDerivativeMagnitude=derivativeMagnitude) + + xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] + d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] + + # Replace original values + xAlongAround[n] = xAround + d1AlongAround[n] = d1Around + n += 1 + + # Resample ring with 6pt junction to improve smoothness + idx = -(elementsCountAlong - elementsAroundHalfEso - 1) + xAve = [] + dAve = [] + xAve.append(xEsoToDuodGC[idx - 1]) + + for n1 in range(1, elementsCountAroundDuod + 1): + startPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[n - 1][n1]) + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + endPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[n + 1][n1 + (0 if n1 < elementsAroundHalfDuod + 1 else -1)]) + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + xSampled = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, + startProportion2, endProportion1, endProportion2, 2)[0] + + xAve.append(xSampled[1]) + + xAve[int(len(xAve) * 0.5)] = x6pt + del xAve[int(len(xAve) * 0.5) + 1] + + for n1 in range(len(xAve)): + v1 = xAve[n1] + v2 = xAve[(n1 + 1) % len(xAve)] + d1 = findDerivativeBetweenPoints(v1, v2) + dAve.append(d1) + dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) + xAlongAround[n] = xAve + d1AlongAround[n] = dAve + # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround ptsOnTrackSurfaceEsoToFundus = [] for n2 in range(elementsCountAlongTrackSurface + 1): @@ -953,8 +1028,8 @@ def generateBaseMesh(cls, region, options): d2GC = d2GCRot xEnd = xAlongAround[0][elementsAroundHalfDuod + 1 + nLoop] - d2End = [xAlongAround[1][elementsAroundHalfDuod + nLoop][c] - - xAlongAround[0][elementsAroundHalfDuod + (0 if elementsCountAroundEso > 8 else 1) + nLoop][c] for c in range(3)] + d2End = [xAlongAround[1][elementsAroundHalfDuod + nLoop + 1][c] - + xAlongAround[0][elementsAroundHalfDuod + (1 if elementsCountAroundEso > 8 else 2) + nLoop][c] for c in range(3)] nx = [xEsoToDuodGC[GCIdx], xEnd] nd2 = [d2GC, d2End] @@ -1232,28 +1307,6 @@ def generateBaseMesh(cls, region, options): dLoopGCTriplePt.append(d) dSmoothLoopGCTriplePt = interp.smoothCubicHermiteDerivativesLoop(xLoopGCTriplePt, dLoopGCTriplePt) - # Resample loop before 6 point junction - for n in range(1, elementsCountAroundDuod + 1): - if elementsAroundHalfDuod <= n <= elementsAroundHalfDuod + 1: - pass - else: - if elementsCountAroundEso > 8: - xStart = xAlongAround[-(elementsAlongCardiaToDuod + 3)][n] - else: - xStart = xUp[-1][n] - xEnd = xAlongAround[-(elementsAlongCardiaToDuod + 1)][n - (1 if n > elementsAroundHalfDuod else 0)] - - startPosition = trackSurfaceStomach.findNearestPosition(xStart) - d2Start = trackSurfaceStomach.evaluateCoordinates(startPosition, derivatives=True)[2] - - endPosition = trackSurfaceStomach.findNearestPosition(xEnd) - d2End = trackSurfaceStomach.evaluateCoordinates(endPosition, derivatives=True)[2] - - xSampled = interp.sampleCubicHermiteCurves([xStart, xEnd], [d2Start, d2End], 2)[0] - xNewPosition = trackSurfaceStomach.findNearestPosition(xSampled[1]) - xNew = trackSurfaceStomach.evaluateCoordinates(xNewPosition) - xAlongAround[-(elementsAlongCardiaToDuod + 2)][n] = xNew - # Assemble nodes and d1 xOuter = [] d1Outer = [] From 5914a70566d1c76cd786bd1f61428497ae1548fc Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Wed, 5 May 2021 22:27:52 +1200 Subject: [PATCH 36/38] Remove redundant steps --- .../meshtypes/meshtype_3d_stomach1.py | 117 ++++++++---------- 1 file changed, 52 insertions(+), 65 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 62d8a862..95c5d58d 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -749,50 +749,46 @@ def generateBaseMesh(cls, region, options): break ptsOnTrackSurfaceGC = [] - xAlongAround = [] - d1AlongAround = [] + xAroundEllipse = [] + d1AroundEllipse = [] for n2 in range(elementsCountAlongTrackSurface + 1): ptsOnTrackSurfaceGC.append(xSampledAll[n2][0]) - # Rings adjacent to triple point (excluding triple point rings) to 6 point junction + # Ring upstream of 6 point junction # First half - for n2 in range(elementsAroundQuarterEso + 1, elementsAroundHalfEso): - ostiumIdx = n2 - GCIdx = elementsAroundHalfDuod - 1 + n2 - GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xEsoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, - trackSurfaceStomach, 0.0, - elementsCountAlongTrackSurface) - GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) - endPosition = o1_Positions[ostiumIdx] - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) - d2 = o1_d2[1][ostiumIdx] - d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) - - xFirstHalf, d1FirstHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, - endProportion2, elementsAroundHalfDuod + 1, - startDerivative=d1GC, endDerivative=d1EndOstium, - endDerivativeMagnitude=cardiaDerivativeFactor * vector.magnitude(d2)) - # Second half - ostiumIdx2 = -n2 - startPosition = o1_Positions[ostiumIdx2] - d1StartOstium = o1_d2[1][ostiumIdx2] - startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - xSecondHalf, d1SecondHalf = \ - getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, - GCProportion2, elementsAroundHalfDuod + 1, - startDerivative=d1StartOstium, endDerivative=d1GC, - startDerivativeMagnitude=cardiaDerivativeFactor * - vector.magnitude(d1StartOstium)) - - xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] - d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] - - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - - # Elements downstream of 6 pt junction + n2 = elementsAroundHalfEso - 1 + ostiumIdx = n2 + GCIdx = elementsAroundHalfDuod - 1 + n2 + GCPosition, d1GC = findClosestPositionAndDerivativeOnTrackSurface(xEsoToDuodGC[GCIdx], ptsOnTrackSurfaceGC, + trackSurfaceStomach, 0.0, + elementsCountAlongTrackSurface) + GCProportion1, GCProportion2 = trackSurfaceStomach.getProportion(GCPosition) + endPosition = o1_Positions[ostiumIdx] + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(o1_d1[1][ostiumIdx]), math.pi) + d2 = o1_d2[1][ostiumIdx] + d1EndOstium = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) + + xFirstHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, 0.0, GCProportion2, endProportion1, + endProportion2, elementsAroundHalfDuod + 1, + startDerivative=d1GC, endDerivative=d1EndOstium, + endDerivativeMagnitude=cardiaDerivativeFactor * vector.magnitude(d2))[0] + # Second half + ostiumIdx2 = -n2 + startPosition = o1_Positions[ostiumIdx2] + d1StartOstium = o1_d2[1][ostiumIdx2] + startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) + xSecondHalf = \ + getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, 1.0, + GCProportion2, elementsAroundHalfDuod + 1, + startDerivative=d1StartOstium, endDerivative=d1GC, + startDerivativeMagnitude=cardiaDerivativeFactor * + vector.magnitude(d1StartOstium))[0] + + xAroundBefore6Pt = xFirstHalf[:-1] + xSecondHalf[1:-1] + + # Rings downstream of 6 pt junction for idx in range(-(elementsCountAlong - elementsAroundHalfEso - 1), 0): # Search for point on central path and use that to make ellipse xStart = xEsoToDuodGC[idx] @@ -873,11 +869,12 @@ def generateBaseMesh(cls, region, options): d1Around = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) + xAroundEllipse.append(xAround) + d1AroundEllipse.append(d1Around) # Average adjacent ring with first downstream ring that is not adjacent to esophagus if idx == -(elementsCountAlong - elementsAroundHalfEso - 1): xAve = [] - dAve = [] xAve.append(xEsoToDuodGC[idx - 1]) for n in range(1, elementsCountAroundDuod): @@ -886,7 +883,7 @@ def generateBaseMesh(cls, region, options): if n == elementsAroundHalfDuod: endPosition = o1_Positions[elementsAroundHalfEso] else: - endPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[-1][n + (0 if n < elementsAroundHalfDuod else 1)]) + endPosition = trackSurfaceStomach.findNearestPosition(xAroundBefore6Pt[n + (0 if n < elementsAroundHalfDuod else 1)]) endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) xSampled = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, endProportion1, endProportion2, 2)[0] @@ -906,26 +903,15 @@ def generateBaseMesh(cls, region, options): p3d_6pt = findDerivativeBetweenPoints(p3x_6pt, xAve[int(len(xAve) * 0.5) - 2]) x6pt = get_bifurcation_triple_point(p1x_6pt, p1d_6pt, p2x_6pt, p2d_6pt, p3x_6pt, p3d_6pt)[0] - xAve[int(len(xAve) * 0.5)] = x6pt - - for n in range(len(xAve)): - v1 = xAve[n] - v2 = xAve[(n + 1) % len(xAve)] - d1 = findDerivativeBetweenPoints(v1, v2) - dAve.append(d1) - dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) - xAlongAround.append(xAve) - d1AlongAround.append(dAve) - xAlongAround.append(xAround) - d1AlongAround.append(d1Around) - # Re-sample rings from downstream of triple point (excluding triple point) to - # 6pt junction (excluding 6pt) so that the nodes around the cardia transit in a smooth curve - # from triple point to 6pt junction + # Gradually vary derivative magnitude at annulus to create smooth transition of nodes around the cardia + # between triple point to 6pt junction distBetween6ptJunctionOstium = vector.magnitude([o1_x[1][elementsAroundHalfEso][c] - x6pt[c] for c in range(3)]) distAnnulusAtQuarterEso = cardiaDerivativeFactor * vector.magnitude(o1_d2[1][elementsAroundQuarterEso]) n = 0 + xAlongAround = [] + d1AlongAround = [] for n2 in range(elementsAroundQuarterEso + 1, elementsAroundHalfEso): xi = n/elementsAroundQuarterEso derivativeMagnitude = xi * distBetween6ptJunctionOstium + (1-xi) * distAnnulusAtQuarterEso @@ -960,10 +946,9 @@ def generateBaseMesh(cls, region, options): xAround = xFirstHalf[:-1] + xSecondHalf[1:-1] d1Around = d1FirstHalf[:-1] + d1SecondHalf[1:-1] - # Replace original values - xAlongAround[n] = xAround - d1AlongAround[n] = d1Around n += 1 + xAlongAround.append(xAround) + d1AlongAround.append(d1Around) # Resample ring with 6pt junction to improve smoothness idx = -(elementsCountAlong - elementsAroundHalfEso - 1) @@ -972,13 +957,12 @@ def generateBaseMesh(cls, region, options): xAve.append(xEsoToDuodGC[idx - 1]) for n1 in range(1, elementsCountAroundDuod + 1): - startPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[n - 1][n1]) + startPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[-1][n1]) startProportion1, startProportion2 = trackSurfaceStomach.getProportion(startPosition) - endPosition = trackSurfaceStomach.findNearestPosition(xAlongAround[n + 1][n1 + (0 if n1 < elementsAroundHalfDuod + 1 else -1)]) + endPosition = trackSurfaceStomach.findNearestPosition(xAroundEllipse[0][n1 + (0 if n1 < elementsAroundHalfDuod + 1 else -1)]) endProportion1, endProportion2 = trackSurfaceStomach.getProportion(endPosition) xSampled = getSmoothedSampledPointsOnTrackSurface(trackSurfaceStomach, startProportion1, startProportion2, endProportion1, endProportion2, 2)[0] - xAve.append(xSampled[1]) xAve[int(len(xAve) * 0.5)] = x6pt @@ -990,8 +974,11 @@ def generateBaseMesh(cls, region, options): d1 = findDerivativeBetweenPoints(v1, v2) dAve.append(d1) dAve = interp.smoothCubicHermiteDerivativesLoop(xAve, dAve) - xAlongAround[n] = xAve - d1AlongAround[n] = dAve + xAlongAround.append(xAve) + d1AlongAround.append(dAve) + + xAlongAround += xAroundEllipse + d1AlongAround += d1AroundEllipse # Sample 2 loops next to annulus from point on GC to point on first ring on xAlongAround ptsOnTrackSurfaceEsoToFundus = [] From 89b9714822eacea579ca2787fe7ee33be4830d0e Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Thu, 6 May 2021 10:02:48 +1200 Subject: [PATCH 37/38] Correct error to improve greater curvature near fundus end --- src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 95c5d58d..f7673366 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -657,7 +657,7 @@ def generateBaseMesh(cls, region, options): d2AlongUpFundus.append(d2) # From fundus apex to end - for n2 in range(startIdx - (0 if limitingRidge else 1)): + for n2 in range(startIdx + (1 if limitingRidge else 0)): xAlongUpFundus.append(xSampledAll[n2][0]) d2AlongUpFundus.append(d2SampledAll[n2][0]) From 07cfc79e85f38020c94a2accf9a3a6ccdcd96b29 Mon Sep 17 00:00:00 2001 From: Mabelle Lin Date: Thu, 6 May 2021 13:53:00 +1200 Subject: [PATCH 38/38] Update unit test for stomach --- tests/test_stomach.py | 113 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 15 deletions(-) diff --git a/tests/test_stomach.py b/tests/test_stomach.py index 954f0c57..a6d535fd 100644 --- a/tests/test_stomach.py +++ b/tests/test_stomach.py @@ -1,11 +1,15 @@ +import copy import unittest -from opencmiss.utils.zinc.finiteelement import evaluateFieldNodesetRange +from opencmiss.utils.zinc.finiteelement import evaluateFieldNodesetRange, findNodeWithName from opencmiss.utils.zinc.general import ChangeManager from opencmiss.zinc.context import Context from opencmiss.zinc.element import Element from opencmiss.zinc.field import Field from opencmiss.zinc.result import RESULT_OK +from scaffoldmaker.annotation.annotationgroup import getAnnotationGroupForTerm +from scaffoldmaker.annotation.stomach_terms import get_stomach_term from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1 +from scaffoldmaker.utils.meshrefinement import MeshRefinement from scaffoldmaker.utils.zinc_utils import createFaceMeshGroupExteriorOnFace from testutils import assertAlmostEqualList @@ -15,15 +19,15 @@ def test_stomach1(self): """ Test creation of stomach scaffold. """ - parameterSetNames = MeshType_3d_stomach1.getParameterSetNames() + scaffold = MeshType_3d_stomach1 + parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, [ "Default", "Human 1", "Rat 1" ]) - options = MeshType_3d_stomach1.getDefaultOptions("Rat 1") - self.assertEqual(17, len(options)) + options = scaffold.getDefaultOptions("Rat 1") + self.assertEqual(15, len(options)) self.assertEqual(12, options.get("Number of elements around esophagus")) self.assertEqual(14, options.get("Number of elements around duodenum")) - self.assertEqual(2, options.get("Number of elements between annulus and duodenum")) - self.assertEqual(1, options.get("Number of elements through wall")) - self.assertEqual(1, options.get("Number of radial elements in annulus")) + self.assertEqual(2, options.get("Number of elements between cardia and duodenum")) + self.assertEqual(1, options.get("Number of elements across cardia")) self.assertEqual(0.5, options.get("Wall thickness")) self.assertEqual(True, options.get("Limiting ridge")) ostiumOptions = options['Gastro-esophagal junction'] @@ -38,13 +42,13 @@ def test_stomach1(self): self.assertEqual(0.5, ostiumSettings.get("Vessel wall thickness")) self.assertEqual(0.0, ostiumSettings.get("Vessel angle 1 degrees")) self.assertEqual(0.55, options.get("Gastro-esophagal junction position along factor")) - self.assertEqual(0.2, options.get("Annulus derivative factor")) + self.assertEqual(0.2, options.get("Cardia derivative factor")) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) - annotationGroups = MeshType_3d_stomach1.generateBaseMesh(region, options) - self.assertEqual(8, len(annotationGroups)) + annotationGroups = scaffold.generateBaseMesh(region, options) + self.assertEqual(13, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) @@ -55,15 +59,15 @@ def test_stomach1(self): mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(823, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(341, nodes.getSize()) + self.assertEqual(342, 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, [-17.977095466754566, -15.437578891036395, -8.706694306455596], 1.0E-6) - assertAlmostEqualList(self, maximums, [17.943222678234513, 15.191836205539767, 8.725549026319936], 1.0E-6) + assertAlmostEqualList(self, minimums, [-18.535034704449842, -14.989550140413265, -8.726949180639382], 1.0E-6) + assertAlmostEqualList(self, maximums, [18.39909561216101, 15.187335864125645, 8.727618869278126], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -75,10 +79,89 @@ def test_stomach1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 2436.4955183926895, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 2452.212186914634, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 1168.9418891341106, delta=1.0E-6) + self.assertAlmostEqual(volume, 1175.367658574881, delta=1.0E-6) + + # check some annotationGroups: + expectedSizes3d = { + "body of stomach" : 28, + "cardia of stomach" : 12, + "duodenum" : 14, + "esophagus" : 24, + "fundus of stomach" : 38, + "pyloric antrum" : 28, + "pylorus": 14, + "stomach": 158 + } + for name in expectedSizes3d: + group = getAnnotationGroupForTerm(annotationGroups, get_stomach_term(name)) + size = group.getMeshGroup(mesh3d).getSize() + self.assertEqual(expectedSizes3d[name], size, name) + + # refine 4x4x4 and check result + # first remove any surface annotation groups as they are re-added by defineFaceAnnotations + removeAnnotationGroups = [] + for annotationGroup in annotationGroups: + if (not annotationGroup.hasMeshGroup(mesh3d)) and (annotationGroup.hasMeshGroup(mesh2d) or annotationGroup.hasMeshGroup(mesh1d)): + removeAnnotationGroups.append(annotationGroup) + + for annotationGroup in removeAnnotationGroups: + annotationGroups.remove(annotationGroup) + self.assertEqual(13, len(annotationGroups)) + + refineRegion = region.createRegion() + refineFieldmodule = refineRegion.getFieldmodule() + options['Refine number of elements surface'] = 4 + options['Refine number of elements through wall'] = 4 + meshrefinement = MeshRefinement(region, refineRegion, annotationGroups) + scaffold.refineMesh(meshrefinement, options) + annotationGroups = meshrefinement.getAnnotationGroups() + + refineFieldmodule.defineAllFaces() + oldAnnotationGroups = copy.copy(annotationGroups) + for annotationGroup in annotationGroups: + annotationGroup.addSubelements() + scaffold.defineFaceAnnotations(refineRegion, options, annotationGroups) + for annotation in annotationGroups: + if annotation not in oldAnnotationGroups: + annotationGroup.addSubelements() + self.assertEqual(16, len(annotationGroups)) +# + mesh3d = refineFieldmodule.findMeshByDimension(3) + self.assertEqual(10112, mesh3d.getSize()) + mesh2d = refineFieldmodule.findMeshByDimension(2) + self.assertEqual(33232, mesh2d.getSize()) + mesh1d = refineFieldmodule.findMeshByDimension(1) + self.assertEqual(36028, mesh1d.getSize()) + nodes = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + self.assertEqual(12936, nodes.getSize()) + datapoints = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) + self.assertEqual(0, datapoints.getSize()) + + # check some refined annotationGroups: + for name in expectedSizes3d: + group = getAnnotationGroupForTerm(annotationGroups, get_stomach_term(name)) + size = group.getMeshGroup(mesh3d).getSize() + self.assertEqual(expectedSizes3d[name]*64, size, name) + + # test finding a marker in refined scaffold + markerGroup = refineFieldmodule.findFieldByName("marker").castGroup() + refinedNodes = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + markerNodes = markerGroup.getFieldNodeGroup(refinedNodes).getNodesetGroup() + self.assertEqual(4, markerNodes.getSize()) + markerName = refineFieldmodule.findFieldByName("marker_name") + self.assertTrue(markerName.isValid()) + markerLocation = refineFieldmodule.findFieldByName("marker_location") + self.assertTrue(markerLocation.isValid()) + cache = refineFieldmodule.createFieldcache() + node = findNodeWithName(markerNodes, markerName, "gastro-esophagal junction on lesser curvature") + self.assertTrue(node.isValid()) + cache.setNode(node) + element, xi = markerLocation.evaluateMeshLocation(cache, 3) + self.assertEqual(1213, element.getIdentifier()) + assertAlmostEqualList(self, xi, [ 0.0, 1.0, 1.0 ], 1.0E-10) if __name__ == "__main__": unittest.main()