class MeshType_3d_colon1(Scaffold_base): ''' Generates a 3-D colon mesh with variable numbers of elements around, along the central line, and through wall. The colon is created by a function that generates a colon segment and uses tubemesh to map the segment along a central line profile. ''' centralPathDefaultScaffoldPackages = { 'Human 1' : ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings' : { 'Coordinate dimensions' : 3, 'Length' : 1.0, '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 ], [ [ [ 0.0, 0.0, 0.0 ], [ -50.7, 178.2, 0.0 ], [ -24.0, -6.0, -12.0 ], [ -14.0, -1.0, -12.0 ] ], [ [ -47.4, 188.6, 0.0 ], [ -19.3, 177.1, 0.0 ], [ -22.0, -4.0, -8.0 ], [ -4.0, 19.0, 22.0 ] ], [ [ -4.4, 396.5, 0.0 ], [ 206.0, 40.1, 0.0 ], [ -10.0, 20.0, 8.0 ], [ -6.0, 0.0, 51.0 ] ], [ [ 130.0, 384.1, 0.0 ], [ 130.8, -40.5, 0.0 ], [ -5.0, 4.0, 29.0 ], [ 0.0, 1.0, 24.0 ] ], [ [ 279.4, 383.0, 0.0 ], [ 118.0, 48.7, 0.0 ], [ -2.0, 10.0, 22.0 ], [ 5.0, 25.0, -20.0 ] ], [ [ 443.9, 390.8, 0.0 ], [ 111.3, -97.0, 0.0 ], [ 10.0, 17.0, 6.0 ], [ 1.0, -6.0, -35.0 ] ], [ [ 475.2, 168.0, 0.0 ], [ -0.8, -112.4, 0.0 ], [ 20.0, 0.0, -20.0 ], [ 15.0, -1.0, -10.0 ] ], [ [ 432.6, -32.3, 0.0 ], [ -90.5, -59.0, 0.0 ], [ 6.0, -9.0, -14.0 ], [ 8.0, -11.0, -13.0 ] ], [ [ 272.4, 7.5, 0.0 ], [ -79.0, 47.4, 0.0 ], [ 1.0, -11.0, -18.0 ], [ 4.0, -12.0, -12.0 ] ] ] ) } ), 'Human 2' : ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings' : { 'Coordinate dimensions' : 3, 'Length' : 1.0, '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 ], [ [ [ 0.0, 0.0, 0.0 ], [ -34.7, 104.1, -18.1 ], [ -24.0, -6.0, -12.0 ], [ -14.0, -1.0, -12.0 ] ], [ [ -34.5, 114.0, -18.1 ], [ 1.2, 86.6, -3.4 ], [ -22.0, -4.0, -8.0 ], [ -4.0, 19.0, 22.0 ] ], [ [ -19.1, 218.5, 5.5 ], [ 78.7, -7.1, 94.5 ], [ -10.0, 20.0, 8.0 ], [ -6.0, 0.0, 51.0 ] ], [ [ 82.5, 189.1, 94.2 ], [ 84.5, 7.1, 71.6 ], [ -5.0, 4.0, 29.0 ], [ 0.0, 1.0, 24.0 ] ], [ [ 226.6, 218.7, 85.7 ], [ 95.0, 91.3, -58.5 ], [ -2.0, 10.0, 22.0 ], [ 5.0, 25.0, -20.0 ] ], [ [ 325.5, 381.7, -57.9 ], [ 229.2, -66.7, -20.4 ], [ 10.0, 17.0, 6.0 ], [ 1.0, -6.0, -35.0 ] ], [ [ 354.0, 105.3, -24.4 ], [ -6.3, -143.7, 20.3 ], [ 20.0, 0.0, -20.0 ], [ 15.0, -1.0, -10.0 ] ], [ [ 296.5, -121.2, -0.6 ], [ -90.5, -59.0, 0.0 ], [ 6.0, -9.0, -14.0 ], [ 8.0, -11.0, -13.0 ] ], [ [ 169.8, -73.4, -33.5 ], [ -72.2, 43.4, -27.4 ], [ 1.0, -11.0, -18.0 ], [ 4.0, -12.0, -12.0 ] ] ] ) } ), 'Mouse 1' : ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings' : { 'Coordinate dimensions' : 3, '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 ], [ [ [ 0.0, 0.0, 0.0 ], [ 6.0, 12.0, -2.0 ], [ 2.0, 1.0, 2.0 ], [ 6.0, 0.0, 3.0 ] ], [ [ -2.0, 11.0, -3.0 ], [ -8.0, 4.0, 9.0 ], [ 2.0, 2.0, 1.0 ], [ 0.0, 1.0, 2.0 ] ], [ [ -3.0, 2.0, 3.0 ], [ -4.0, -8.0, 0.0 ], [ 2.0, -1.0, 2.0 ], [ 1.0, 0.0, 2.0 ] ], [ [ -11.0, -3.0, -4.0 ], [ -8.0, -3.0, -7.0 ], [ 1.0, -2.0, 1.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -16.0, -4.0, 0.0 ], [ 4.0, -3.0, 14.0 ], [ 1.0, -3.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -7.0, -8.0, 0.0 ], [ 5.0, -1.0, -14.0 ], [ 0.0, -3.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -1.0, -6.0, -1.0 ], [ 2.0, -2.0, 9.0 ], [ 1.0, -3.0, -1.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -2.0, -14.0, 5.0 ], [ -2.0, -4.0, 2.0 ], [ 1.0, -2.0, -2.0 ], [ 0.0, 0.0, 0.5 ] ] ] ) } ), 'Mouse 2' : ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings' : { 'Coordinate dimensions' : 3, '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 ], [ [ [ 0.0, 0.0, 0.0 ], [ 0.0, 0.0, 13.0 ], [ 0.0, -10.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 0.0, 0.0, 13.0 ], [ 0.0, 2.0, 28.0 ], [ 0.0, -10.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -14.0, -2.0, 13.0 ], [ 0.0, -3.0, -19.0 ], [ 0.0, -10.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -14.0, -1.0, -10.0 ], [ 1.0, 1.0, -17.0 ], [ 0.0, -10.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -14.0, 0.0, -28.0 ], [ 0.0, 0.0, -11.0 ], [ 0.0, -10.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ] ] ) } ), 'Pig 1' : ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings' : { 'Coordinate dimensions' : 3, 'Length' : 1.0, 'Number of elements' : 36 }, 'meshEdits' : exnodeStringFromNodeValues( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2 ], [ [ [ -7.2, 83.3, -20.7 ], [ -65.2, -8.1, 7.6 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -68.5, 52.8, -9.6 ], [ -40.1, -36.1, 10.7 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -97.4, -26.3, 5.7 ], [ 18.0, -93.2, 13.7 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -56.8, -90.5, 14.1 ], [ 65.5, -41.4, 7.3 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 48.9, -100.8, 24.0 ], [ 112.2, 40.1, 19.0 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 114.8, -12.6, 38.7 ], [ 8.2, 96.1, 14.2 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 60.3, 83.5, 43.7 ], [ -108.7, 54.1, 22.4 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -41.2, 90.7, 56.3 ], [ -89.0, -32.4, 14.4 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -107.9, -9.7, 76.6 ], [ 11.1, -94.4, 11.3 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -57.3, -91.9, 81.3 ], [ 71.2, -31.2, 5.7 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 51.2, -89.4, 97.2 ], [ 99.1, 55.4, 12.9 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 91.6, 9.3, 103.6 ], [ 4.7, 51.2, 3.4 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 61.6, 111.8, 109.6 ], [ -85.2, 46.1, 2.6 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -54.6, 91.9, 129.4 ], [ -92.7, -55.0, 14.5 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -109.0, 5.6, 156.9 ], [ 23.6, -108.2, 27.7 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -59.1, -62.5, 170.8 ], [ 74.0, -20.1, 14.4 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 23.5, -53.2, 179.7 ], [ 84.6, 47.0, 6.9 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 62.3, 30.1, 187.5 ], [ -12.8, 58.0, 0.8 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 22.4, 45.2, 181.1 ], [ -23.6, -34.5, -7.4 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -1.9, 4.9, 180.5 ], [ -41.3, -30.9, 7.5 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -45.1, -12.6, 194.4 ], [ -40.5, -4.6, 6.9 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -71.7, -2.2, 197.2 ], [ -25.2, 35.8, -6.8 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -65.8, 42.1, 182.3 ], [ 26.6, 37.6, -15.6 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -14.1, 81.2, 163.5 ], [ 41.0, 10.3, -9.5 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 61.7, 86.1, 156.4 ], [ 77.9, -40.7, 8.9 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 92.9, 20.5, 150.3 ], [ 0.0, -73.3, -5.2 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 48.9, -65.0, 142.8 ], [ -82.8, -80.0, -1.9 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -54.3, -90.8, 134.0 ], [ -60.1, 26.4, -8.2 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -89.9, 11.2, 115.0 ], [ 34.9, 125.1, -27.9 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -17.4, 74.2, 91.1 ], [ 78.8, 19.1, -15.4 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 43.4, 50.2, 73.3 ], [ 30.2, -36.0, -9.9 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 62.4, -5.1, 63.5 ], [ 10.9, -54.2, -2.7 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 32.7, -51.7, 56.1 ], [ -38.6, -29.8, -8.1 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -38.1, -28.6, 46.8 ], [ -66.0, 83.3, -12.1 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -5.4, 32.0, 26.0 ], [ 48.1, 17.6, -21.4 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 146.6, 101.2, -41.2 ], [ 63.3, 35.3, -31.2 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ 312.3, 199.5, -123.4 ], [ 39.7, 24.3, -20.0 ], [ 0.0, 0.0, 5.0 ], [ 0.0, 0.0, 0.5 ] ] ] ) } ), 'Pig 2': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'Length': 90.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], [ [ [ 0.0, 0.0, 0.0 ], [ 30.0, 0.0, 0.0 ], [ 0.0, 1.0, 0.0 ], [ 0.0, 0.0, 0.0 ] ], [ [ 30.0, 0.0, 0.0 ], [ 30.0, 0.0, 0.0 ], [ 0.0, 1.0, 0.0 ], [ 0.0, 0.0, 0.0 ] ], [ [ 60.0, 0.0, 0.0 ], [ 30.0, 0.0, 0.0 ], [ 0.0, 1.0, 0.0 ], [ 0.0, 0.0, 0.0 ] ], [ [ 90.0, 0.0, 0.0 ], [ 30.0, 0.0, 0.0 ], [ 0.0, 1.0, 0.0 ], [ 0.0, 0.0, 0.0 ] ] ] ) } ), } @staticmethod def getName(): return '3D Colon 1' @staticmethod def getParameterSetNames(): return [ 'Default', 'Human 1', 'Human 2', 'Mouse 1', 'Mouse 2', 'Pig 1', 'Pig 2'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 2'] elif 'Mouse 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 1'] elif 'Mouse 2' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 2'] elif 'Pig 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 1'] elif 'Pig 2' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 2'] else: centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] if 'Mouse' in parameterSetName: segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName = 'Mouse 1') elif 'Pig' in parameterSetName: segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName = 'Pig 1') else: segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName = 'Human 1') options = { 'Central path' : copy.deepcopy(centralPathOption), 'Segment profile' : segmentProfileOption, 'Number of segments': 30, 'Start phase': 0.0, 'Proximal length': 420.0, 'Transverse length': 460.0, 'Distal length': 620.0, 'Proximal inner radius': 43.5, 'Proximal tenia coli width': 10.0, 'Proximal-transverse inner radius': 33.0, 'Proximal-transverse tenia coli width': 10.0, 'Transverse-distal inner radius': 29.0, 'Transverse-distal tenia coli width': 10.0, 'Distal inner radius': 31.5, 'Distal tenia coli width': 10.0, 'Refine' : False, 'Refine number of elements around' : 1, 'Refine number of elements along' : 1, 'Refine number of elements through wall' : 1 } if 'Human 2' in parameterSetName: options['Proximal length'] = 180.0 options['Transverse length'] = 620.0 options['Distal length'] = 700.0 elif 'Mouse' in parameterSetName: options['Number of segments'] = 10 options['Proximal length'] = 30.0 options['Transverse length'] = 20.0 options['Distal length'] = 25.0 options['Proximal inner radius'] = 1.0 options['Proximal tenia coli width'] = 0.5 options['Proximal-transverse inner radius'] = 0.9 options['Proximal-transverse tenia coli width'] = 0.7 options['Transverse-distal inner radius'] = 0.7 options['Transverse-distal tenia coli width'] = 1.0 options['Distal inner radius'] = 0.7 options['Distal tenia coli width'] = 1.0 elif 'Pig 1' in parameterSetName: options['Number of segments'] = 120 options['Proximal length'] = 3000.0 options['Transverse length'] = 200.0 options['Distal length'] = 200.0 options['Proximal inner radius'] = 38.0 options['Proximal tenia coli width'] = 5.0 options['Proximal-transverse inner radius'] = 14.0 options['Proximal-transverse tenia coli width'] = 4.0 options['Transverse-distal inner radius'] = 10.5 options['Transverse-distal tenia coli width'] = 3.0 options['Distal inner radius'] = 8.0 options['Distal tenia coli width'] = 1.5 elif 'Pig 2' in parameterSetName: options['Number of segments'] = 3 options['Proximal length'] = 30.0 options['Transverse length'] = 30.0 options['Distal length'] = 30.0 options['Proximal inner radius'] = 16.0 options['Proximal tenia coli width'] = 5.0 options['Proximal-transverse inner radius'] = 16.0 options['Proximal-transverse tenia coli width'] = 5.0 options['Transverse-distal inner radius'] = 16.0 options['Transverse-distal tenia coli width'] = 5.0 options['Distal inner radius'] = 16.0 options['Distal tenia coli width'] = 5.0 return options @staticmethod def getOrderedOptionNames(): return [ 'Central path', 'Segment profile', 'Number of segments', 'Start phase', 'Proximal length', 'Transverse length', 'Distal length', 'Proximal inner radius', 'Proximal tenia coli width', 'Proximal-transverse inner radius', 'Proximal-transverse tenia coli width', 'Transverse-distal inner radius', 'Transverse-distal tenia coli width', 'Distal inner radius', 'Distal tenia coli width', '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 == 'Segment profile': return [ MeshType_3d_colonsegment1 ] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.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 == 'Segment profile': if not parameterSetName: parameterSetName = scaffoldType.getParameterSetNames()[0] return ScaffoldPackage(scaffoldType, defaultParameterSetName = 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['Segment profile'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Segment profile'): options['Segment profile'] = cls.getOptionScaffoldPackage('Segment profile', MeshType_3d_colonsegment1) for key in [ 'Number of segments', 'Refine number of elements around', 'Refine number of elements along', 'Refine number of elements through wall']: if options[key] < 1: options[key] = 1 for key in [ 'Proximal length', 'Transverse length', 'Distal length', 'Proximal inner radius', 'Proximal tenia coli width', 'Proximal-transverse inner radius', 'Proximal-transverse tenia coli width', 'Transverse-distal inner radius', 'Transverse-distal tenia coli width', 'Distal inner radius', 'Distal tenia coli width']: if options[key] < 0.0: options[key] = 0.0 @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: annotationGroups """ centralPath = options['Central path'] segmentProfile = options['Segment profile'] segmentCount = options['Number of segments'] startPhase = options['Start phase'] % 360.0 proximalLength = options['Proximal length'] transverseLength = options['Transverse length'] proximalInnerRadius = options['Proximal inner radius'] proximalTCWidth = options['Proximal tenia coli width'] proximalTransverseInnerRadius = options['Proximal-transverse inner radius'] proximalTransverseTCWidth = options['Proximal-transverse tenia coli width'] transverseDistalInnerRadius = options['Transverse-distal inner radius'] transverseDistalTCWidth = options['Transverse-distal tenia coli width'] distalInnerRadius = options['Distal inner radius'] distalTCWidth = options['Distal tenia coli width'] segmentSettings = segmentProfile.getScaffoldSettings() elementsCountAroundTC = segmentSettings['Number of elements around tenia coli'] elementsCountAroundHaustrum = segmentSettings['Number of elements around haustrum'] cornerInnerRadiusFactor = segmentSettings['Corner inner radius factor'] haustrumInnerRadiusFactor = segmentSettings['Haustrum inner radius factor'] segmentLengthEndDerivativeFactor = segmentSettings['Segment length end derivative factor'] segmentLengthMidDerivativeFactor = segmentSettings['Segment length mid derivative factor'] tcCount = segmentSettings['Number of tenia coli'] tcThickness = segmentSettings['Tenia coli thickness'] elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum)*tcCount elementsCountAlongSegment = segmentSettings['Number of elements along segment'] elementsCountThroughWall = segmentSettings['Number of elements through wall'] wallThickness = segmentSettings['Wall thickness'] useCrossDerivatives = segmentSettings['Use cross derivatives'] useCubicHermiteThroughWall = not(segmentSettings['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment*segmentCount) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections = True, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength(cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount # print('Length = ', length) elementAlongLength = length / elementsCountAlong # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) # Generate variation of radius & tc width along length lengthList = [0.0, proximalLength, proximalLength + transverseLength, length] innerRadiusList = [proximalInnerRadius, proximalTransverseInnerRadius, transverseDistalInnerRadius, distalInnerRadius] innerRadiusAlongElementList, dInnerRadiusAlongElementList = interp.sampleParameterAlongLine(lengthList, innerRadiusList, elementsCountAlong) tcWidthList = [proximalTCWidth, proximalTransverseTCWidth, transverseDistalTCWidth, distalTCWidth] tcWidthAlongElementList, dTCWidthAlongElementList = interp.sampleParameterAlongLine(lengthList, tcWidthList, elementsCountAlong) # Account for reduced haustrum appearance in transverse and distal pig colon if tcCount == 2: haustrumInnerRadiusFactorList = [haustrumInnerRadiusFactor, haustrumInnerRadiusFactor*0.75, haustrumInnerRadiusFactor*0.5, haustrumInnerRadiusFactor*0.2] haustrumInnerRadiusFactorAlongElementList = \ interp.sampleParameterAlongLine(lengthList, haustrumInnerRadiusFactorList, elementsCountAlong)[0] else: haustrumInnerRadiusFactorAlongElementList = [haustrumInnerRadiusFactor]*(elementsCountAlong+1) # Create annotation groups for colon sections elementsAlongInProximal = round(proximalLength/elementAlongLength) elementsAlongInTransverse = round(transverseLength/elementAlongLength) elementsAlongInDistal = elementsCountAlong - elementsAlongInProximal - elementsAlongInTransverse elementsCountAlongGroups = [elementsAlongInProximal, elementsAlongInTransverse, elementsAlongInDistal] colonGroup = AnnotationGroup(region, get_colon_term("colon")) if tcCount == 1: proximalGroup = AnnotationGroup(region, get_colon_term("proximal colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) distalGroup = AnnotationGroup(region, get_colon_term("distal colon")) annotationGroupAlong = [[colonGroup, proximalGroup], [colonGroup, transverseGroup], [colonGroup, distalGroup]] elif tcCount == 2: spiralGroup = AnnotationGroup(region, get_colon_term("spiral colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) distalGroup = AnnotationGroup(region, get_colon_term("distal colon")) annotationGroupAlong = [[colonGroup, spiralGroup], [colonGroup, transverseGroup], [colonGroup, distalGroup]] elif tcCount == 3: ascendingGroup = AnnotationGroup(region, get_colon_term("ascending colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) descendingGroup = AnnotationGroup(region, get_colon_term("descending colon")) annotationGroupAlong = [[colonGroup, ascendingGroup], [colonGroup, transverseGroup], [colonGroup, descendingGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsThroughWall = [] for i in range(elementsCountThroughWall): annotationGroupsThroughWall.append([ ]) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] sxRefExtrudeList = [] # Create object colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongElementList, innerRadiusAlongElementList, dInnerRadiusAlongElementList, tcWidthAlongElementList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) # Project reference point for warping onto central path start = nSegment * elementsCountAlongSegment end = (nSegment + 1) * elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xInner, elementsCountAround, elementsCountAlongSegment, segmentLength, sx[start:end], sd1[start:end], sd2[start:end], sd12[start:end]) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList, innerRadiusAlongElementList[start:end], closedProximalEnd=False) # Store points along length xExtrude += xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:] d1Extrude += d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:] d2Extrude += d2WarpedList if nSegment == 0 else d2WarpedList[elementsCountAround:] d3UnitExtrude += d3WarpedUnitList if nSegment == 0 else d3WarpedUnitList[elementsCountAround:] sxRefExtrudeList += sxRefList if nSegment == 0 else sxRefList[elementsCountAround:] contractedWallThicknessList = colonSegmentTubeMeshInnerPoints.getContractedWallThicknessList() # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, contractedWallThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) relaxedLengthList, xiList = colonSegmentTubeMeshInnerPoints.getRelaxedLengthAndXiList() closedProximalEnd = False if tcThickness > 0: tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() xList, d1List, d2List, d3List, annotationArrayAround = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tubeTCWidthList, tcThickness, sxRefExtrudeList, annotationGroupsAround, closedProximalEnd) # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = createFlatAndTextureCoordinatesTeniaColi( xiList, relaxedLengthList, length, wallThickness, tcCount, tcThickness, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, transitElementList, closedProximalEnd) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) else: # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, relaxedLengthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) return annotationGroups @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 test_smallintestine1(self): """ Test creation of small intestine scaffold. """ parameterSetNames = MeshType_3d_smallintestine1.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Mouse 1"]) centralPathDefaultScaffoldPackages = { 'Test line': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { 'D2 derivatives': True, 'Coordinate dimensions': 3, '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], [ [[-2.3, 18.5, -4.4], [-4.2, -0.8, 3.7], [0.0, 5.0, 0.0], [0.0, 0.0, 0.5]], [[-8.6, 16.3, -0.4], [-7.1, -2.7, 1.6], [0.0, 5.0, 0.0], [0.0, 0.0, 0.5]], [[-18.3, 12.6, -1.5], [-6.4, -1.7, -3.8], [0.0, 5.0, 0.0], [0.0, 0.0, 0.5]], [[-15.6, 13.7, -6.1], [7.0, 2.1, -1.8], [0.0, 5.0, 0.0], [0.0, 0.0, 0.5]]]) }) } centralPathOption = centralPathDefaultScaffoldPackages['Test line'] options = MeshType_3d_smallintestine1.getDefaultOptions("Mouse 1") options['Central path'] = copy.deepcopy(centralPathOption) options['Number of segments'] = 4 options['Duodenum length'] = 5.0 options['Jejunum length'] = 15.0 options['Ileum length'] = 5.0 self.assertEqual(19, len(options)) centralPath = options['Central path'] self.assertEqual(4, options.get("Number of segments")) self.assertEqual(8, options.get("Number of elements around")) self.assertEqual(4, options.get("Number of elements along segment")) self.assertEqual(1, options.get("Number of elements through wall")) self.assertEqual(5.0, options.get("Duodenum length")) self.assertEqual(5.0, options.get("Ileum length")) self.assertEqual(0.6, options.get("Duodenum inner radius")) self.assertEqual(1.0, options.get("Jejunum-ileum inner radius")) self.assertEqual(0.1, options.get("Wall thickness")) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx = extractPathParametersFromRegion(tmpRegion, [Node.VALUE_LABEL_VALUE])[0] self.assertEqual(4, len(cx)) assertAlmostEqualList(self, cx[0], [-2.3, 18.5, -4.4], 1.0E-6) assertAlmostEqualList(self, cx[2], [-18.3, 12.6, -1.5], 1.0E-6) del tmpRegion annotationGroups = MeshType_3d_smallintestine1.generateBaseMesh(region, options) self.assertEqual(4, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) self.assertEqual(128, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) self.assertEqual(520, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(664, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) self.assertEqual(272, 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, [-20.06978981419564, 11.406595205949705, -7.1653294859433965], 1.0E-6) assertAlmostEqualList(self, maximums, [-1.8300388314851923, 19.193885338090105, 0.9772071374844936], 1.0E-6) flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement() self.assertTrue(flatCoordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(flatCoordinates, nodes) assertAlmostEqualList(self, minimums, [-1.39038154442654, 0.0, 0.0], 1.0E-6) assertAlmostEqualList(self, maximums, [4.891237158967401, 25.293706698841913, 0.1], 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) flatSurfaceAreaField = fieldmodule.createFieldMeshIntegral(one, flatCoordinates, faceMeshGroup) flatSurfaceAreaField.setNumbersOfPoints(4) fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(surfaceArea, 171.27464080337143, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 16.35219225882822, delta=1.0E-6) result, flatSurfaceArea = flatSurfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(flatSurfaceArea, 171.37026123844635, delta=1.0E-3)
def test_colon1(self): """ Test creation of colon scaffold. """ parameterSetNames = MeshType_3d_colon1.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Mouse 1", "Mouse 2", "Pig 1", "Pig 2"]) centralPathDefaultScaffoldPackages = { 'Test line': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'Length': 1.0, 'Number of elements': 1 }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2], [ [[163.7, -25.2, 12.2], [-21.7, 50.1, -18.1], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[117.2, 32.8, -2.6], [-64.3, 34.4, -3.9], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]]]) }) } centralPathOption = centralPathDefaultScaffoldPackages['Test line'] segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { 'Central path': copy.deepcopy(centralPathOption), 'Segment profile': segmentProfileOption, 'Number of segments': 3, 'Start phase': 0.0, 'Proximal length': 25.0, 'Transverse length': 25.0, 'Distal length': 25.0, 'Proximal inner radius': 20.0, 'Proximal tenia coli width': 8.0, 'Proximal-transverse inner radius': 18.0, 'Proximal-transverse tenia coli width': 6.0, 'Transverse-distal inner radius': 16.0, 'Transverse-distal tenia coli width': 5.0, 'Distal inner radius': 15.0, 'Distal tenia coli width': 5.0, 'Refine': False, 'Refine number of elements around': 1, 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } self.assertEqual(19, len(options)) centralPath = options['Central path'] segmentProfile = options.get("Segment profile") segmentSettings = segmentProfile.getScaffoldSettings() self.assertEqual(8, segmentSettings.get("Number of elements around haustrum")) self.assertEqual(0.5, segmentSettings.get("Corner inner radius factor")) self.assertEqual(0.5, segmentSettings.get("Haustrum inner radius factor")) self.assertEqual(0.5, segmentSettings.get("Segment length end derivative factor")) self.assertEqual(3, segmentSettings.get("Number of tenia coli")) self.assertEqual(1.6, segmentSettings.get("Tenia coli thickness")) self.assertEqual(3, options.get("Number of segments")) self.assertEqual(0.0, options.get("Start phase")) self.assertEqual(25.0, options.get("Transverse length")) self.assertEqual(20.0, options.get("Proximal inner radius")) self.assertEqual(6.0, options.get("Proximal-transverse tenia coli width")) self.assertEqual(16.0, options.get("Transverse-distal inner radius")) self.assertEqual(5.0, options.get("Distal tenia coli width")) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx = extractPathParametersFromRegion(tmpRegion)[0] self.assertEqual(2, len(cx)) assertAlmostEqualList(self, cx[0], [ 163.7, -25.2, 12.2 ], 1.0E-6) assertAlmostEqualList(self, cx[1], [ 117.2, 32.8, -2.6 ], 1.0E-6) del tmpRegion annotationGroups = MeshType_3d_colon1.generateBaseMesh(region, options) self.assertEqual(7, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) if annotationGroups is not None: for annotationGroup in annotationGroups: annotationGroup.addSubelements() mesh3d = fieldmodule.findMeshByDimension(3) self.assertEqual(432, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) self.assertEqual(1656, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) self.assertEqual(2043, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) self.assertEqual(819, 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, [ 108.0250647983898, -36.876103983560014, -25.89741158325083 ], 1.0E-6) assertAlmostEqualList(self, maximums, [ 185.46457506220003, 48.101157490744, 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, 77.4178187926561, 3.2000000000000006 ], 1.0E-6) textureCoordinates = fieldmodule.findFieldByName("texture coordinates").castFiniteElement() minimums, maximums = evaluateFieldNodesetRange(textureCoordinates, nodes) assertAlmostEqualList(self, minimums, [ 0.0, 0.0, 0.0 ], 1.0E-6) assertAlmostEqualList(self, maximums, [ 0.9812471574796385, 1.0, 2.0 ], 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, 14612.416788520026, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 26826.069540921028, delta=1.0E-6)
class MeshType_3d_esophagus1(Scaffold_base): """ Generates a 3-D esophagus mesh with variable numbers of elements around, along the central line, and through wall. The esophagus is created by a function that generates an elliptical tube segment and uses tubemesh to map the segment along a central path profile. """ centralPathDefaultScaffoldPackages = { 'Human 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 ], [[[7.5, 289.8, 0.0], [2.8, -33.6, 0.0], [9.9, 0.8, 0.0], [0.1, -1.6, 0.0], [0.0, 0.0, 10.0], [0.0, 0.0, 0.0]], [[8.9, 242.5, 0.0], [-2.6, -87.5, 0.0], [10.0, -0.3, 0.0], [0.1, -0.6, 0.0], [0.0, 0.0, 10.0], [0.0, 0.0, 0.0]], [[-2.5, 115.4, 0.0], [3.9, -102.0, 0.0], [10.0, 0.4, 0.0], [-0.3, 1.9, 0.0], [0.0, 0.0, 10.0], [0.0, 0.0, 0.0]], [[10.1, 40.3, 0.0], [17.8, -57.9, 0.0], [9.6, 2.9, 0.0], [-1.3, 3.2, 0.0], [0.0, 0.0, 10.0], [0.0, 0.0, 0.0]], [[28.6, -0.1, 0.0], [18.5, -22.1, 0.0], [7.7, 6.5, 0.0], [-2.4, 3.9, 0.0], [0.0, 0.0, 10.0], [0.0, 0.0, 0.0]]]), 'userAnnotationGroups': [{ '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1', 'name': get_esophagus_term('cervical part of esophagus')[0], 'ontId': get_esophagus_term('cervical part of esophagus')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '2-3', 'name': get_esophagus_term('thoracic part of esophagus')[0], 'ontId': get_esophagus_term('thoracic part of esophagus')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '4', 'name': get_esophagus_term('abdominal part of esophagus')[0], 'ontId': get_esophagus_term('abdominal part of esophagus')[1] }] }) } @staticmethod def getName(): return '3D Esophagus 1' @staticmethod def getParameterSetNames(): return ['Default', 'Human 1'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] options = { 'Central path': copy.deepcopy(centralPathOption), 'Number of elements around': 8, 'Number of elements along': 12, 'Number of elements through wall': 4, 'Wall thickness': 5.0, # 3.0mm when relaxed 'Mucosa relative thickness': 0.35, 'Submucosa relative thickness': 0.15, 'Circular muscle layer relative thickness': 0.25, 'Longitudinal muscle layer relative thickness': 0.25, 'Use cross derivatives': False, 'Use linear through wall': True, 'Refine': False, 'Refine number of elements around': 1, 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } return options @staticmethod def getOrderedOptionNames(): return [ 'Central path', 'Number of elements around', 'Number of elements along', 'Number of elements through wall', 'Wall thickness', 'Mucosa relative thickness', 'Submucosa relative thickness', 'Circular muscle layer relative thickness', 'Longitudinal muscle layer relative thickness', '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] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.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]) 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 options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 for key in [ 'Number of elements around', 'Number of elements along', '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 if options['Wall thickness'] < 0.0: options['Wall thickness'] = 0.0 @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: annotationGroups """ centralPath = options['Central path'] elementsCountAround = options['Number of elements around'] elementsCountAlong = options['Number of elements along'] elementsCountThroughWall = options['Number of elements through wall'] wallThickness = options['Wall thickness'] mucosaRelThickness = options['Mucosa relative thickness'] submucosaRelThickness = options['Submucosa relative thickness'] circularRelThickness = options[ 'Circular muscle layer relative thickness'] longitudinalRelThickness = options[ 'Longitudinal muscle layer relative thickness'] useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not (options['Use linear through wall']) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path esophagusTermsAlong = [ None, 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus' ] arcLengthOfGroupsAlong = [] for i in range(len(esophagusTermsAlong)): tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ extractPathParametersFromRegion(tmpRegion, [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D2_DS1DS3], groupName=esophagusTermsAlong[i]) arcLength = 0.0 for e in range(len(cxGroup) - 1): arcLength += interp.getCubicHermiteArcLength( cxGroup[e], cd1Group[e], cxGroup[e + 1], cd1Group[e + 1]) arcLengthOfGroupsAlong.append(arcLength) if i == 0: cx = cxGroup cd1 = cd1Group cd2 = cd2Group cd3 = cd3Group cd12 = cd12Group cd13 = cd13Group del tmpRegion # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves( cx, cd1, elementsCountAlong) sd2, sd12 = interp.interpolateSampleCubicHermite( cd2, cd12, se, sxi, ssf) sd3, sd13 = interp.interpolateSampleCubicHermite( cd3, cd13, se, sxi, ssf) centralPathLength = arcLengthOfGroupsAlong[0] elementAlongLength = centralPathLength / elementsCountAlong elementsCountAlongGroups = [] groupLength = 0.0 e = 0 elementsCount = 1 length = elementAlongLength for i in range(1, len(esophagusTermsAlong)): groupLength += arcLengthOfGroupsAlong[i] if e == elementsCountAlong - 2: elementsCount += 1 elementsCountAlongGroups.append(elementsCount) else: while length < groupLength: elementsCount += 1 e += 1 length += elementAlongLength # check which end is grouplength closer to distToUpperEnd = abs(length - groupLength) distToLowerEnd = abs(groupLength - (length - elementsCountAlong)) if distToLowerEnd < distToUpperEnd: elementsCount -= 1 elementsCountAlongGroups.append(elementsCount) e -= 1 length -= elementAlongLength else: elementsCountAlongGroups.append(elementsCount) elementsCount = 0 majorRadiusElementList = sd2 minorRadiusElementList = sd3 # Create annotation groups along esophagus esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) cervicalGroup = AnnotationGroup( region, get_esophagus_term("cervical part of esophagus")) thoracicGroup = AnnotationGroup( region, get_esophagus_term("thoracic part of esophagus")) abdominalGroup = AnnotationGroup( region, get_esophagus_term("abdominal part of esophagus")) annotationGroupAlong = [[esophagusGroup, cervicalGroup], [esophagusGroup, thoracicGroup], [esophagusGroup, abdominalGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsAround = [] for i in range(elementsCountAround): annotationGroupsAround.append([]) # Groups through wall longitudinalMuscleGroup = AnnotationGroup( region, get_esophagus_term("esophagus smooth muscle longitudinal layer")) circularMuscleGroup = AnnotationGroup( region, get_esophagus_term("esophagus smooth muscle circular layer")) submucosaGroup = AnnotationGroup( region, get_esophagus_term("submucosa of esophagus")) mucosaGroup = AnnotationGroup(region, get_esophagus_term("esophagus mucosa")) if elementsCountThroughWall == 1: relativeThicknessList = [1.0] annotationGroupsThroughWall = [[]] else: relativeThicknessList = [ mucosaRelThickness, submucosaRelThickness, circularRelThickness, longitudinalRelThickness ] annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], [longitudinalMuscleGroup]] xToSample = [] d1ToSample = [] for n2 in range(elementsCountAlong + 1): # Create inner points cx = [0.0, 0.0, elementAlongLength * n2] axis1 = [vector.magnitude(majorRadiusElementList[n2]), 0.0, 0.0] axis2 = [0.0, vector.magnitude(minorRadiusElementList[n2]), 0.0] xInner, d1Inner = geometry.createEllipsePoints(cx, 2 * math.pi, axis1, axis2, elementsCountAround, startRadians=0.0) xToSample += xInner d1ToSample += d1Inner d2ToSample = [[0.0, 0.0, elementAlongLength] ] * (elementsCountAround * (elementsCountAlong + 1)) # Sample along length xInnerRaw = [] d2InnerRaw = [] xToWarp = [] d1ToWarp = [] d2ToWarp = [] flatWidthList = [] xiList = [] for n1 in range(elementsCountAround): xForSamplingAlong = [] d2ForSamplingAlong = [] for n2 in range(elementsCountAlong + 1): idx = n2 * elementsCountAround + n1 xForSamplingAlong.append(xToSample[idx]) d2ForSamplingAlong.append(d2ToSample[idx]) xSampled, d2Sampled = interp.sampleCubicHermiteCurves( xForSamplingAlong, d2ForSamplingAlong, elementsCountAlong, arcLengthDerivatives=True)[0:2] xInnerRaw.append(xSampled) d2InnerRaw.append(d2Sampled) # Re-arrange sample order & calculate dx_ds1 and dx_ds3 from dx_ds2 for n2 in range(elementsCountAlong + 1): xAround = [] d2Around = [] for n1 in range(elementsCountAround): x = xInnerRaw[n1][n2] d2 = d2InnerRaw[n1][n2] xAround.append(x) d2Around.append(d2) d1Around = [] for n1 in range(elementsCountAround): v1 = xAround[n1] v2 = xAround[(n1 + 1) % elementsCountAround] d1 = d2 = [v2[c] - v1[c] for c in range(3)] arcLengthAround = interp.computeCubicHermiteArcLength( v1, d1, v2, d2, True) dx_ds1 = [c * arcLengthAround for c in vector.normalise(d1)] d1Around.append(dx_ds1) d1Smoothed = interp.smoothCubicHermiteDerivativesLoop( xAround, d1Around) xToWarp += xAround d1ToWarp += d1Smoothed d2ToWarp += d2Around # Flat width and xi flatWidth = 0.0 xiFace = [] for n1 in range(elementsCountAround): v1 = xAround[n1] d1 = d1Smoothed[n1] v2 = xAround[(n1 + 1) % elementsCountAround] d2 = d1Smoothed[(n1 + 1) % elementsCountAround] flatWidth += interp.getCubicHermiteArcLength(v1, d1, v2, d2) flatWidthList.append(flatWidth) for n1 in range(elementsCountAround + 1): xi = 1.0 / elementsCountAround * n1 xiFace.append(xi) xiList.append(xiFace) # Project reference point for warping onto central path sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, centralPathLength, sx, sd1, sd2, sd12) # Warp points segmentAxis = [0.0, 0.0, 1.0] closedProximalEnd = False innerRadiusAlong = [] for n2 in range(elementsCountAlong + 1): firstNodeAlong = xToWarp[n2 * elementsCountAround] midptSegmentAxis = [0.0, 0.0, elementAlongLength * n2] radius = vector.magnitude(firstNodeAlong[c] - midptSegmentAxis[c] for c in range(3)) innerRadiusAlong.append(radius) xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = \ tubemesh.warpSegmentPoints(xToWarp, d1ToWarp, d2ToWarp, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlong, zRefList, innerRadiusAlong, closedProximalEnd) # Create coordinates and derivatives transitElementList = [0] * elementsCountAround xList, d1List, d2List, d3List, curvatureList = \ tubemesh.getCoordinatesFromInner(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, [wallThickness]*(elementsCountAlong+1), relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create flat coordinates xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( xiList, flatWidthList, length, wallThickness, relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements xOrgan = [] d1Organ = [] d2Organ = [] nodeIdentifier, elementIdentifier, annotationGroups = \ tubemesh.createNodesAndElements(region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) # annotation fiducial points fm = region.getFieldmodule() fm.beginChange() mesh = fm.findMeshByDimension(3) cache = fm.createFieldcache() markerGroup = findOrCreateFieldGroup(fm, "marker") markerName = findOrCreateFieldStoredString(fm, name="marker_name") markerLocation = findOrCreateFieldStoredMeshLocation( fm, mesh, name="marker_location") nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() markerTemplateInternal = nodes.createNodetemplate() markerTemplateInternal.defineField(markerName) markerTemplateInternal.defineField(markerLocation) markerNames = [ "proximodorsal midpoint on serosa of upper esophageal sphincter", "proximoventral midpoint on serosa of upper esophageal sphincter", "distal point of lower esophageal sphincter serosa on the greater curvature of stomach", "distal point of lower esophageal sphincter serosa on the lesser curvature of stomach" ] totalElements = elementIdentifier radPerElementAround = math.pi * 2.0 / elementsCountAround elementAroundHalfPi = int(0.25 * elementsCountAround) xi1HalfPi = (math.pi * 0.5 - radPerElementAround * elementAroundHalfPi) / radPerElementAround elementAroundPi = int(0.5 * elementsCountAround) xi1Pi = (math.pi - radPerElementAround * elementAroundPi) / radPerElementAround markerElementIdentifiers = [ elementsCountAround * elementsCountThroughWall - elementAroundHalfPi, elementAroundHalfPi + 1 + elementsCountAround * (elementsCountThroughWall - 1), totalElements - elementsCountAround, totalElements - elementsCountAround + elementAroundPi ] markerXis = [[1.0 - xi1HalfPi, 0.0, 1.0], [xi1HalfPi, 0.0, 1.0], [0.0, 1.0, 1.0], [xi1Pi, 1.0, 1.0]] for n in range(len(markerNames)): markerGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_esophagus_term(markerNames[n])) markerElement = mesh.findElementByIdentifier( markerElementIdentifiers[n]) markerXi = markerXis[n] cache.setMeshLocation(markerElement, markerXi) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) markerName.assignString(cache, markerGroup.getName()) markerLocation.assignMeshLocation(cache, markerElement, markerXi) for group in [esophagusGroup, markerGroup]: group.getNodesetGroup(nodes).addNode(markerPoint) fm.endChange() return annotationGroups @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 @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. ''' # Create 2d surface mesh groups fm = region.getFieldmodule() mesh2d = fm.findMeshByDimension(2) esophagusGroup = getAnnotationGroupForTerm( annotationGroups, get_esophagus_term("esophagus")) is_exterior = fm.createFieldIsExterior() is_exterior_face_xi3_1 = fm.createFieldAnd( is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) is_esophagus = esophagusGroup.getFieldElementGroup(mesh2d) is_serosa = fm.createFieldAnd(is_esophagus, is_exterior_face_xi3_1) serosa = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_esophagus_term("serosa of esophagus")) serosa.getMeshGroup(mesh2d).addElementsConditional(is_serosa)
class MeshType_3d_wholebody1(Scaffold_base): """ Generates body coordinates using a solid cylinder of all cube elements, with variable numbers of elements in major, minor, shell and for each section of abdomen, thorax, neck and head. """ cylinder1Settings = { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 3.5, 'Number of elements': 1 } axis1 = [0, 0, 1] axis2 = [1, 0, 0] axis3 = [0, 1, 0] centralPathDefaultScaffoldPackages = { 'Default': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': cylinder1Settings, '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], [ [[0.0, 0.0, 0.0], setMagnitude(axis1, cylinder1Settings['Length']), setMagnitude(axis2, 0.5), [0.0, 0.0, 0.0], setMagnitude(axis3, 0.5), [0.0, 0.0, 0.0]], [setMagnitude(axis1, cylinder1Settings['Length']), setMagnitude(axis1, cylinder1Settings['Length']), setMagnitude(axis2, 0.5), [0.0, 0.0, 0.0], setMagnitude(axis3, 0.5), [0.0, 0.0, 0.0]] ]) }) } @staticmethod def getName(): return '3D Whole Body 1' @staticmethod def getParameterSetNames(): return [ 'Default', 'Human Coarse', 'Human Fine', 'Rat Coarse', 'Rat Fine' ] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if parameterSetName == 'Default': parameterSetName = 'Human Coarse' centralPathOption = cls.centralPathDefaultScaffoldPackages['Default'] options = {} options['Base parameter set'] = parameterSetName options['Central path'] = copy.deepcopy(centralPathOption) options['Number of elements across major'] = 6 options['Number of elements across minor'] = 6 options['Number of elements across shell'] = 1 options['Number of elements across transition'] = 1 options['Number of elements in abdomen'] = 5 options['Number of elements in thorax'] = 3 options['Number of elements in neck'] = 1 options['Number of elements in head'] = 2 options['Shell thickness proportion'] = 0.2 options['Discontinuity on the core boundary'] = True options['Lower half'] = False options['Use cross derivatives'] = False options['Refine'] = False options['Refine number of elements across major'] = 1 options['Refine number of elements along'] = 1 if 'Coarse' in parameterSetName: pass if 'Fine' in parameterSetName: options['Number of elements across major'] = 10 options['Number of elements across minor'] = 10 options['Number of elements across shell'] = 1 options['Number of elements across transition'] = 1 options['Number of elements in abdomen'] = 10 options['Number of elements in thorax'] = 6 options['Number of elements in neck'] = 2 options['Number of elements in head'] = 4 return options @staticmethod def getOrderedOptionNames(): return [ 'Central path', 'Number of elements across major', 'Number of elements across minor', 'Number of elements across shell', 'Number of elements across transition', 'Number of elements in abdomen', 'Number of elements in thorax', 'Number of elements in neck', 'Number of elements in head', 'Shell thickness proportion', 'Discontinuity on the core boundary', 'Refine', 'Refine number of elements across major', 'Refine number of elements along' ] @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': return [MeshType_1d_path1] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.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]) 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) dependentChanges = False if options['Number of elements across major'] < 4: options['Number of elements across major'] = 4 if options['Number of elements across major'] % 2: options['Number of elements across major'] += 1 if options['Number of elements across minor'] != options['Number of elements across major']: options['Number of elements across minor'] = options['Number of elements across major'] dependentChanges = True if options['Number of elements across transition'] < 1: options['Number of elements across transition'] = 1 Rcrit = min(options['Number of elements across major']-4, options['Number of elements across minor']-4)//2 if options['Number of elements across shell'] + options['Number of elements across transition'] - 1 > Rcrit: dependentChanges = True options['Number of elements across shell'] = Rcrit options['Number of elements across transition'] = 1 if options['Shell thickness proportion'] < 0.07 or options['Shell thickness proportion'] > 0.7: options['Shell thickness proportion'] = 2*options['Number of elements across shell']/options['Number of elements across major'] if options['Number of elements in abdomen'] < 1: options['Number of elements in abdomen'] = 1 if options['Number of elements in head'] < 1: options['Number of elements in head'] = 1 if options['Number of elements in neck'] < 1: options['Number of elements in neck'] = 1 if options['Number of elements in thorax'] < 1: options['Number of elements in thorax'] = 1 return dependentChanges @staticmethod def generateBaseMesh(region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: List of AnnotationGroup """ baseParameterSetName = options['Base parameter set'] isHuman = 'Human' in baseParameterSetName isRat = 'Rat' in baseParameterSetName centralPath = options['Central path'] full = not options['Lower half'] elementsCountAcrossMajor = options['Number of elements across major'] if not full: elementsCountAcrossMajor //= 2 elementsCountAcrossMinor = options['Number of elements across minor'] elementsCountAcrossShell = options['Number of elements across shell'] elementsCountAcrossTransition = options['Number of elements across transition'] elementsCountAlongAbdomen = options['Number of elements in abdomen'] elementsCountAlongHead = options['Number of elements in head'] elementsCountAlongNeck = options['Number of elements in neck'] elementsCountAlongThorax = options['Number of elements in thorax'] shellRadiusProportion = options['Shell thickness proportion'] shellProportion = 1/(1/shellRadiusProportion-1)*(elementsCountAcrossMajor/2/elementsCountAcrossShell - 1) discontinuity = options['Discontinuity on the core boundary'] useCrossDerivatives = options['Use cross derivatives'] elementsCountAlong = elementsCountAlongAbdomen + elementsCountAlongThorax + elementsCountAlongNeck + elementsCountAlongHead fieldmodule = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fieldmodule) mesh = fieldmodule.findMeshByDimension(3) bodyGroup = AnnotationGroup(region, get_body_term("body")) coreGroup = AnnotationGroup(region, get_body_term("core")) non_coreGroup = AnnotationGroup(region, get_body_term("non core")) abdomenGroup = AnnotationGroup(region, get_body_term("abdomen")) thoraxGroup = AnnotationGroup(region, get_body_term("thorax")) neckGroup = AnnotationGroup(region, get_body_term("neck core")) headGroup = AnnotationGroup(region, get_body_term("head core")) annotationGroups = [bodyGroup, coreGroup, non_coreGroup, abdomenGroup, thoraxGroup, neckGroup, headGroup] cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong) cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, [0.0, 0.0, 0.0], cylinderCentralPath.alongAxis[0], cylinderCentralPath.majorAxis[0], cylinderCentralPath.minorRadii[0]) cylinder1 = CylinderMesh(fieldmodule, coordinates, elementsCountAlong, base, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) # body coordinates bodyCoordinates = findOrCreateFieldCoordinates(fieldmodule, name="body coordinates") tmp_region = region.createRegion() tmp_fieldmodule = tmp_region.getFieldmodule() tmp_body_coordinates = findOrCreateFieldCoordinates(tmp_fieldmodule, name="body coordinates") tmp_cylinder = CylinderMesh(tmp_fieldmodule, tmp_body_coordinates, elementsCountAlong, base, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) sir = tmp_region.createStreaminformationRegion() srm = sir.createStreamresourceMemory() tmp_region.write(sir) result, buffer = srm.getBuffer() sir = region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) region.read(sir) del srm del sir del tmp_body_coordinates del tmp_fieldmodule del tmp_region # Groups of different parts of the body is_body = fieldmodule.createFieldConstant(1) bodyMeshGroup = bodyGroup.getMeshGroup(mesh) bodyMeshGroup.addElementsConditional(is_body) coreMeshGroup = coreGroup.getMeshGroup(mesh) # core group e1a = elementsCountAcrossShell e1z = elementsCountAcrossMinor - elementsCountAcrossShell - 1 e2a = elementsCountAcrossShell e2b = e2a + elementsCountAcrossTransition e2z = elementsCountAcrossMajor - elementsCountAcrossShell - 1 e2y = e2z - elementsCountAcrossTransition e1oc = elementsCountAcrossMinor - 2*elementsCountAcrossShell - 2*elementsCountAcrossTransition e2oc = elementsCountAcrossMajor - 2*elementsCountAcrossShell - 2*elementsCountAcrossTransition e2oCore = e2oc * e1oc + 2 * elementsCountAcrossTransition * (e2oc + e1oc) elementsCountAround = cylinder1.getElementsCountAround() e2oShell = elementsCountAround * elementsCountAcrossShell e2o = e2oCore + e2oShell elementId = cylinder1.getElementIdentifiers() for e3 in range(elementsCountAlong): for e2 in range(elementsCountAcrossMajor): for e1 in range(elementsCountAcrossMinor): coreElement = ((e2 >= e2a) and (e2 <= e2z)) and ((e1 >= e1a) and (e1 <= e1z)) if coreElement: elementIdentifier = elementId[e3][e2][e1] if elementIdentifier: element = mesh.findElementByIdentifier(elementIdentifier) coreMeshGroup.addElement(element) is_non_core = fieldmodule.createFieldNot(coreGroup.getGroup()) non_coreMeshGroup = non_coreGroup.getMeshGroup(mesh) non_coreMeshGroup.addElementsConditional(is_non_core) abdomenMeshGroup = abdomenGroup.getMeshGroup(mesh) thoraxMeshGroup = thoraxGroup.getMeshGroup(mesh) neckMeshGroup = neckGroup.getMeshGroup(mesh) headMeshGroup = headGroup.getMeshGroup(mesh) meshGroups = [abdomenMeshGroup, thoraxMeshGroup, neckMeshGroup, headMeshGroup] abdomenRange = [1, elementsCountAlongAbdomen*e2o] thoraxRange = [abdomenRange[1]+1, abdomenRange[1]+elementsCountAlongThorax*e2o] neckRange = [thoraxRange[1]+1, thoraxRange[1] + elementsCountAlongNeck*e2o] headRange = [neckRange[1]+1, elementsCountAlong*e2o] groupsRanges = [abdomenRange, thoraxRange, neckRange, headRange] totalElements = e2o*elementsCountAlong for elementIdentifier in range(1, totalElements+1): element = mesh.findElementByIdentifier(elementIdentifier) if coreMeshGroup.containsElement(element): ri = 0 for groupRange in groupsRanges: if (elementIdentifier >= groupRange[0]) and (elementIdentifier <= groupRange[1]): meshGroups[ri].addElement(element) break ri += 1 if discontinuity: # create discontinuity in d3 on the core boundary nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) elementtemplate = mesh.createElementtemplate() undefineNodetemplate = nodes.createNodetemplate() undefineNodetemplate.undefineField(coordinates) nodetemplate = nodes.createNodetemplate() fieldcache = fieldmodule.createFieldcache() with ChangeManager(fieldmodule): localNodeIndexes = [1, 2, 3, 4] valueLabel = Node.VALUE_LABEL_D_DS3 for e3 in range(elementsCountAlong): for e2 in range(elementsCountAcrossMajor): for e1 in range(elementsCountAcrossMinor): regularRowElement = (((e2 >= e2b) and (e2 <= e2y)) and ((e1 == e1a - 1) or (e1 == e1z + 1))) non_coreFirstLayerElement = (e2 == e2a - 1) or regularRowElement or (e2 == e2z + 1) elementIdentifier = elementId[e3][e2][e1] if elementIdentifier and non_coreFirstLayerElement: element = mesh.findElementByIdentifier(elementIdentifier) eft = element.getElementfieldtemplate(coordinates, -1) nodeIds = get_element_node_identifiers(element, eft) for localNodeIndex in localNodeIndexes: node = element.getNode(eft, localNodeIndex) nodetemplate.defineFieldFromNode(coordinates, node) versionsCount = nodetemplate.getValueNumberOfVersions(coordinates, -1, valueLabel) if versionsCount == 1: fieldcache.setNode(node) result0, x = coordinates.getNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, 3) result0, d1 = coordinates.getNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, 3) result0, d2 = coordinates.getNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, 3) result0, d3 = coordinates.getNodeParameters(fieldcache, -1, valueLabel, 1, 3) result1 = node.merge(undefineNodetemplate) result2 = nodetemplate.setValueNumberOfVersions(coordinates, -1, valueLabel, 2) result3 = node.merge(nodetemplate) result4 = coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_VALUE, 1, x) result4 = coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS1, 1, d1) result4 = coordinates.setNodeParameters(fieldcache, -1, Node.VALUE_LABEL_D_DS2, 1, d2) result4 = coordinates.setNodeParameters(fieldcache, -1, valueLabel, 1, d3) result5 = coordinates.setNodeParameters(fieldcache, -1, valueLabel, 2, d3) remapEftNodeValueLabelsVersion(eft, localNodeIndexes, [valueLabel], 2) result1 = elementtemplate.defineField(coordinates, -1, eft) result2 = element.merge(elementtemplate) result3 = element.setNodesByIdentifier(eft, nodeIds) else: fieldcache = fieldmodule.createFieldcache() # Annotation fiducial point markerGroup = findOrCreateFieldGroup(fieldmodule, "marker") markerName = findOrCreateFieldStoredString(fieldmodule, name="marker_name") markerLocation = findOrCreateFieldStoredMeshLocation(fieldmodule, mesh, name="marker_location") markerBodyCoordinates = findOrCreateFieldCoordinates(fieldmodule, name="marker_body_coordinates") nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() markerTemplateInternal = nodes.createNodetemplate() markerTemplateInternal.defineField(markerName) markerTemplateInternal.defineField(markerLocation) markerTemplateInternal.defineField(markerBodyCoordinates) # middleLeft = elementsCountAcrossMinor//2 topElem = elementsCountAcrossMajor - 1 middleRight = middleLeft - 1 neckFirstElem = elementsCountAlongAbdomen+elementsCountAlongThorax thoraxFirstElem = elementsCountAlongAbdomen middleDown = elementsCountAcrossMajor//2 - 1 # organ landmarks groups apexOfHeart = heart_terms.get_heart_term('apex of heart') leftAtriumEpicardiumVenousMidpoint = heart_terms.get_heart_term('left atrium epicardium venous midpoint') rightAtriumEpicardiumVenousMidpoint = heart_terms.get_heart_term('right atrium epicardium venous midpoint') apexOfUrinaryBladder = bladder_terms.get_bladder_term('apex of urinary bladder') leftUreterJunctionWithBladder = bladder_terms.get_bladder_term('left ureter junction with bladder') rightUreterJunctionWithBladder = bladder_terms.get_bladder_term('right ureter junction with bladder') urethraJunctionWithBladderDorsal = bladder_terms.get_bladder_term('urethra junction of dorsal bladder neck') urethraJunctionWithBladderVentral = bladder_terms.get_bladder_term('urethra junction of ventral bladder neck') gastroesophagalJunctionOnLesserCurvature = stomach_terms.get_stomach_term('esophagogastric junction along the lesser curvature on serosa') limitingRidgeOnGreaterCurvature = stomach_terms.get_stomach_term('limiting ridge at the greater curvature on serosa') pylorusOnGreaterCurvature = stomach_terms.get_stomach_term('gastroduodenal junction along the greater curvature on serosa') junctionBetweenFundusAndBodyOnGreaterCurvature = stomach_terms.get_stomach_term("fundus-body junction along the greater curvature on serosa") apexOfLeftLung = lung_terms.get_lung_term('apex of left lung') ventralBaseOfLeftLung = lung_terms.get_lung_term('ventral base of left lung') dorsalBaseOfLeftLung = lung_terms.get_lung_term('dorsal base of left lung') apexOfRightLung = lung_terms.get_lung_term('apex of right lung') ventralBaseOfRightLung = lung_terms.get_lung_term('ventral base of right lung') dorsalBaseOfRightLung = lung_terms.get_lung_term('dorsal base of right lung') laterodorsalTipOfMiddleLobeOfRightLung = lung_terms.get_lung_term('laterodorsal tip of middle lobe of right lung') apexOfRightLungAccessoryLobe = lung_terms.get_lung_term('apex of right lung accessory lobe') ventralBaseOfRightLungAccessoryLobe = lung_terms.get_lung_term('ventral base of right lung accessory lobe') dorsalBaseOfRightLungAccessoryLobe = lung_terms.get_lung_term('dorsal base of right lung accessory lobe') medialBaseOfLeftLung = lung_terms.get_lung_term("medial base of left lung") medialBaseOfRightLung = lung_terms.get_lung_term("medial base of right lung") brainstemDorsalMidlineCaudalPoint = brainstem_terms.get_brainstem_term('brainstem dorsal midline caudal point') brainstemDorsalMidlineCranialPoint = brainstem_terms.get_brainstem_term('brainstem dorsal midline cranial point') brainstemVentralMidlineCaudalPoint = brainstem_terms.get_brainstem_term('brainstem ventral midline caudal point') brainstemVentralMidlineCranialPoint = brainstem_terms.get_brainstem_term('brainstem ventral midline cranial point') # marker coordinates. In future we want to have only one table for all species. if isRat: bodyMarkerPoints = [ {"group": ("left hip joint", ''), "x": [0.367, 0.266, 0.477]}, {"group": ("right hip joint", ''), "x": [-0.367, 0.266, 0.477]}, {"group": ("left shoulder joint", ''), "x": [0.456, -0.071, 2.705]}, {"group": ("right shoulder joint", ''), "x": [-0.456, -0.071, 2.705]}, {"group": ("along left femur", ''), "x": [0.456, 0.07, 0.633]}, {"group": ("along right femur", ''), "x": [-0.456, 0.07, 0.633]}, {"group": ("along left humerus", ''), "x": [0.423, -0.173, 2.545]}, {"group": ("along right humerus", ''), "x": [-0.423, -0.173, 2.545]}, {"group": apexOfUrinaryBladder, "x": [-0.124, -0.383, 0.434]}, {"group": leftUreterJunctionWithBladder, "x": [-0.111, -0.172, 0.354]}, {"group": rightUreterJunctionWithBladder, "x": [-0.03, -0.196, 0.363]}, {"group": urethraJunctionWithBladderDorsal, "x": [-0.03, -0.26, 0.209]}, {"group": urethraJunctionWithBladderVentral, "x": [-0.037, -0.304, 0.203]}, {"group": brainstemDorsalMidlineCaudalPoint, "x": [-0.032, 0.418, 2.713]}, {"group": brainstemDorsalMidlineCranialPoint, "x": [-0.017, 0.203, 2.941]}, {"group": brainstemVentralMidlineCaudalPoint, "x": [-0.028, 0.388, 2.72]}, {"group": brainstemVentralMidlineCranialPoint, "x": [-0.019, 0.167, 2.95]}, {"group": apexOfHeart, "x": [0.096, -0.128, 1.601]}, {"group": leftAtriumEpicardiumVenousMidpoint, "x": [0.127, -0.083, 2.079]}, {"group": rightAtriumEpicardiumVenousMidpoint, "x": [0.039, -0.082, 2.075]}, {"group": apexOfLeftLung, "x": [0.172, -0.175, 2.337]}, {"group": ventralBaseOfLeftLung, "x": [0.274, -0.285, 1.602]}, {"group": dorsalBaseOfLeftLung, "x": [0.037, 0.31, 1.649]}, {"group": apexOfRightLung, "x": [-0.086, -0.096, 2.311]}, {"group": ventralBaseOfRightLung, "x": [0.14, -0.357, 1.662]}, {"group": dorsalBaseOfRightLung, "x": [-0.054, 0.304, 1.667]}, {"group": laterodorsalTipOfMiddleLobeOfRightLung, "x": [-0.258, -0.173, 2.013]}, {"group": apexOfRightLungAccessoryLobe, "x": [0.041, -0.063, 1.965]}, {"group": ventralBaseOfRightLungAccessoryLobe, "x": [0.143, -0.356, 1.66]}, {"group": dorsalBaseOfRightLungAccessoryLobe, "x": [0.121, -0.067, 1.627]}, {"group": gastroesophagalJunctionOnLesserCurvature, "x": [0.12, 0.009, 1.446]}, {"group": limitingRidgeOnGreaterCurvature, "x": [0.318, 0.097, 1.406]}, {"group": pylorusOnGreaterCurvature, "x": [0.08, -0.111, 1.443]}, ] elif isHuman: bodyMarkerPoints = [ {"group": urethraJunctionWithBladderDorsal, "x": [-0.0071, -0.2439, 0.1798]}, {"group": urethraJunctionWithBladderVentral, "x": [-0.007, -0.2528, 0.1732]}, {"group": leftUreterJunctionWithBladder, "x": [0.1074, 0.045, 0.1728]}, {"group": rightUreterJunctionWithBladder, "x": [-0.1058, 0.0533, 0.1701]}, {"group": apexOfUrinaryBladder, "x": [0.005, 0.1286, 0.1264]}, {"group": brainstemDorsalMidlineCaudalPoint, "x": [0.0068, 0.427, 2.7389]}, {"group": brainstemDorsalMidlineCranialPoint, "x": [0.008, -0.0231, 3.0778]}, {"group": brainstemVentralMidlineCaudalPoint, "x": [0.0054, 0.3041, 2.7374]}, {"group": brainstemVentralMidlineCranialPoint, "x": [0.0025, -0.2308, 3.091]}, {"group": apexOfHeart, "x": [0.1373, -0.1855, 1.421]}, {"group": leftAtriumEpicardiumVenousMidpoint, "x": [0.0024, 0.1452, 1.8022]}, {"group": rightAtriumEpicardiumVenousMidpoint, "x": [-0.0464, 0.0373, 1.7491]}, {"group": apexOfLeftLung, "x": [0.0655, -0.0873, 2.3564]}, {"group": apexOfRightLung, "x": [-0.088, -0.0363, 2.3518]}, {"group": laterodorsalTipOfMiddleLobeOfRightLung, "x": [-0.2838, -0.0933, 1.9962]}, {"group": ventralBaseOfLeftLung, "x": [0.219, -0.2866, 1.4602]}, {"group": medialBaseOfLeftLung, "x": [0.0426, -0.0201, 1.4109]}, {"group": ventralBaseOfRightLung, "x": [-0.2302, -0.2356, 1.3926]}, {"group": medialBaseOfRightLung, "x": [-0.0363, 0.0589, 1.3984]}, {"group": dorsalBaseOfLeftLung, "x": [0.1544, 0.2603, 1.3691]}, {"group": dorsalBaseOfRightLung, "x": [0.0369, -0.2524, 0.912]}, {"group": gastroesophagalJunctionOnLesserCurvature, "x": [-0.0062, -0.3259, 0.8586]}, {"group": pylorusOnGreaterCurvature, "x": [-0.0761, -0.3189, 0.8663]}, {"group": junctionBetweenFundusAndBodyOnGreaterCurvature, "x": [0.1884, -0.1839, 0.9639]}, ] nodeIdentifier = cylinder1._endNodeIdentifier findMarkerLocation = fieldmodule.createFieldFindMeshLocation(markerBodyCoordinates, bodyCoordinates, mesh) findMarkerLocation.setSearchMode(FieldFindMeshLocation.SEARCH_MODE_EXACT) for bodyMarkerPoint in bodyMarkerPoints: markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) fieldcache.setNode(markerPoint) markerBodyCoordinates.assignReal(fieldcache, bodyMarkerPoint["x"]) markerName.assignString(fieldcache, bodyMarkerPoint["group"][0]) element, xi = findMarkerLocation.evaluateMeshLocation(fieldcache, 3) markerLocation.assignMeshLocation(fieldcache, element, xi) nodeIdentifier += 1 return annotationGroups @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(). """ assert isinstance(meshRefinement, MeshRefinement) refineElementsCountAcrossMajor = options['Refine number of elements across major'] refineElementsCountAlong = options['Refine number of elements along'] meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcrossMajor, refineElementsCountAlong, refineElementsCountAcrossMajor) @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. """ # create 2d surface mesh groups fm = region.getFieldmodule() mesh2d = fm.findMeshByDimension(2) bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_body_term("body")) coreGroup = getAnnotationGroupForTerm(annotationGroups, get_body_term("core")) non_coreGroup = getAnnotationGroupForTerm(annotationGroups, get_body_term("non core")) abdomenGroup = getAnnotationGroupForTerm(annotationGroups, get_body_term("abdomen")) thoraxGroup = getAnnotationGroupForTerm(annotationGroups, get_body_term("thorax")) neckGroup = getAnnotationGroupForTerm(annotationGroups, get_body_term("neck core")) skinGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_body_term("skin epidermis")) coreBoundaryGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_body_term("core boundary")) diaphragmGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_body_term("diaphragm")) spinalCordGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_body_term("spinal cord")) is_exterior = fm.createFieldIsExterior() is_on_face_xi3_1 = fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1) is_skin = fm.createFieldAnd(is_exterior, is_on_face_xi3_1) skinMeshGroup = skinGroup.getMeshGroup(mesh2d) skinMeshGroup.addElementsConditional(is_skin) is_core_boundary = fm.createFieldAnd(coreGroup.getGroup(), non_coreGroup.getGroup()) coreBoundaryMeshGroup = coreBoundaryGroup.getMeshGroup(mesh2d) coreBoundaryMeshGroup.addElementsConditional(is_core_boundary) is_diaphragm = fm.createFieldAnd(abdomenGroup.getGroup(), thoraxGroup.getGroup()) diaphragmMeshGroup = diaphragmGroup.getMeshGroup(mesh2d) diaphragmMeshGroup.addElementsConditional(is_diaphragm) # spinal cord coordinates = fm.findFieldByName('coordinates').castFiniteElement() zero = fm.createFieldConstant(0) zero_m = fm.createFieldConstant(-0.01) zero_p = fm.createFieldConstant(0.01) comp2 = cls.axis2.index(max(cls.axis2)) + 1 ax2_comp = fm.createFieldComponent(coordinates, comp2) ax2_gt_zero_m = fm.createFieldGreaterThan(ax2_comp, zero_m) ax2_lt_zero_p = fm.createFieldLessThan(ax2_comp, zero_p) ax2_gt_zero_xi10 = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), ax2_gt_zero_m) ax2_lt_zero_xi10 = fm.createFieldAnd(fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0), ax2_lt_zero_p) is_ax2_zero = fm.createFieldAnd(ax2_lt_zero_xi10, ax2_gt_zero_xi10) comp3 = cls.axis3.index(max(cls.axis3)) + 1 ax3_comp = fm.createFieldComponent(coordinates, comp3) ax3_positive = fm.createFieldGreaterThan(ax3_comp, zero) is_ax2_zero_ax3_positive = fm.createFieldAnd(is_ax2_zero, ax3_positive) is_abdomen_thorax = fm.createFieldAdd(abdomenGroup.getGroup(), thoraxGroup.getGroup()) is_abdomen_thorax_neck = fm.createFieldAdd(is_abdomen_thorax, neckGroup.getGroup()) is_abdomen_thorax_neck_boundary = fm.createFieldAnd(is_core_boundary, is_abdomen_thorax_neck) is_spinal_cord = fm.createFieldAnd(is_ax2_zero_ax3_positive, is_abdomen_thorax_neck_boundary) mesh1d = fm.findMeshByDimension(1) spinalCordMeshGroup = spinalCordGroup.getMeshGroup(mesh1d) spinalCordMeshGroup.addElementsConditional(is_spinal_cord)
class MeshType_3d_solidcylinder1(Scaffold_base): """ Generates a solid cylinder using a ShieldMesh of all cube elements, with variable numbers of elements in major, minor, shell and axial directions. """ centralPathDefaultScaffoldPackages = { 'Cylinder 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 3.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], [ [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 2.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 3.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]] ]) }) } @staticmethod def getName(): return '3D Solid Cylinder 1' @classmethod def getDefaultOptions(cls, parameterSetName='Default'): centralPathOption = cls.centralPathDefaultScaffoldPackages['Cylinder 1'] options = { 'Central path': copy.deepcopy(centralPathOption), 'Number of elements across major': 4, 'Number of elements across minor': 4, 'Number of elements across shell': 0, 'Number of elements across transition': 1, 'Number of elements along': 1, 'Shell element thickness proportion': 1.0, 'Lower half': False, 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements across major': 1, 'Refine number of elements along': 1 } return options @staticmethod def getOrderedOptionNames(): return [ 'Central path', 'Number of elements across major', 'Number of elements across minor', 'Number of elements across shell', 'Number of elements across transition', 'Number of elements along', 'Shell element thickness proportion', 'Lower half', 'Refine', 'Refine number of elements across major', 'Refine number of elements along' ] @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': return [MeshType_1d_path1] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.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]) 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) dependentChanges = False if options['Number of elements across major'] < 4: options['Number of elements across major'] = 4 if options['Number of elements across major'] % 2: options['Number of elements across major'] += 1 if options['Number of elements across minor'] < 4: options['Number of elements across minor'] = 4 if options['Number of elements across minor'] % 2: options['Number of elements across minor'] += 1 if options['Number of elements along'] < 1: options['Number of elements along'] = 1 if options['Number of elements across transition'] < 1: options['Number of elements across transition'] = 1 Rcrit = min(options['Number of elements across major']-4, options['Number of elements across minor']-4)//2 if options['Number of elements across shell'] + options['Number of elements across transition'] - 1 > Rcrit: dependentChanges = True options['Number of elements across shell'] = Rcrit options['Number of elements across transition'] = 1 if options['Shell element thickness proportion'] < 0.15: options['Shell element thickness proportion'] = 1.0 return dependentChanges @staticmethod def generateBaseMesh(region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: None """ centralPath = options['Central path'] full = not options['Lower half'] elementsCountAcrossMajor = options['Number of elements across major'] if not full: elementsCountAcrossMajor //= 2 elementsCountAcrossMinor = options['Number of elements across minor'] elementsCountAcrossShell = options['Number of elements across shell'] elementsCountAcrossTransition = options['Number of elements across transition'] elementsCountAlong = options['Number of elements along'] shellProportion = options['Shell element thickness proportion'] useCrossDerivatives = options['Use cross derivatives'] fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong) cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if full else CylinderShape.CYLINDER_SHAPE_LOWER_HALF base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, [0.0, 0.0, 0.0], cylinderCentralPath.alongAxis[0], cylinderCentralPath.majorAxis[0], cylinderCentralPath.minorRadii[0]) cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) 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(). """ assert isinstance(meshRefinement, MeshRefinement) refineElementsCountAcrossMajor = options['Refine number of elements across major'] refineElementsCountAlong = options['Refine number of elements along'] meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcrossMajor, refineElementsCountAlong, refineElementsCountAcrossMajor)
class MeshType_3d_smallintestine1(Scaffold_base): ''' Generates a 3-D small intestine mesh with variable numbers of elements around, along the central line, and through wall. The small intestine is created by a function that generates a small intestine segment and uses tubemesh to map the segment along a central line profile. ''' centralPathDefaultScaffoldPackages = { 'Mouse 1' : ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings' : { 'Coordinate dimensions' : 3, 'Length' : 1.0, 'Number of elements' : 45 }, 'meshEdits' : exnodeStringFromNodeValues( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2 ], [ [ [ -2.3, 18.5, -4.4 ], [ -4.2, -0.8, 3.7 ], [ 0.0, 5.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -8.6, 16.3, -0.4 ], [ -7.1, -2.7, 1.6 ], [ 0.0, 5.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -18.3, 12.6, -1.5 ], [ -6.4, -1.7, -3.8 ], [ 0.0, 5.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -15.6, 13.7, -6.1 ], [ 7.0, 2.1, -1.8 ], [ 0.0, 5.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -9.3, 14.8, -4.9 ], [ 4.7, 0.7, 1.8 ], [ 0.0, 5.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -3.9, 15.7, -3.0 ], [ 4.3, 0.7, 2.0 ], [ 0.0, 5.0, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -3.4, 13.4, -2.8 ], [ -4.1, -0.7, -1.7 ], [ 0.6, -2.0, 0.3 ], [ 0.0, 0.0, 0.5 ] ], [ [ -7.6, 12.4, -4.6 ], [ -3.7, -0.8, -0.9 ], [ 0.0, -2.1, 0.1 ], [ 0.0, 0.0, 0.5 ] ], [ [ -11.6, 11.6, -5.7 ], [ -4.2, -0.7, -0.2 ], [ 0.0, -1.9, 0.1 ], [ 0.0, 0.0, 0.5 ] ], [ [ -16.5, 11.7, -3.9 ], [ -1.0, 0.2, 5.8 ], [ 0.3, -1.4, -0.2 ], [ 0.0, 0.0, 0.5 ] ], [ [ -12.5, 11.7, -1.4 ], [ 3.6, 0.1, 0.6 ], [ -0.1, -1.4, -0.7 ], [ 0.0, 0.0, 0.5 ] ], [ [ -6.8, 11.8, -0.6 ], [ 2.9, 0.0, 0.7 ], [ -0.7, -1.2, -0.9 ], [ 0.0, 0.0, 0.5 ] ], [ [ -6.4, 9.8, -1.6 ], [ -2.9, -0.3, -1.4 ], [ -0.9, 1.6, 0.4 ], [ 0.0, 0.0, 0.5 ] ], [ [ -9.5, 9.5, -2.9 ], [ -4.6, 0.0, -1.8 ], [ -0.5, 1.7, 0.7 ], [ 0.0, 0.0, 0.5 ] ], [ [ -14.3, 9.4, -4.6 ], [ -3.4, 0.1, -1.6 ], [ -0.1, 1.6, 0.5 ], [ 0.0, 0.0, 0.5 ] ], [ [ -19.0, 9.4, -2.9 ], [ 0.3, 0.2, 6.7 ], [ 0.0, 1.8, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -14.5, 9.7, 0.2 ], [ 3.6, -1.2, 1.0 ], [ 0.7, 2.2, 0.9 ], [ 0.0, 0.0, 0.5 ] ], [ [ -12.6, 7.7, 0.7 ], [ 0.6, -2.7, 0.2 ], [ 1.7, 0.8, 1.6 ], [ 0.0, 0.0, 0.5 ] ], [ [ -13.1, 3.8, 0.3 ], [ -4.0, -3.6, -1.5 ], [ 1.0, -1.1, 1.5 ], [ 0.0, 0.0, 0.5 ] ], [ [ -15.2, 5.1, -0.8 ], [ 6.0, 6.9, 1.8 ], [ -0.9, -0.4, 0.3 ], [ 0.0, 0.0, 0.5 ] ], [ [ -17.3, 6.9, -1.0 ], [ -2.5, 0.0, -0.4 ], [ -1.6, 0.0, 1.7 ], [ 0.0, 0.0, 0.5 ] ], [ [ -19.9, 6.8, -2.5 ], [ -1.5, -1.1, -3.4 ], [ -1.8, -0.7, 0.4 ], [ 0.0, 0.0, 0.5 ] ], [ [ -17.2, 6.3, -5.1 ], [ 4.0, 0.8, -1.3 ], [ -0.4, -1.3, -1.5 ], [ 0.0, 0.0, 0.5 ] ], [ [ -12.2, 7.8, -6.8 ], [ 4.8, 1.7, -0.3 ], [ 0.1, -0.6, -1.6 ], [ 0.0, 0.0, 0.5 ] ], [ [ -7.9, 9.6, -6.5 ], [ 3.7, 1.7, 0.7 ], [ 0.5, -0.6, -1.6 ], [ 0.0, 0.0, 0.5 ] ], [ [ -3.8, 10.3, -5.5 ], [ 3.8, -2.7, -0.1 ], [ -1.3, -0.3, -3.1 ], [ 0.0, 0.0, 0.5 ] ], [ [ -5.3, 7.6, -6.4 ], [ -3.5, -1.0, -1.3 ], [ -0.4, 1.1, -1.5 ], [ 0.0, 0.0, 0.5 ] ], [ [ -9.0, 6.4, -7.3 ], [ -3.2, -1.3, 1.9 ], [ -0.9, 0.5, -1.1 ], [ 0.0, 0.0, 0.5 ] ], [ [ -11.6, 4.0, -2.0 ], [ 5.6, -0.2, 4.3 ], [ -1.8, -0.3, 1.2 ], [ 0.0, 0.0, 0.5 ] ], [ [ -5.9, 5.0, -3.1 ], [ 4.1, 1.2, -1.6 ], [ 1.0, -0.3, 1.9 ], [ 0.0, 0.0, 0.5 ] ], [ [ -2.5, 6.0, -3.8 ], [ 3.6, 0.7, 3.2 ], [ -1.7, -1.2, 1.2 ], [ 0.0, 0.0, 0.5 ] ], [ [ -4.1, 3.2, -0.4 ], [ -3.5, -1.7, 2.6 ], [ -1.0, 0.4, -1.1 ], [ 0.0, 0.0, 0.5 ] ], [ [ -9.7, 1.7, 2.3 ], [ -7.9, -1.0, 1.0 ], [ -0.6, 1.0, -1.6 ], [ 0.0, 0.0, 0.5 ] ], [ [ -19.0, 0.6, -0.4 ], [ 0.2, 3.7, -6.8 ], [ 2.6, 0.8, 0.0 ], [ 0.0, 0.0, 0.5 ] ], [ [ -13.9, 2.3, -5.8 ], [ 4.4, 0.6, -1.1 ], [ 0.5, -0.1, 2.4 ], [ 0.0, 0.0, 0.5 ] ], [ [ -7.7, 1.2, -4.6 ], [ 3.9, -3.4, 1.5 ], [ -0.5, 0.0, 2.2 ], [ 0.0, 0.0, 0.5 ] ], [ [ -4.8, -4.0, -1.3 ], [ -4.2, -3.3, 3.1 ], [ -1.5, 2.5, 2.3 ], [ 0.0, 0.0, 0.5 ] ], [ [ -10.9, -6.1, -0.6 ], [ -5.3, -1.2, -0.9 ], [ -0.5, 1.9, 1.3 ], [ 0.0, 0.0, 0.5 ] ], [ [ -19.9, -6.4, -5.5 ], [ -0.3, 1.7, -10.5 ], [ -0.9, 2.0, 0.7 ], [ 0.0, 0.0, 0.5 ] ], [ [ -10.7, -3.2, -8.8 ], [ 7.8, 0.4, 0.1 ], [ -0.2, 2.1, 0.2 ], [ 0.0, 0.0, 0.5 ] ], [ [ -1.2, -1.9, -7.3 ], [ 0.8, 8.1, 2.5 ], [ -3.8, 0.1, -0.6 ], [ 0.0, 0.0, 0.5 ] ], [ [ -6.3, 0.5, -8.1 ], [ -9.8, -1.2, 0.5 ], [ 0.2, -1.9, -0.5 ], [ 0.0, 0.0, 0.5 ] ], [ [ -16.0, -0.7, -7.4 ], [ -7.6, 1.2, 1.5 ], [ -0.1, -2.0, -0.9 ], [ 0.0, 0.0, 0.5 ] ], [ [ -20.5, 2.3, -6.1 ], [ 3.5, 7.2, -2.9 ], [ -2.3, 0.2, -0.2 ], [ 0.0, 0.0, 0.5 ] ], [ [ -11.4, 2.6, -10.1 ], [ 10.4, 1.5, -0.2 ], [ -0.2, 1.3, -2.2 ], [ 0.0, 0.0, 0.5 ] ], [ [ -3.8, 4.2, -7.3 ], [ 3.5, 0.9, 2.7 ], [ 0.2, 1.0, -2.6 ], [ 0.0, 0.0, 0.5 ] ] ] ) } ) } @staticmethod def getName(): return '3D Small Intestine 1' @staticmethod def getParameterSetNames(): return [ 'Default', 'Mouse 1'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 1'] options = { 'Central path': copy.deepcopy(centralPathOption), 'Number of segments': 100, 'Number of elements around': 8, 'Number of elements along segment': 4, 'Number of elements through wall': 1, 'Duodenum length': 25.0, 'Jejunum length': 240.0, 'Ileum length': 10.0, 'Duodenum inner radius': 0.6, 'Duodenum-jejunum inner radius': 1.0, 'Jejunum-ileum inner radius': 1.0, 'Ileum inner radius': 1.0, 'Wall thickness': 0.1, 'Use cross derivatives': False, 'Use linear through wall': True, 'Refine': False, 'Refine number of elements around': 1, 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } return options @staticmethod def getOrderedOptionNames(): return [ 'Central path', 'Number of segments', 'Number of elements around', 'Number of elements along segment', 'Number of elements through wall', 'Duodenum length', 'Jejunum length', 'Ileum length', 'Duodenum inner radius', 'Duodenum-jejunum inner radius', 'Jejunum-ileum inner radius', 'Ileum inner radius', 'Wall thickness', '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 ] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.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]) 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) for key in [ 'Number of segments', 'Number of elements around', 'Number of elements along segment', '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 for key in [ 'Duodenum length', 'Jejunum length', 'Ileum length', 'Duodenum inner radius', 'Duodenum-jejunum inner radius', 'Jejunum-ileum inner radius', 'Ileum inner radius', 'Wall thickness']: if options[key] < 0.0: options[key] = 0.0 @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: annotationGroups """ centralPath = options['Central path'] segmentCount = options['Number of segments'] elementsCountAround = options['Number of elements around'] elementsCountAlongSegment = options['Number of elements along segment'] elementsCountThroughWall = options['Number of elements through wall'] duodenumLength = options['Duodenum length'] jejunumLength = options['Jejunum length'] duodenumInnerRadius = options['Duodenum inner radius'] duodenumJejunumInnerRadius = options['Duodenum-jejunum inner radius'] jejunumIleumInnerRadius = options['Jejunum-ileum inner radius'] ileumInnerRadius = options['Ileum inner radius'] wallThickness = options['Wall thickness'] useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not(options['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment*segmentCount) startPhase = 0.0 firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i],',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections = True, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength(cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount elementAlongLength = length / elementsCountAlong # print('Length = ', length) # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongSegment*segmentCount) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) # Generate variation of radius & tc width along length lengthList = [0.0, duodenumLength, duodenumLength + jejunumLength, length] innerRadiusList = [duodenumInnerRadius, duodenumJejunumInnerRadius, jejunumIleumInnerRadius, ileumInnerRadius] innerRadiusSegmentList, dInnerRadiusSegmentList = interp.sampleParameterAlongLine(lengthList, innerRadiusList, segmentCount) # Create annotation groups for small intestine sections elementsAlongDuodenum = round(duodenumLength / elementAlongLength) elementsAlongJejunum = round(jejunumLength / elementAlongLength) elementsAlongIleum = elementsCountAlong - elementsAlongDuodenum - elementsAlongJejunum elementsCountAlongGroups = [elementsAlongDuodenum, elementsAlongJejunum, elementsAlongIleum] smallintestineGroup = AnnotationGroup(region, get_smallintestine_term("small intestine")) duodenumGroup = AnnotationGroup(region, get_smallintestine_term("duodenum")) jejunumGroup = AnnotationGroup(region, get_smallintestine_term("jejunum")) ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) annotationGroupAlong = [[smallintestineGroup, duodenumGroup], [smallintestineGroup, jejunumGroup], [smallintestineGroup, ileumGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsAround = [] for i in range(elementsCountAround): annotationGroupsAround.append([ ]) annotationGroupsThroughWall = [] for i in range(elementsCountThroughWall): annotationGroupsThroughWall.append([ ]) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] # Create object smallIntestineSegmentTubeMeshInnerPoints = CylindricalSegmentTubeMeshInnerPoints( elementsCountAround, elementsCountAlongSegment, segmentLength, wallThickness, innerRadiusSegmentList, dInnerRadiusSegmentList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, radiusAlongSegmentList = \ smallIntestineSegmentTubeMeshInnerPoints.getCylindricalSegmentTubeMeshInnerPoints(nSegment) # Project reference point for warping onto central path start = nSegment*elementsCountAlongSegment end = (nSegment + 1)*elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xInner, elementsCountAround, elementsCountAlongSegment, segmentLength, sx[start:end], sd1[start:end], sd2[start:end], sd12[start:end]) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList, radiusAlongSegmentList, closedProximalEnd=False) # Store points along length xExtrude = xExtrude + (xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:]) d1Extrude = d1Extrude + (d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:]) # Smooth d2 for nodes between segments and recalculate d3 if nSegment == 0: d2Extrude = d2Extrude + (d2WarpedList[:-elementsCountAround]) d3UnitExtrude = d3UnitExtrude + (d3WarpedUnitList[:-elementsCountAround]) else: xSecondFace = xWarpedList[elementsCountAround:elementsCountAround*2] d2SecondFace = d2WarpedList[elementsCountAround:elementsCountAround*2] for n1 in range(elementsCountAround): nx = [xLastTwoFaces[n1], xLastTwoFaces[n1 + elementsCountAround], xSecondFace[n1]] nd2 = [d2LastTwoFaces[n1], d2LastTwoFaces[n1 + elementsCountAround], d2SecondFace[n1]] d2 = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixStartDerivative = True, fixEndDerivative = True)[1] d2Extrude.append(d2) d3Unit = vector.normalise(vector.crossproduct3(vector.normalise(d1LastTwoFaces[n1 + elementsCountAround]), vector.normalise(d2))) d3UnitExtrude.append(d3Unit) d2Extrude = d2Extrude + \ (d2WarpedList[elementsCountAround:-elementsCountAround] if nSegment < segmentCount - 1 else d2WarpedList[elementsCountAround:]) d3UnitExtrude = d3UnitExtrude + \ (d3WarpedUnitList[elementsCountAround:-elementsCountAround] if nSegment < segmentCount - 1 else d3WarpedUnitList[elementsCountAround:]) xLastTwoFaces = xWarpedList[-elementsCountAround*2:] d1LastTwoFaces = d1WarpedList[-elementsCountAround*2:] d2LastTwoFaces = d2WarpedList[-elementsCountAround*2:] # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, [wallThickness]*(elementsCountAlong+1), elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) flatWidthList, xiList = smallIntestineSegmentTubeMeshInnerPoints.getFlatWidthAndXiList() # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, flatWidthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=False) return annotationGroups @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
class MeshType_3d_colon1(Scaffold_base): ''' Generates a 3-D colon mesh with variable numbers of elements around, along the central line, and through wall. The colon is created by a function that generates a colon segment and uses tubemesh to map the segment along a central line profile. ''' centralPathDefaultScaffoldPackages = { 'Human 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'Length': 1.0, '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 ], [[[0.0, 0.0, 0.0], [-50.7, 178.2, 0.0], [-24.0, -6.0, -12.0], [-14.0, -1.0, -12.0]], [[-47.4, 188.6, 0.0], [-19.3, 177.1, 0.0], [-22.0, -4.0, -8.0], [-4.0, 19.0, 22.0]], [[-4.4, 396.5, 0.0], [206.0, 40.1, 0.0], [-10.0, 20.0, 8.0], [-6.0, 0.0, 51.0]], [[130.0, 384.1, 0.0], [130.8, -40.5, 0.0], [-5.0, 4.0, 29.0], [0.0, 1.0, 24.0]], [[279.4, 383.0, 0.0], [118.0, 48.7, 0.0], [-2.0, 10.0, 22.0], [5.0, 25.0, -20.0]], [[443.9, 390.8, 0.0], [111.3, -97.0, 0.0], [10.0, 17.0, 6.0], [1.0, -6.0, -35.0]], [[475.2, 168.0, 0.0], [-0.8, -112.4, 0.0], [20.0, 0.0, -20.0], [15.0, -1.0, -10.0]], [[432.6, -32.3, 0.0], [-90.5, -59.0, 0.0], [6.0, -9.0, -14.0], [8.0, -11.0, -13.0]], [[272.4, 7.5, 0.0], [-79.0, 47.4, 0.0], [1.0, -11.0, -18.0], [4.0, -12.0, -12.0]]]) }), 'Human 2': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'Length': 1.0, '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 ], [[[0.0, 0.0, 0.0], [-34.7, 104.1, -18.1], [-24.0, -6.0, -12.0], [-14.0, -1.0, -12.0]], [[-34.5, 114.0, -18.1], [1.2, 86.6, -3.4], [-22.0, -4.0, -8.0], [-4.0, 19.0, 22.0]], [[-19.1, 218.5, 5.5], [78.7, -7.1, 94.5], [-10.0, 20.0, 8.0], [-6.0, 0.0, 51.0]], [[82.5, 189.1, 94.2], [84.5, 7.1, 71.6], [-5.0, 4.0, 29.0], [0.0, 1.0, 24.0]], [[226.6, 218.7, 85.7], [95.0, 91.3, -58.5], [-2.0, 10.0, 22.0], [5.0, 25.0, -20.0]], [[325.5, 381.7, -57.9], [229.2, -66.7, -20.4], [10.0, 17.0, 6.0], [1.0, -6.0, -35.0]], [[354.0, 105.3, -24.4], [-6.3, -143.7, 20.3], [20.0, 0.0, -20.0], [15.0, -1.0, -10.0]], [[296.5, -121.2, -0.6], [-90.5, -59.0, 0.0], [6.0, -9.0, -14.0], [8.0, -11.0, -13.0]], [[169.8, -73.4, -33.5], [-72.2, 43.4, -27.4], [1.0, -11.0, -18.0], [4.0, -12.0, -12.0]]]) }), 'Mouse 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, '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 ], [[[0.0, 0.0, 0.0], [6.0, 12.0, -2.0], [2.0, 1.0, 2.0], [6.0, 0.0, 3.0]], [[-2.0, 11.0, -3.0], [-8.0, 4.0, 9.0], [2.0, 2.0, 1.0], [0.0, 1.0, 2.0]], [[-3.0, 2.0, 3.0], [-4.0, -8.0, 0.0], [2.0, -1.0, 2.0], [1.0, 0.0, 2.0]], [[-11.0, -3.0, -4.0], [-8.0, -3.0, -7.0], [1.0, -2.0, 1.0], [0.0, 0.0, 0.5]], [[-16.0, -4.0, 0.0], [4.0, -3.0, 14.0], [1.0, -3.0, 0.0], [0.0, 0.0, 0.5]], [[-7.0, -8.0, 0.0], [5.0, -1.0, -14.0], [0.0, -3.0, 0.0], [0.0, 0.0, 0.5]], [[-1.0, -6.0, -1.0], [2.0, -2.0, 9.0], [1.0, -3.0, -1.0], [0.0, 0.0, 0.5]], [[-2.0, -14.0, 5.0], [-2.0, -4.0, 2.0], [1.0, -2.0, -2.0], [0.0, 0.0, 0.5]]]) }), 'Mouse 2': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, '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 ], [[[0.0, 0.0, 0.0], [0.0, 0.0, 13.0], [0.0, -10.0, 0.0], [0.0, 0.0, 0.5]], [[0.0, 0.0, 13.0], [0.0, 2.0, 28.0], [0.0, -10.0, 0.0], [0.0, 0.0, 0.5]], [[-14.0, -2.0, 13.0], [0.0, -3.0, -19.0], [0.0, -10.0, 0.0], [0.0, 0.0, 0.5]], [[-14.0, -1.0, -10.0], [1.0, 1.0, -17.0], [0.0, -10.0, 0.0], [0.0, 0.0, 0.5]], [[-14.0, 0.0, -28.0], [0.0, 0.0, -11.0], [0.0, -10.0, 0.0], [0.0, 0.0, 0.5]]]) }), 'Pig 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'Length': 1.0, 'Number of elements': 36 }, 'meshEdits': exnodeStringFromNodeValues([ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2 ], [[[163.7, -25.2, 12.2], [-21.7, 50.1, -18.1], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[117.2, 32.8, -2.6], [-64.3, 34.4, -3.9], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[38.8, 68.0, 2.6], [-83.9, 24.9, 14.7], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-42.8, 65.5, 15.5], [-69.9, -46.7, 10.3], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-93.1, -11.4, 30.6], [5.7, -104.4, 9.7], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-51.1, -83.7, 32.0], [69.7, -44.1, 1.0], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[43.0, -88.5, 28.5], [71.0, 41.0, -1.0], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[94.9, -5.8, 33.7], [-14.3, 60.1, 0.7], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[56.6, 72.9, 45.0], [-108.7, 54.1, 22.4], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-37.0, 64.6, 59.3], [-72.5, -33.9, 6.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-94.1, -15.6, 78.2], [8.5, -82.1, 13.7], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-46.1, -90.1, 82.9], [76.6, -39.9, 11.9], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[45.8, -87.7, 92.3], [99.1, 55.4, 12.9], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[110.7, 2.2, 102.2], [0.4, 61.7, 12.7], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[73.9, 58.3, 110.7], [-86.3, 19.7, 9.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-21.8, 25.4, 118.0], [-78.1, -83.9, 23.6], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-41.7, -49.8, 134.9], [10.8, -41.9, 18.8], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[4.0, -46.5, 133.5], [8.3, 43.8, -7.7], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[12.0, 2.6, 130.0], [27.8, 34.6, 1.5], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[67.4, 25.7, 125.9], [66.6, -38.7, -10.1], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[75.1, -21.4, 122.5], [-17.5, -31.0, 4.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[42.7, -66.4, 124.2], [-47.7, -41.1, -2.1], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-2.1, -88.6, 122.8], [-29.6, -5.3, -1.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-52.1, -78.6, 117.3], [-42.2, 33.8, -6.8], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-72.2, -6.5, 104.4], [16.8, 80.4, -10.7], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-28.6, 45.7, 90.9], [47.4, 37.5, -9.5], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[67.1, 63.6, 78.6], [77.1, -44.5, -5.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[89.1, -11.8, 67.7], [0.0, -73.3, -5.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[40.5, -79.2, 62.3], [-63.5, -36.7, -5.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-36.4, -80.2, 59.6], [-60.1, 26.4, -8.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-69.2, -19.3, 47.0], [0.0, 73.3, -5.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-22.4, 39.1, 34.8], [63.5, 36.7, -5.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[40.6, 46.0, 32.9], [25.4, -23.1, -7.5], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[66.2, 11.0, 24.6], [13.7, -51.4, -1.8], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[32.0, -49.3, 24.4], [-51.1, -50.1, -1.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-51.1, -45.3, 15.7], [-38.0, 52.2, -16.2], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]], [[-122.9, 124.2, -36.0], [-21.3, 64.5, -18.3], [0.0, 0.0, 5.0], [0.0, 0.0, 0.5]]]) }), 'Pig 2': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'Length': 90.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 ], [[[0.0, 0.0, 0.0], [30.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[30.0, 0.0, 0.0], [30.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[60.0, 0.0, 0.0], [30.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[90.0, 0.0, 0.0], [30.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]]]) }), } @staticmethod def getName(): return '3D Colon 1' @staticmethod def getParameterSetNames(): return [ 'Default', 'Human 1', 'Human 2', 'Mouse 1', 'Mouse 2', 'Pig 1', 'Pig 2' ] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages[ 'Human 2'] elif 'Mouse 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages[ 'Mouse 1'] elif 'Mouse 2' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages[ 'Mouse 2'] elif 'Pig 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 1'] elif 'Pig 2' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 2'] else: centralPathOption = cls.centralPathDefaultScaffoldPackages[ 'Human 1'] if 'Mouse' in parameterSetName: segmentProfileOption = ScaffoldPackage( MeshType_3d_colonsegment1, defaultParameterSetName='Mouse 1') elif 'Pig' in parameterSetName: segmentProfileOption = ScaffoldPackage( MeshType_3d_colonsegment1, defaultParameterSetName='Pig 1') else: segmentProfileOption = ScaffoldPackage( MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { 'Central path': copy.deepcopy(centralPathOption), 'Segment profile': segmentProfileOption, 'Number of segments': 30, 'Start phase': 0.0, 'Proximal length': 420.0, 'Transverse length': 460.0, 'Distal length': 620.0, 'Proximal inner radius': 43.5, 'Proximal tenia coli width': 10.0, 'Proximal-transverse inner radius': 33.0, 'Proximal-transverse tenia coli width': 10.0, 'Transverse-distal inner radius': 29.0, 'Transverse-distal tenia coli width': 10.0, 'Distal inner radius': 31.5, 'Distal tenia coli width': 10.0, 'Refine': False, 'Refine number of elements around': 1, 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } if 'Human 2' in parameterSetName: options['Proximal length'] = 180.0 options['Transverse length'] = 620.0 options['Distal length'] = 700.0 elif 'Mouse' in parameterSetName: options['Number of segments'] = 10 options['Proximal length'] = 30.0 options['Transverse length'] = 20.0 options['Distal length'] = 25.0 options['Proximal inner radius'] = 1.0 options['Proximal tenia coli width'] = 0.5 options['Proximal-transverse inner radius'] = 0.9 options['Proximal-transverse tenia coli width'] = 0.7 options['Transverse-distal inner radius'] = 0.7 options['Transverse-distal tenia coli width'] = 1.0 options['Distal inner radius'] = 0.7 options['Distal tenia coli width'] = 1.0 elif 'Pig 1' in parameterSetName: options['Number of segments'] = 120 options['Proximal length'] = 2610.0 options['Transverse length'] = 200.0 options['Distal length'] = 200.0 options['Proximal inner radius'] = 20.0 options['Proximal tenia coli width'] = 5.0 options['Proximal-transverse inner radius'] = 10.5 options['Proximal-transverse tenia coli width'] = 5.0 options['Transverse-distal inner radius'] = 8.0 options['Transverse-distal tenia coli width'] = 5.0 options['Distal inner radius'] = 8.0 options['Distal tenia coli width'] = 5.0 elif 'Pig 2' in parameterSetName: options['Number of segments'] = 3 options['Proximal length'] = 30.0 options['Transverse length'] = 30.0 options['Distal length'] = 30.0 options['Proximal inner radius'] = 16.0 options['Proximal tenia coli width'] = 5.0 options['Proximal-transverse inner radius'] = 16.0 options['Proximal-transverse tenia coli width'] = 5.0 options['Transverse-distal inner radius'] = 16.0 options['Transverse-distal tenia coli width'] = 5.0 options['Distal inner radius'] = 16.0 options['Distal tenia coli width'] = 5.0 return options @staticmethod def getOrderedOptionNames(): return [ 'Central path', 'Segment profile', 'Number of segments', 'Start phase', 'Proximal length', 'Transverse length', 'Distal length', 'Proximal inner radius', 'Proximal tenia coli width', 'Proximal-transverse inner radius', 'Proximal-transverse tenia coli width', 'Transverse-distal inner radius', 'Transverse-distal tenia coli width', 'Distal inner radius', 'Distal tenia coli width', '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 == 'Segment profile': return [MeshType_3d_colonsegment1] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.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 == 'Segment profile': if not parameterSetName: parameterSetName = scaffoldType.getParameterSetNames()[0] return ScaffoldPackage(scaffoldType, defaultParameterSetName=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['Segment profile'].getScaffoldType( ) in cls.getOptionValidScaffoldTypes('Segment profile'): options['Segment profile'] = cls.getOptionScaffoldPackage( 'Segment profile', MeshType_3d_colonsegmentteniacoli1) for key in [ 'Number of segments', 'Refine number of elements around', 'Refine number of elements along', 'Refine number of elements through wall' ]: if options[key] < 1: options[key] = 1 for key in [ 'Proximal length', 'Transverse length', 'Distal length', 'Proximal inner radius', 'Proximal tenia coli width', 'Proximal-transverse inner radius', 'Proximal-transverse tenia coli width', 'Transverse-distal inner radius', 'Transverse-distal tenia coli width', 'Distal inner radius', 'Distal tenia coli width' ]: if options[key] < 0.0: options[key] = 0.0 @staticmethod def generateBaseMesh(region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ centralPath = options['Central path'] segmentProfile = options['Segment profile'] segmentCount = options['Number of segments'] startPhase = options['Start phase'] % 360.0 proximalLength = options['Proximal length'] transverseLength = options['Transverse length'] distalLength = options['Distal length'] proximalInnerRadius = options['Proximal inner radius'] proximalTCWidth = options['Proximal tenia coli width'] proximalTransverseInnerRadius = options[ 'Proximal-transverse inner radius'] proximalTransverseTCWidth = options[ 'Proximal-transverse tenia coli width'] transverseDistalInnerRadius = options['Transverse-distal inner radius'] transverseDistalTCWidth = options['Transverse-distal tenia coli width'] distalInnerRadius = options['Distal inner radius'] distalTCWidth = options['Distal tenia coli width'] segmentSettings = segmentProfile.getScaffoldSettings() elementsCountAroundTC = segmentSettings[ 'Number of elements around tenia coli'] elementsCountAroundHaustrum = segmentSettings[ 'Number of elements around haustrum'] cornerInnerRadiusFactor = segmentSettings['Corner inner radius factor'] haustrumInnerRadiusFactor = segmentSettings[ 'Haustrum inner radius factor'] segmentLengthEndDerivativeFactor = segmentSettings[ 'Segment length end derivative factor'] segmentLengthMidDerivativeFactor = segmentSettings[ 'Segment length mid derivative factor'] tcCount = segmentSettings['Number of tenia coli'] tcThickness = segmentSettings['Tenia coli thickness'] elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount elementsCountAlongSegment = segmentSettings[ 'Number of elements along segment'] elementsCountThroughWall = segmentSettings[ 'Number of elements through wall'] wallThickness = segmentSettings['Wall thickness'] useCrossDerivatives = segmentSettings['Use cross derivatives'] useCubicHermiteThroughWall = not ( segmentSettings['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment * segmentCount) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine( cx, cd1, fixAllDirections=True, magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength( cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount # print('Length = ', length) # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves( cx, cd1, elementsCountAlongSegment * segmentCount) sd2 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf)[0] # Generate variation of radius & tc width along length lengthList = [ 0.0, proximalLength, proximalLength + transverseLength, length ] innerRadiusList = [ proximalInnerRadius, proximalTransverseInnerRadius, transverseDistalInnerRadius, distalInnerRadius ] innerRadiusAlongElementList, dInnerRadiusAlongElementList = interp.sampleParameterAlongLine( lengthList, innerRadiusList, elementsCountAlong) tcWidthList = [ proximalTCWidth, proximalTransverseTCWidth, transverseDistalTCWidth, distalTCWidth ] tcWidthAlongElementList, dTCWidthAlongElementList = interp.sampleParameterAlongLine( lengthList, tcWidthList, elementsCountAlong) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] # Create object colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactor, innerRadiusAlongElementList, dInnerRadiusAlongElementList, tcWidthAlongElementList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroups, annotationArray, \ faceMidPointsZ = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, segmentLength, sx, sd1, sd2, elementsCountAround, elementsCountAlongSegment, nSegment, faceMidPointsZ) # Store points along length xExtrude = xExtrude + (xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:]) d1Extrude = d1Extrude + (d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:]) d2Extrude = d2Extrude + (d2WarpedList if nSegment == 0 else d2WarpedList[elementsCountAround:]) d3UnitExtrude = d3UnitExtrude + ( d3WarpedUnitList if nSegment == 0 else d3WarpedUnitList[elementsCountAround:]) contractedWallThicknessList = colonSegmentTubeMeshInnerPoints.getContractedWallThicknessList( ) # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner( xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, contractedWallThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) relaxedLengthList, xiList = colonSegmentTubeMeshInnerPoints.getRelaxedLengthAndXiList( ) if tcThickness > 0: tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList( ) xList, d1List, d2List, d3List, annotationGroups, annotationArray = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tubeTCWidthList, tcThickness, sx, annotationGroups, annotationArray) # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = createFlatAndTextureCoordinatesTeniaColi( xiList, relaxedLengthList, length, wallThickness, tcCount, tcThickness, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroups, annotationArray, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives) else: # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, relaxedLengthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroups, annotationArray, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives) return annotationGroups @classmethod def generateMesh(cls, region, options): """ Generate base or refined mesh. :param region: Zinc region to create mesh in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: list of AnnotationGroup for mesh. """ if not options['Refine']: return cls.generateBaseMesh(region, options) refineElementsCountAround = options['Refine number of elements around'] refineElementsCountAlong = options['Refine number of elements along'] refineElementsCountThroughWall = options[ 'Refine number of elements through wall'] baseRegion = region.createRegion() baseAnnotationGroups = cls.generateBaseMesh(baseRegion, options) meshrefinement = MeshRefinement(baseRegion, region, baseAnnotationGroups) meshrefinement.refineAllElementsCubeStandard3d( refineElementsCountAround, refineElementsCountAlong, refineElementsCountThroughWall) return meshrefinement.getAnnotationGroups()
class MeshType_3d_brainstem1(Scaffold_base): """ Generates a tapered cylinder for the brainstem based on solid cylinder mesh, with variable numbers of elements in major, minor and length directions. Regions of the brainstem are annotated. """ centralPathDefaultScaffoldPackages = { 'Brainstem 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 3.0, 'Number of elements': 6 }, 'meshEdits': exnodeStringFromNodeValues( # dimensional. [ 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 ], [[[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 2.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 3.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 4.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 5.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 6.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 7.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], [[0.0, 0.0, 8.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.0, 0.0], [0.0, 0.0, 0.0]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1', 'name': get_brainstem_term('medulla oblongata')[0], 'ontId': get_brainstem_term('medulla oblongata')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '2', 'name': get_brainstem_term('pons')[0], 'ontId': get_brainstem_term('pons')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '3', 'name': get_brainstem_term('midbrain')[0], 'ontId': get_brainstem_term('midbrain')[1] } ] }), 'Cat 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 3.0, 'Number of elements': 6 }, 'meshEdits': exnodeStringFromNodeValues( # dimensional. [ 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 ], [ # [ [0.0,1.0,-5.0], [0.0,0.0,4.5], [5.0,0.0,0.0], [1.0,0.0,0.0], [0.0,2.4,0.0], [0.0,2.2,0.0] ], # [ [0.0,1.0,-0.5], [0.0,0.0,4.5], [6.0,0.0,0.0], [1.0,0.0,0.0], [0.0,4.0,0.0], [0.0,1.1,0.0] ], # [ [0.0,1.0, 4.0], [0.0,0.0,4.5], [7.0,0.0,0.0], [1.0,0.0,0.0], [0.0,4.5,0.0], [0.0,0.8,0.0] ], # [ [0.0,1.0, 8.5], [0.0,0.0,4.5], [8.0,0.0,0.0], [1.0,0.0,0.0], [0.0,5.5,0.0], [0.0,0.8,0.0] ], # [ [0.0,1.0,13.0], [0.0,0.0,4.5], [9.0,0.0,0.0], [1.0,0.0,0.0], [0.0,6.0,0.0], [0.0,0.2,0.0] ] [[0.0, 10.7, -12.3], [0.0, -3.8, 3.1], [4.8, 0.0, 0.0], [-0.7, 0.0, 0.0], [-0.0, 2.2, 2.6], [0.0, 0.5, 0.1]], [[0.0, 6.8, -8.8], [0.0, -4.0, 3.9], [4.5, 0.0, 0.0], [0.1, 0.0, 0.0], [-0.0, 2.7, 2.7], [0.0, 0.5, 0.1]], [[0.0, 2.8, -4.5], [0.0, -3.5, 4.2], [5.0, 0.0, 0.0], [1.2, 0.0, 0.0], [-0.0, 3.2, 2.8], [0.0, 0.5, 0.0]], [[0.0, -0.2, -0.5], [0.0, -2.8, 3.8], [6.8, 0.0, 0.0], [0.8, 0.0, 0.0], [-0.0, 3.8, 2.8], [0.0, 0.6, -0.4]], [[0.0, -2.8, 3.0], [0.0, -1.9, 4.1], [6.8, 0.0, 0.0], [-0.6, 0.0, 0.0], [-0.0, 4.5, 2.0], [0.0, 0.3, -0.1]], [[0.0, -3.8, 7.5], [0.0, -2.7, 4.6], [5.5, 0.0, 0.0], [-0.2, 0.0, 0.0], [-0.0, 4.3, 2.5], [0.0, -1.0, 1.0]], [[0.0, -8.2, 11.5], [0.0, -5.9, 3.2], [6.8, 0.0, 0.0], [2.8, 0.0, 0.0], [-0.0, 2.3, 4.2], [0.0, -3.1, 2.4]] ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1', 'name': get_brainstem_term('medulla oblongata')[0], 'ontId': get_brainstem_term('medulla oblongata')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '2', 'name': get_brainstem_term('pons')[0], 'ontId': get_brainstem_term('pons')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '3', 'name': get_brainstem_term('midbrain')[0], 'ontId': get_brainstem_term('midbrain')[1] } ] }), 'Human 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, 'Number of elements': 6 }, 'meshEdits': exnodeStringFromNodeValues( # dimensional. [ 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 ], [[[0.0, 18.9, -50.7], [0.0, -3.2, 15.4], [7.8, 0.0, 0.0], [0.5, 0.0, 0.0], [-0.0, 6.1, 1.3], [0.0, 0.8, 1.7]], [[0.0, 14.6, -36.3], [0.0, -5.4, 13.3], [8.5, 0.0, 0.0], [0.9, 0.0, 0.0], [-0.0, 7.2, 2.9], [0.0, 1.4, 1.6]], [[0.0, 8.3, -24.1], [0.0, -6.4, 12.5], [9.6, 0.0, 0.0], [4.4, 0.0, 0.0], [-0.0, 8.9, 4.6], [0.0, 1.3, 0.5]], [[0.0, 1.8, -11.4], [0.0, -5.3, 13.3], [17.4, 0.0, 0.0], [5.3, 0.0, 0.0], [-0.0, 9.8, 3.9], [0.0, 2.6, -0.2]], [[0.0, -2.3, 2.4], [0.0, -3.9, 13.2], [20.2, 0.0, 0.0], [-0.4, 0.0, 0.0], [-0.0, 14.1, 4.2], [0.0, 2.2, -0.5]], [[0.0, -6.0, 15.0], [0.0, -2.6, 12.9], [16.8, 0.0, 0.0], [-2.4, 0.0, 0.0], [-0.0, 14.4, 2.9], [0.0, 0.2, -1.9]], [[0.0, -7.5, 28.0], [0.0, -0.4, 13.1], [15.3, 0.0, 0.0], [-0.6, 0.0, 0.0], [-0.0, 14.5, 0.4], [0.0, 0.0, -3.1]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', 'name': get_brainstem_term('medulla oblongata')[0], 'ontId': get_brainstem_term('medulla oblongata')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '3-4', 'name': get_brainstem_term('pons')[0], 'ontId': get_brainstem_term('pons')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '5-6', 'name': get_brainstem_term('midbrain')[0], 'ontId': get_brainstem_term('midbrain')[1] } ] }), 'Mouse 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, 'Number of elements': 6 }, 'meshEdits': exnodeStringFromNodeValues( # dimensional. [ 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 ], [([[0.0, 1.5, -3.4], [0.0, -0.1, 1.1], [1.4, 0.0, 0.0], [-0.1, 0.0, 0.0], [0.0, 1.0, 0.1], [0.0, 0.1, 0.9]]), ([[0.0, 1.0, -2.3], [0.0, -0.8, 1.0], [1.3, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.8, 0.7], [0.0, 0.0, 0.6]]), ([[0.0, -0.1, -1.6], [0.0, -1.2, 0.8], [1.5, 0.0, 0.0], [0.4, 0.0, 0.0], [0.0, 0.7, 1.0], [0.0, 0.1, 0.1]]), ([[0.0, -1.2, -0.7], [0.0, -0.7, 1.2], [2.0, 0.0, 0.0], [0.2, 0.0, 0.0], [0.0, 1.2, 0.7], [0.0, 0.1, -0.1]]), ([[0.0, -1.5, 0.5], [0.0, 0.1, 1.4], [2.0, 0.0, 0.0], [-0.1, 0.0, 0.0], [0.0, 1.4, -0.1], [0.0, 0.1, -0.1]]), ([[0.0, -1.1, 1.9], [0.0, -0.3, 1.4], [1.6, 0.0, 0.0], [-0.1, 0.0, 0.0], [0.0, 1.5, 0.3], [0.0, -0.3, 0.3]]), ([[0.0, -2.1, 3.1], [0.0, -1.3, 0.8], [2.0, 0.0, 0.0], [0.8, 0.0, 0.0], [0.0, 0.7, 1.2], [0.0, -0.8, 0.7]])]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', 'name': get_brainstem_term('medulla oblongata')[0], 'ontId': get_brainstem_term('medulla oblongata')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '3-4', 'name': get_brainstem_term('pons')[0], 'ontId': get_brainstem_term('pons')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '5-6', 'name': get_brainstem_term('midbrain')[0], 'ontId': get_brainstem_term('midbrain')[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( # dimensional. [ 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 ], [[[0.0, 2.9, -5.4], [0.0, 0.5, 1.7], [1.9, 0.0, 0.0], [-0.2, 0.0, 0.0], [0.0, 1.3, -0.4], [-0.0, 0.2, 1.3]], [[0.0, 2.7, -3.5], [0.0, -0.9, 2.0], [1.8, 0.0, 0.0], [0.0, 0.0, 0.0], [-0.0, 1.4, 0.6], [-0.0, 0.0, 0.8]], [[0.0, 1.1, -1.8], [0.0, -1.4, 1.7], [2.0, 0.0, 0.0], [0.5, 0.0, 0.0], [-0.0, 1.3, 1.1], [0.0, 0.1, 0.2]], [[0.0, -0.1, -0.2], [0.0, -1.1, 1.5], [2.7, 0.0, 0.0], [0.3, 0.0, 0.0], [-0.0, 1.5, 1.1], [0.0, 0.2, -0.2]], [[0.0, -1.1, 1.2], [0.0, -0.7, 1.6], [2.7, 0.0, 0.0], [-0.2, 0.0, 0.0], [-0.0, 1.8, 0.8], [0.0, 0.1, -0.1]], [[0.0, -1.5, 3.0], [0.0, -1.1, 1.9], [2.2, 0.0, 0.0], [-0.1, 0.0, 0.0], [-0.0, 1.7, 1.0], [0.0, -0.4, 0.4]], [[0.0, -3.3, 4.6], [0.0, -2.4, 1.3], [2.7, 0.0, 0.0], [1.1, 0.0, 0.0], [-0.0, 0.9, 1.7], [0.0, -1.2, 1.0]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', 'name': get_brainstem_term('medulla oblongata')[0], 'ontId': get_brainstem_term('medulla oblongata')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '3-4', 'name': get_brainstem_term('pons')[0], 'ontId': get_brainstem_term('pons')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '5-6', 'name': get_brainstem_term('midbrain')[0], 'ontId': get_brainstem_term('midbrain')[1] } ] }), 'Pig 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, 'Number of elements': 6 }, 'meshEdits': exnodeStringFromNodeValues( # dimensional. [ 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 ], [([[0.0, 25.6, -29.3], [0.0, -5.4, 3.5], [4.8, 0.0, 0.0], [-0.7, 0.0, 0.0], [0.0, 1.8, 2.9], [0.0, 1.1, 1.4]]), ([[0.0, 19.5, -25.3], [0.0, -6.7, 4.8], [5.7, 0.0, 0.0], [2.5, 0.0, 0.0], [0.0, 2.8, 4.0], [0.0, 0.8, 0.7]]), ([[0.0, 12.2, -19.9], [0.0, -6.7, 5.4], [10.1, 0.0, 0.0], [3.0, 0.0, 0.0], [0.0, 3.3, 4.2], [0.0, 1.5, 0.5]]), ([[0.0, 6.0, -14.5], [0.0, -5.5, 6.3], [12.9, -0.2, -0.2], [0.7, 0.0, 0.0], [0.1, 5.7, 4.9], [0.0, 2.0, -0.6]]), ([[0.0, 1.5, -7.4], [0.0, -2.8, 7.0], [11.4, 0.0, 0.0], [-0.3, 0.2, 0.0], [0.0, 7.4, 3.0], [-0.2, 2.4, -1.2]]), ([[0.0, 0.1, -1.0], [0.0, -1.5, 6.9], [11.2, 0.3, 0.1], [-0.5, 0.1, 0.1], [-0.3, 11.3, 2.5], [-0.1, 1.5, -0.2] ]), ([[0.0, -1.5, 6.6], [0.0, -2.0, 7.4], [10.3, 0.2, 0.0], [-1.3, -0.2, -0.0], [-0.2, 9.4, 2.5], [0.2, -2.3, 0.9]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', 'name': get_brainstem_term('medulla oblongata')[0], 'ontId': get_brainstem_term('medulla oblongata')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '3-4', 'name': get_brainstem_term('pons')[0], 'ontId': get_brainstem_term('pons')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '5-6', 'name': get_brainstem_term('midbrain')[0], 'ontId': get_brainstem_term('midbrain')[1] } ] }), 'Sheep 1': ScaffoldPackage( MeshType_1d_path1, { 'scaffoldSettings': { 'Coordinate dimensions': 3, 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, 'Number of elements': 6 }, 'meshEdits': exnodeStringFromNodeValues( # dimensional. [ 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 ], [([[0.0, 21.3, -33.2], [0.0, -7.5, 6.0], [4.8, 0.0, 0.0], [4.8, -0.0, -0.0], [0.0, 2.8, 3.5], [0.0, 3.2, 1.3]]), ([[0.0, 14.5, -26.7], [0.0, -6.1, 7.2], [8.5, -0.0, -0.0], [2.6, 0.0, 0.0], [0.0, 4.9, 4.1], [-0.0, 1.1, 0.1]]), ([[0.0, 9.2, -19.0], [0.0, -5.2, 7.2], [10.1, 0.0, 0.0], [1.1, -0.1, -0.0], [0.0, 5.0, 3.6], [0.1, 0.4, -0.6]]), ([[0.0, 4.0, -12.2], [0.0, -3.5, 7.0], [10.8, -0.2, -0.1], [-0.4, 0.2, 0.0], [0.1, 5.7, 2.9], [-0.1, 0.8, -1.4]]), ([[0.0, 2.1, -5.5], [0.0, -1.2, 7.6], [9.4, 0.3, 0.1], [0.1, 0.2, 0.1], [-0.2, 6.6, 1.0], [-0.2, 2.2, -0.3]]), ([[0.0, 1.9, 2.9], [0.0, -2.1, 8.8], [11.2, 0.2, 0.1], [3.3, -0.1, -0.0], [-0.2, 10.4, 2.5], [0.1, 0.3, 2.0]]), ([[0.0, -2.3, 11.4], [0.0, -6.2, 8.1], [16.2, 0.1, 0.0], [6.7, -0.2, -0.0], [-0.0, 6.7, 5.1], [0.3, -7.7, 3.2]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', 'name': get_brainstem_term('medulla oblongata')[0], 'ontId': get_brainstem_term('medulla oblongata')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '3-4', 'name': get_brainstem_term('pons')[0], 'ontId': get_brainstem_term('pons')[1] }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '5-6', 'name': get_brainstem_term('midbrain')[0], 'ontId': get_brainstem_term('midbrain')[1] } ] }) } @staticmethod def getName(): return '3D Brainstem 1' @staticmethod def getParameterSetNames(): return [ 'Default', 'Cat 1', 'Human 1', 'Mouse 1', 'Rat 1', 'Pig 1', 'Sheep 1' ] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if parameterSetName == 'Default': parameterSetName = 'Human 1' if 'Cat 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Cat 1'] if 'Human 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages[ 'Human 1'] if 'Mouse 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages[ 'Mouse 1'] if 'Rat 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] if 'Pig 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 1'] if 'Sheep 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages[ 'Sheep 1'] options = { 'Base parameter set': parameterSetName, 'Central path': copy.deepcopy(centralPathOption), 'Number of elements across major': 6, 'Number of elements across minor': 6, 'Number of elements along': 8, 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements across major and minor': 1, 'Refine number of elements along': 1 } return options @staticmethod def getOrderedOptionNames(): return [ 'Central path', 'Number of elements across major', 'Number of elements across minor', 'Number of elements along', 'Refine', 'Refine number of elements across major and minor', 'Refine number of elements along' ] @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': return [MeshType_1d_path1] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': return list(cls.centralPathDefaultScaffoldPackages.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]) 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) dependentChanges = False if options['Number of elements across major'] < 4: options['Number of elements across major'] = 4 if options['Number of elements across major'] % 2: options['Number of elements across major'] += 1 if options['Number of elements across minor'] < 4: options['Number of elements across minor'] = 4 if options['Number of elements across minor'] % 2: options['Number of elements across minor'] += 1 if options['Number of elements along'] < 2: options['Number of elements along'] = 2 return dependentChanges @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 """ parameterSetName = options['Base parameter set'] isCat = 'Cat 1' in parameterSetName isHuman = 'Human 1' in parameterSetName isMouse = 'Mouse 1' in parameterSetName isRat = 'Rat 1' in parameterSetName isPig = 'Pig 1' in parameterSetName isSheep = 'Sheep 1' in parameterSetName centralPath = options['Central path'] brainstemPath = cls.centralPathDefaultScaffoldPackages['Brainstem 1'] elementsCountAcrossMajor = options['Number of elements across major'] elementsCountAcrossMinor = options['Number of elements across minor'] elementsCountAlong = options['Number of elements along'] # Cross section at Z axis halfBrainStem = False if halfBrainStem: elementsCountAcrossMajor //= 2 elementsPerLayer = ( (elementsCountAcrossMajor - 2) * elementsCountAcrossMinor) + (2 * (elementsCountAcrossMinor - 2)) fm = region.getFieldmodule() cache = fm.createFieldcache() coordinates = findOrCreateFieldCoordinates(fm) mesh = fm.findMeshByDimension(3) # Annotation groups brainstemGroup = AnnotationGroup(region, get_brainstem_term('brainstem')) brainstemMeshGroup = brainstemGroup.getMeshGroup(mesh) midbrainGroup = AnnotationGroup(region, get_brainstem_term('midbrain')) midbrainMeshGroup = midbrainGroup.getMeshGroup(mesh) ponsGroup = AnnotationGroup(region, get_brainstem_term('pons')) ponsMeshGroup = ponsGroup.getMeshGroup(mesh) medullaGroup = AnnotationGroup(region, get_brainstem_term('medulla oblongata')) medullaMeshGroup = medullaGroup.getMeshGroup(mesh) annotationGroups = [ brainstemGroup, midbrainGroup, ponsGroup, medullaGroup ] annotationGroupAlong = [[brainstemGroup, midbrainGroup], [brainstemGroup, ponsGroup], [brainstemGroup, medullaGroup]] # point markers # centralCanal = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('central canal of spinal cord')) # cerebralAqueduct = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('cerebral aqueduct')) # foramenCaecum = findOrCreateAnnotationGroupForTerm(annotationGroups, region, # get_brainstem_term('foramen caecum of medulla oblongata')) dorsalMidCaudalGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem dorsal midline caudal point')) ventralMidCaudalGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem ventral midline caudal point')) dorsalMidCranGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem dorsal midline cranial point')) ventralMidCranGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term('brainstem ventral midline cranial point')) dorsalMidMedullaPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem dorsal midline pons-medulla junction')) ventralMidMedullaPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem ventral midline pons-medulla junction')) dorsalMidMidbrainPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem dorsal midline midbrain-pons junction')) ventralMidMidbrainPonsJunction = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term( 'brainstem ventral midline midbrain-pons junction')) ####################### # CREATE MAIN BODY MESH ####################### cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if not halfBrainStem else CylinderShape.CYLINDER_SHAPE_LOWER_HALF # Body coordinates cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong) base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, centre=[0.0, 0.0, 0.0], alongAxis=cylinderCentralPath.alongAxis[0], majorAxis=cylinderCentralPath.majorAxis[0], minorRadius=cylinderCentralPath.minorRadii[0]) cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) brainstem_coordinates = findOrCreateFieldCoordinates( fm, name="brainstem coordinates") # Brain coordinates tmp_region = region.createRegion() tmp_fm = tmp_region.getFieldmodule() tmp_brainstem_coordinates = findOrCreateFieldCoordinates( tmp_fm, name="brainstem coordinates") cylinderCentralPath1 = CylinderCentralPath(tmp_region, brainstemPath, elementsCountAlong) base1 = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, centre=[0.0, 0.0, 0.0], alongAxis=cylinderCentralPath1.alongAxis[0], majorAxis=cylinderCentralPath1.majorAxis[0], minorRadius=cylinderCentralPath1.minorRadii[0]) cylinder2 = CylinderMesh(tmp_fm, tmp_brainstem_coordinates, elementsCountAlong, base1, cylinderShape=cylinderShape, cylinderCentralPath=cylinderCentralPath1, useCrossDerivatives=False) # Write two coordinates sir = tmp_region.createStreaminformationRegion() srm = sir.createStreamresourceMemory() tmp_region.write(sir) result, buffer = srm.getBuffer() sir = region.createStreaminformationRegion() srm = sir.createStreamresourceMemoryBuffer(buffer) region.read(sir) del srm del sir del tmp_fm del tmp_brainstem_coordinates del tmp_region # Annotating groups iRegionBoundaries = [ int(6 * elementsCountAlong / 15), int(13 * elementsCountAlong / 15) ] for elementIdentifier in range(1, mesh.getSize() + 1): element = mesh.findElementByIdentifier(elementIdentifier) brainstemMeshGroup.addElement(element) if elementIdentifier > (iRegionBoundaries[-1] * elementsPerLayer): midbrainMeshGroup.addElement(element) elif (elementIdentifier > (iRegionBoundaries[0] * elementsPerLayer)) and ( elementIdentifier <= (iRegionBoundaries[-1] * elementsPerLayer)): ponsMeshGroup.addElement(element) else: medullaMeshGroup.addElement(element) ################ # point markers ################ pointMarkers = [ { "group": dorsalMidCaudalGroup, "marker_brainstem_coordinates": [0.0, 1.0, 0.0] }, { "group": ventralMidCaudalGroup, "marker_brainstem_coordinates": [0.0, -1.0, 0.0] }, { "group": dorsalMidCranGroup, "marker_brainstem_coordinates": [0.0, 1.0, 8.0] }, { "group": ventralMidCranGroup, "marker_brainstem_coordinates": [0.0, -1.0, 8.0] }, { "group": dorsalMidMedullaPonsJunction, "marker_brainstem_coordinates": [0.0, 1.0, 3.0] }, { "group": ventralMidMedullaPonsJunction, "marker_brainstem_coordinates": [0.0, -1.0, 3.0] }, { "group": dorsalMidMidbrainPonsJunction, "marker_brainstem_coordinates": [0.0, 1.0, 6.0] }, { "group": ventralMidMidbrainPonsJunction, "marker_brainstem_coordinates": [0.0, -1.0, 6.0] }, ] markerGroup = findOrCreateFieldGroup(fm, "marker") markerName = findOrCreateFieldStoredString(fm, name="marker_name") markerLocation = findOrCreateFieldStoredMeshLocation( fm, mesh, name="marker_location") nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() markerBrainstemCoordinates = findOrCreateFieldCoordinates( fm, name="marker_body_coordinates") markerTemplateInternal = nodes.createNodetemplate() markerTemplateInternal.defineField(markerName) markerTemplateInternal.defineField(markerLocation) markerTemplateInternal.defineField(markerBrainstemCoordinates) cache = fm.createFieldcache() brainstemNodesetGroup = brainstemGroup.getNodesetGroup(nodes) nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) findMarkerLocation = fm.createFieldFindMeshLocation( markerBrainstemCoordinates, brainstem_coordinates, mesh) findMarkerLocation.setSearchMode( FieldFindMeshLocation.SEARCH_MODE_EXACT) for pointMarker in pointMarkers: group = pointMarker["group"] markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) cache.setNode(markerPoint) markerBrainstemCoordinates.assignReal( cache, pointMarker["marker_brainstem_coordinates"]) markerName.assignString(cache, group.getName()) element, xi = findMarkerLocation.evaluateMeshLocation(cache, 3) markerLocation.assignMeshLocation(cache, element, xi) group.getNodesetGroup(nodes).addNode(markerPoint) brainstemNodesetGroup.addNode(markerPoint) nodeIdentifier += 1 return annotationGroups @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(). """ assert isinstance(meshRefinement, MeshRefinement) refineElementsCountAcrossMajor = options[ 'Refine number of elements across major and minor'] refineElementsCountAlong = options['Refine number of elements along'] meshRefinement.refineAllElementsCubeStandard3d( refineElementsCountAcrossMajor, refineElementsCountAlong, refineElementsCountAcrossMajor) @classmethod def defineFaceAnnotations(cls, region, options, annotationGroups): """ Add face annotation groups from the 1D mesh. :param region: Zinc region containing model. :param options: Dict containing options. See getDefaultOptions(). :param annotationGroups: List of annotation groups for ventral-level elements. New point annotation groups are appended to this list. """ # create groups fm = region.getFieldmodule() mesh2d = fm.findMeshByDimension(2) is_exterior = fm.createFieldIsExterior() is_exterior_face_xi1 = fm.createFieldOr( fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_0)), fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI1_1))) is_exterior_face_xi2 = fm.createFieldOr( fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_0)), fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI2_1))) is_exterior_face_xi3 = fm.createFieldOr( fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)), fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1))) # external regions groupNames = ['brainstem', 'midbrain', 'medulla oblongata', 'pons'] for groupName in groupNames: subGroup = AnnotationGroup(region, get_brainstem_term(groupName)) issub = subGroup.getFieldElementGroup(mesh2d) is_subface_ext = fm.createFieldOr( fm.createFieldAnd(issub, is_exterior_face_xi1), fm.createFieldAnd(issub, is_exterior_face_xi3)) subFaceGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term(groupName + ' exterior')) subFaceGroup.getMeshGroup(mesh2d).addElementsConditional( is_subface_ext) # brainstem interface groupNames = [ 'brainstem-spinal cord interface', 'thalamus-brainstem interface' ] for groupName in groupNames: subGroupName = 'midbrain' if groupName == 'thalamus-brainstem interface' else 'medulla oblongata' subGroup = AnnotationGroup(region, get_brainstem_term(subGroupName)) issub = subGroup.getFieldElementGroup(mesh2d) is_subface_ext = fm.createFieldAnd(issub, is_exterior_face_xi2) subFaceGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_brainstem_term(groupName)) subFaceGroup.getMeshGroup(mesh2d).addElementsConditional( is_subface_ext)