From 7c45c8c253b8e9bfa1fcf8e4d4d72582501a2189 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Fri, 3 Jun 2022 17:45:23 +1200 Subject: [PATCH 01/26] first attempt to make the new bladder. --- .../meshtypes/meshtype_3d_bladder1.py | 1323 +++++++---------- 1 file changed, 533 insertions(+), 790 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 921dbb46..9bf03091 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -1,5 +1,6 @@ """ -Generates a 3-D bladder mesh with variable numbers of elements around and up. +Generates a 3-D bladder mesh along the central line, with variable +numbers of elements around , along and through wall. """ from __future__ import division @@ -7,88 +8,211 @@ import copy import math -from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates +from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates, findOrCreateFieldGroup, \ + findOrCreateFieldStoredString, findOrCreateFieldStoredMeshLocation, findOrCreateFieldNodeGroup +from opencmiss.utils.zinc.finiteelement import get_element_node_identifiers from opencmiss.zinc.element import Element from opencmiss.zinc.field import Field from opencmiss.zinc.node import Node -from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, findOrCreateAnnotationGroupForTerm, getAnnotationGroupForTerm +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups, \ + getAnnotationGroupForTerm, findOrCreateAnnotationGroupForTerm from scaffoldmaker.annotation.bladder_terms import get_bladder_term -from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1, generateOstiumMesh +from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1, extractPathParametersFromRegion from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp +from scaffoldmaker.utils import matrix from scaffoldmaker.utils import vector -from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d -from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear -from scaffoldmaker.utils.interpolation import getCubicHermiteBasis, smoothCubicHermiteDerivativesLine -from scaffoldmaker.utils.meshrefinement import MeshRefinement -from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition, calculate_surface_axes +from scaffoldmaker.utils.geometry import createEllipsePoints +from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues, mesh_destroy_elements_and_nodes_by_identifiers class MeshType_3d_bladder1(Scaffold_base): - ''' - 3-D bladder scaffold. - ''' - ostiumDefaultScaffoldPackages = { - 'Ostium Cat 1': ScaffoldPackage(MeshType_3d_ostium1, { + """ + Generates a 3-D bladder mesh with variable numbers of elements around, along the central line, and through wall. + The bladder is created using a central path as the longitudinal axis of the bladder. Magnitude of D2 and D3 are + the radii of the bladder in the respective direction. + """ + centralPathDefaultScaffoldPackages_Bladder = { + 'Cat 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, - 'Number of elements around ostium': 8, - 'Number of elements along': 2, - 'Number of elements through wall': 1, # not implemented for > 1 - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium diameter': 0.3, - 'Ostium length': 0.2, - 'Ostium wall thickness': 0.05, - 'Ostium inter-vessel distance': 0.8, - 'Ostium inter-vessel height': 0.0, - 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 0.15, - 'Vessel wall thickness': 0.04, - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, - 'Use linear through vessel wall': True, - # 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 7 + }, + 'meshEdits': exnodeStringFromNodeValues( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [[70.80, 72.30, 0.00], [-6.62, -16.41, -1.20], [38.60, -15.67, 1.49], [-8.82, -10.04, -1.62], [-2.26, -1.91, 38.59], [4.19, 4.77, 4.06]], + [[57.51, 51.14, -0.10], [-19.84, -25.60, 1.02], [30.18, -23.37, 0.26], [-8.02, -5.36, -0.83], [0.57, 1.21, 41.38], [1.49, 1.45, 1.53]], + [[30.29, 22.36, 2.55], [-25.83, -23.54, -0.03], [22.79, -25.01, 0.06], [-8.14, 1.29, 0.15], [-0.08, 0.03, 40.90], [-1.33, -0.83, -5.13]], + [[6.64, 3.83, 0.48], [-22.06, -14.48, -1.56], [14.08, -21.50, 0.48], [-6.95, 3.05, 0.10], [-1.93, -0.54, 32.24], [-0.40, -0.03, -9.52]], + [[-13.27, -6.98, -0.63], [-21.39, -9.64, -1.27], [8.45, -18.80, 0.34], [-4.94, 3.33, 0.35], [-1.24, -0.16, 22.07], [0.24, 0.77, -7.46]], + [[-36.03, -15.27, -2.05], [-21.61, -6.31, -1.44], [4.24, -14.80, 1.22], [-3.51, 4.96, 0.69], [-1.47, 1.02, 17.51], [0.02, 0.97, -6.00]], + [[-56.31, -19.78, -3.49], [-25.21, -4.17, -2.30], [1.33, -9.02, 1.75], [-2.24, 4.68, 0.72], [-1.24, 1.81, 10.27], [0.21, 0.99, -5.74]], + [[-86.41, -23.06, -6.84], [-34.94, -2.39, -4.40], [0.06, -5.95, 2.75], [-0.30, 1.46, 1.27], [-1.06, 3.10, 6.73], [0.15, 1.57, -1.34]]]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_bladder_term('dome of the bladder')[0], + 'ontId': get_bladder_term('dome of the bladder')[1] }, - }), - 'Ostium Rat 1': ScaffoldPackage(MeshType_3d_ostium1, { + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-7', + 'name': get_bladder_term('neck of urinary bladder')[0], + 'ontId': get_bladder_term('neck of urinary bladder')[1] + }] + }), + 'Human 1': ScaffoldPackage(MeshType_1d_path1, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, - 'Number of elements around ostium': 8, - 'Number of elements along': 1, - 'Number of elements through wall': 1, # not implemented for > 1 - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium diameter': 0.15, - 'Ostium length': 0.05, - 'Ostium wall thickness': 0.02, - 'Ostium inter-vessel distance': 0.8, - 'Ostium inter-vessel height': 0.0, - 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 0.04, - 'Vessel wall thickness': 0.01, - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, - 'Use linear through vessel wall': True, - # 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 7 + }, + 'meshEdits': exnodeStringFromNodeValues( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [ [ 70.80, 72.30, 0.00], [ -6.62, -16.41, -1.20], [ 38.60, -15.67, 1.49], [ -8.82, -10.04, -1.62], [ -2.26, -1.91, 38.59], [ 4.19, 4.77, 4.06] ], + [ [ 57.51, 51.14, -0.10], [ -19.84, -25.60, 1.02], [ 30.18, -23.37, 0.26], [ -8.02, -5.36, -0.83], [ 0.57, 1.21, 41.38], [ 1.49, 1.45, 1.53] ], + [ [ 30.29, 22.36, 2.55], [ -25.83, -23.54, -0.03], [ 22.79, -25.01, 0.06], [ -8.14, 1.29, 0.15], [ -0.08, 0.03, 40.90], [ -1.33, -0.83, -5.13] ], + [ [ 6.64, 3.83, 0.48], [ -22.06, -14.48, -1.56], [ 14.08, -21.50, 0.48], [ -6.95, 3.05, 0.10], [ -1.93, -0.54, 32.24], [ -0.40, -0.03, -9.52] ], + [ [ -13.27, -6.98, -0.63], [ -21.39, -9.64, -1.27], [ 8.45, -18.80, 0.34], [ -4.94, 3.33, 0.35], [ -1.24, -0.16, 22.07], [ 0.24, 0.77, -7.46] ], + [ [ -36.03, -15.27, -2.05], [ -21.61, -6.31, -1.44], [ 4.24, -14.80, 1.22], [ -3.51, 4.96, 0.69], [ -1.47, 1.02, 17.51], [ 0.02, 0.97, -6.00] ], + [ [ -56.31, -19.78, -3.49], [ -25.21, -4.17, -2.30], [ 1.33, -9.02, 1.75], [ -2.24, 4.68, 0.72], [ -1.24, 1.81, 10.27], [ 0.21, 0.99, -5.74] ], + [ [ -86.41, -23.06, -6.84], [ -34.94, -2.39, -4.40], [ 0.06, -5.95, 2.75], [ -0.30, 1.46, 1.27], [ -1.06, 3.10, 6.73], [ 0.15, 1.57, -1.34] ] ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_bladder_term('dome of the bladder')[0], + 'ontId': get_bladder_term('dome of the bladder')[1] }, - }) - } + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-7', + 'name': get_bladder_term('neck of urinary bladder')[0], + 'ontId': get_bladder_term('neck of urinary bladder')[1] + }] + }), + 'Mouse 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + '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, + Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [ [ 0.9, 3.7, 0.0 ], [ -0.8, -3.6, 0.0 ], [ 3.2, -0.6, 0.0 ], [ -1.3, -0.5, 0.0 ], [ 0.0, 0.0, 2.6 ], [ 0.0, 0.0, 0.9 ] ], + [ [ -0.1, 0.7, 0.0 ], [ -1.2, -2.4, 0.0 ], [ 2.0, -1.5, 0.0 ], [ -1.1, -1.3, 0.0 ], [ 0.0, 0.0, 3.1 ], [ 0.0, 0.0, 0.1 ] ], + [ [ -1.4, -1.1, 0.0 ], [ -1.6, -1.1, 0.0 ], [ 1.0, -3.0, 0.0 ], [ -1.3, -0.8, 0.0 ], [ 0.0, 0.0, 3.0 ], [ 0.0, 0.0, -0.2 ] ], + [ [ -2.9, -1.6, 0.0 ], [ -1.6, 0.2, 0.0 ], [ -0.6, -3.3, 0.0 ], [ -1.4, 0.2, 0.0 ], [ 0.0, 0.0, 2.8 ], [ 0.0, 0.0, -0.1 ] ], + [ [ -4.3, -0.8, 0.0 ], [ -1.2, 1.1, 0.0 ], [ -1.8, -2.5, 0.0 ], [ -0.8, 1.1, 0.0 ], [ 0.0, 0.0, 2.9 ], [ 0.0, 0.0, -0.1 ] ], + [ [ -5.2, 0.6, 0.0 ], [ -0.8, 1.6, 0.0 ], [ -2.2, -1.1, 0.0 ], [ 0.2, 1.1, 0.0 ], [ 0.0, 0.0, 2.5 ], [ 0.0, 0.0, -0.7 ] ], + [ [ -5.9, 2.3, 0.0 ], [ -0.5, 1.3, 0.0 ], [ -1.3, -0.4, 0.0 ], [ 0.6, 0.3, 0.0 ], [ 0.0, 0.0, 1.4 ], [ 0.0, 0.0, -0.7 ] ], + [ [ -6.2, 3.2, 0.0 ], [ -0.4, 0.9, 0.0 ], [ -0.8, -0.3, 0.0 ], [ 0.1, -0.0, 0.0 ], [ 0.0, 0.0, 0.9 ], [ 0.0, 0.0, -0.2 ] ], + [ [ -6.8, 4.1, 0.0 ], [ -0.7, 0.9, 0.0 ], [ -1.1, -0.5, 0.0 ], [ -0.7, -0.4, 0.0 ], [ 0.0, 0.0, 1.1 ], [ 0.0, 0.0, 0.6 ] ] ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_bladder_term('dome of the bladder')[0], + 'ontId': get_bladder_term('dome of the bladder')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-7', + 'name': get_bladder_term('neck of urinary bladder')[0], + 'ontId': get_bladder_term('neck of urinary bladder')[1] + }] + }), + 'Pig 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 7 + }, + 'meshEdits': exnodeStringFromNodeValues( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [ [ 73.1, 50.2, 0.0 ], [ -18.5, -35.4, 0.0 ], [ 18.5, -10.9, 0.0 ], [ 18.6, -8.2, 0.0 ], [ 0.0, 0.0, 27.8 ], [ 0.0, 0.0, 8.6 ] ], + [ [ 57.3, 20.3, 0.0 ], [ -13.1, -24.4, 0.0 ], [ 30.1, -17.0, 0.0 ], [ 4.6, -4.0, 0.0 ], [ 0.0, 0.0, 33.3 ], [ 0.0, 0.0, 2.4 ] ], + [ [ 47.0, 1.4, 0.0 ], [ -12.6, -19.8, 0.0 ], [ 30.2, -19.7, 0.0 ], [ -4.3, -4.5, 0.0 ], [ 0.0, 0.0, 33.7 ], [ 0.0, 0.0, -0.7 ] ], + [ [ 32.0, -18.9, 0.0 ], [ -19.5, -14.4, 0.0 ], [ 20.7, -26.4, 0.0 ], [ -13.7, -4.9, 0.0 ], [ 0.0, 0.0, 31.6 ], [ 0.0, 0.0, -3.7 ] ], + [ [ 10.7, -26.3, 0.0 ], [ -24.3, 1.9, 0.0 ], [ 3.1, -29.7, 0.0 ], [ -16.7, 4.8, 0.0 ], [ 0.0, 0.0, 26.5 ], [ 0.0, 0.0, -8.8 ] ], + [ [ -11.3, -14.4, 0.0 ], [ -14.4, 19.6, 0.0 ], [ -12.7, -15.9, 0.0 ], [ -4.1, 13.5, 0.0 ], [ 0.0, 0.0, 13.5 ], [ 0.0, 0.0, -7.8 ] ], + [ [ -15.8, 7.8, 0.0 ], [ -8.3, 18.3, 0.0 ], [ -6.4, -2.7, 0.0 ], [ 2.8, 4.4, 0.0 ], [ 0.0, 0.0, 10.4 ], [ 0.0, 0.0, -1.7 ] ], + [ [ -26.2, 21.4, 0.0 ], [ -11.8, 8.4, 0.0 ], [ -6.3, -4.9, 0.0 ], [ -2.6, -8.8, 0.0 ], [ 0.0, 0.0, 9.8 ], [ 0.0, 0.0, 0.5 ] ] ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_bladder_term('dome of the bladder')[0], + 'ontId': get_bladder_term('dome of the bladder')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-7', + 'name': get_bladder_term('neck of urinary bladder')[0], + 'ontId': get_bladder_term('neck of urinary bladder')[1] + }] + }), + 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + '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, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [ [ 11.3, 13.4, 0.0 ], [ 0.3, -13.4, 0.0 ], [ 9.4, -1.3, 0.0 ], [ -1.0, -5.6, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.5 ] ], + [ [ 9.3, 2.1, 0.0 ], [ -4.4, -8.7, 0.0 ], [ 7.4, -6.1, 0.0 ], [ -3.0, -3.9, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], + [ [ 4.0, -3.6, 0.0 ], [ -6.8, -3.8, 0.0 ], [ 3.7, -9.4, 0.0 ], [ -4.9, -2.4, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, 0.1 ] ], + [ [ -3.4, -5.1, 0.0 ], [ -6.4, 0.6, 0.0 ], [ -2.4, -10.9, 0.0 ], [ -5.0, 0.9, 0.0 ], [ 0.0, 0.0, 8.8 ], [ 0.0, 0.0, -0.5 ] ], + [ [ -8.1, -3.2, 0.0 ], [ -4.4, 3.8, 0.0 ], [ -6.7, -8.3, 0.0 ], [ -2.5, 3.4, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.2 ] ], + [ [ -11.4, 2.3, 0.0 ], [ -1.4, 6.4, 0.0 ], [ -6.9, -4.0, 0.0 ], [ 1.9, 4.2, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], + [ [ -10.7, 8.9, 0.0 ], [ 0.3, 5.0, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 0.9, 1.1, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -0.6 ] ], + [ [ -10.7, 12.2, 0.0 ], [ -0.3, 3.0, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -0.3, -0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 0.4 ] ], + [ [ -11.3, 14.8, 0.0 ], [ -0.9, 2.2, 0.0 ], [ -3.5, -0.3, 0.0 ], [ 0.3, 0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, -0.4 ] ] ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_bladder_term('dome of the bladder')[0], + 'ontId': get_bladder_term('dome of the bladder')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-7', + 'name': get_bladder_term('neck of urinary bladder')[0], + 'ontId': get_bladder_term('neck of urinary bladder')[1] + }] + }), + } @staticmethod def getName(): @@ -99,794 +223,413 @@ def getParameterSetNames(): return [ 'Default', 'Cat 1', + 'Human 1', + 'Mouse 1', + 'Pig 1', 'Rat 1'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - if 'Rat' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Ostium Rat 1'] + if 'Human 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Human 1'] + elif 'Mouse 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Mouse 1'] + elif 'Pig 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Pig 1'] + elif 'Rat 1' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Rat 1'] else: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Ostium Cat 1'] - + centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Cat 1'] options = { - 'Number of elements up neck': 6, - 'Number of elements up body': 8, - 'Number of elements around': 8, # should be even + 'Central path': copy.deepcopy(centralPathOption), + 'Number of elements along bladder': 12, + 'Number of elements around bladder': 8, 'Number of elements through wall': 1, - 'Number of elements around ostium': 8, # implemented for 8 - 'Number of elements radially on annulus': 1, - 'Height': 5.0, - 'Major diameter': 6.0, - 'Minor diameter': 6.0, - 'Bladder wall thickness': 0.05, - 'Urethra diameter': 1.0, - 'Ureter': copy.deepcopy(ostiumOption), - 'Ostium position around': 0.55, # should be on the dorsal part - 'Ostium position up': 0.55, - 'Use cross derivatives': False, + 'Wall thickness': 0.5, + 'Ureter position around': 0.67, + 'Ureter position down': 0.8, + 'Use linear through wall': True, 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements up': 4, + 'Refine number of elements along bladder': 4, + 'Refine number of elements around bladder': 4, 'Refine number of elements through wall': 1 } - if 'Rat' in parameterSetName: - options['Number of elements around'] = 16 # should be even - options['Height'] = 3.0 - options['Major diameter'] = 5.0 - options['Minor diameter'] = 3.0 - options['Bladder wall thickness'] = 0.02 - options['Urethra diameter'] = 0.7 - options['Ostium position around'] = 0.65 # should be on the dorsal part - options['Ostium position up'] = 0.75 + if 'Human 1' in parameterSetName: + options['Number of elements along bladder'] = 8 + options['Number of elements around bladder'] = 12 + options['Wall thickness'] = 1.0 + options['Ureter position around'] = 0.82 # should be on the dorsal part (> 0.5) + options['Ureter position down'] = 0.63 + if 'Mouse 1' in parameterSetName: + options['Number of elements along bladder'] = 10 + options['Number of elements around bladder'] = 4 + options['Wall thickness'] = 0.2 + options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) + options['Ureter position down'] = 0.865 + if 'Pig 1' in parameterSetName: + options['Number of elements along bladder'] = 6 + options['Number of elements around bladder'] = 16 + options['Wall thickness'] = 2.0 + options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) + options['Ureter position down'] = 0.865 + if 'Rat 1' in parameterSetName: + options['Number of elements along bladder'] = 12 + options['Number of elements around bladder'] = 12 + options['Wall thickness'] = 0.1 + options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) + options['Ureter position down'] = 0.83 return options @staticmethod def getOrderedOptionNames(): - return [ - 'Number of elements up neck', - 'Number of elements up body', - 'Number of elements around', + optionNames = [ + 'Central path', + 'Number of elements along bladder', + 'Number of elements around bladder', 'Number of elements through wall', - 'Number of elements radially on annulus', - 'Height', - 'Major diameter', - 'Minor diameter', - 'Bladder wall thickness', - 'Urethra diameter', - 'Ostium position around', - 'Ostium position up', - 'Ureter', - 'Use cross derivatives', + 'Wall thickness', + 'Ureter position around', + 'Ureter position down', + 'Use linear through wall', 'Refine', - 'Refine number of elements around', - 'Refine number of elements up', - 'Refine number of elements through wall' - ] + 'Refine number of elements around bladder', + 'Refine number of elements along bladder', + 'Refine number of elements through wall'] + return optionNames @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Ureter': - return [MeshType_3d_ostium1] + if optionName == 'Central path': + return [MeshType_1d_path1] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Ureter': - return list(cls.ostiumDefaultScaffoldPackages.keys()) - assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ + if optionName == 'Central path': + return list(cls.centralPathDefaultScaffoldPackages_Bladder.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 == 'Ureter': + '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.ostiumDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.centralPathDefaultScaffoldPackages_Bladder.keys())[0] + return copy.deepcopy(cls.centralPathDefaultScaffoldPackages_Bladder[parameterSetName]) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): - if not options['Ureter'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Ureter'): - options['Ureter'] = cls.getOptionScaffoldPackage('Ureter', MeshType_3d_ostium1) - if (options['Number of elements up neck'] < 4): - options['Number of elements up neck'] = 4 - if (options['Number of elements up body'] < 4): - options['Number of elements up body'] = 4 - if (options['Number of elements around'] < 8): - options['Number of elements around'] = 8 - elif (options['Number of elements around'] % 2) == 1: - options['Number of elements around'] += 1 - if (options['Number of elements through wall'] != 1): - options['Number of elements through wall'] = 1 - if(options['Number of elements radially on annulus'] > 2): - options['Number of elements radially on annulus'] = 2 - if (options['Major diameter'] < options['Minor diameter']): - options['Major diameter'] = options['Minor diameter'] + 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 elements along bladder', + 'Number of elements around bladder', + 'Number of elements through wall', + 'Refine number of elements along bladder', + 'Refine number of elements around bladder', + 'Refine number of elements through wall']: + if options[key] < 1: + options[key] = 1 + # if options['Number of elements around bladder'] % 2: + # options['Number of elements around bladder'] += 1 + if options['Number of elements around bladder'] % 2 != 0: + options['Number of elements around bladder'] += 1 + if options['Ureter position around'] < 0.5: + options['Ureter position around'] = 0.5 # ureters are on the dorsal part of the bladder + # elif options['Ureter position around'] > 0.9: + # options['Ureter position around'] = 0.9 + # if options['Ureter position down'] < 0.15: + # options['Ureter position down'] = 0.15 + # elif options['Ureter position down'] > 0.95: + # options['Ureter position down'] = 0.95 + + # if options['Number of elements around bladder'] < 12: + # options['Number of elements around bladder'] = 12 + # if options['Number of elements through wall'] != (1 or 4): + # options['Number of elements through wall'] = 4 @classmethod def generateBaseMesh(cls, region, options): - ''' - Generate the base bicubic Hermite mesh. + """ + 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 - ''' - elementsCountUpNeck = options['Number of elements up neck'] - elementsCountUpBody = options['Number of elements up body'] - elementsCountAround = options['Number of elements around'] - height = options['Height'] - majorDiameter = options['Major diameter'] - minorDiameter = options['Minor diameter'] - radius = 0.5 * options['Urethra diameter'] - bladderWallThickness = options['Bladder wall thickness'] - useCrossDerivatives = options['Use cross derivatives'] - elementsCountAroundOstium = options['Number of elements around ostium'] - elementsCountAnnulusRadially = options['Number of elements radially on annulus'] - ostiumPositionAround = options['Ostium position around'] - ostiumPositionUp = options['Ostium position up'] - - ostiumOptions = options['Ureter'] - ostiumDefaultOptions = ostiumOptions.getScaffoldSettings() + :return: None + """ + centralPath = options['Central path'] + elementsCountAlongBladder = options['Number of elements along bladder'] + elementsCountAroundBladder = options['Number of elements around bladder'] + elementsCountThroughWall = options['Number of elements through wall'] + wallThickness = options['Wall thickness'] + useCrossDerivatives = False + useCubicHermiteThroughWall = not (options['Use linear through wall']) fm = region.getFieldmodule() fm.beginChange() - coordinates = findOrCreateFieldCoordinates(fm) - cache = fm.createFieldcache() - - mesh = fm.findMeshByDimension(3) + coordinates = findOrCreateFieldCoordinates(fm) nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - nodetemplateApex = nodes.createNodetemplate() - nodetemplateApex.defineField(coordinates) - nodetemplateApex.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) - nodetemplateApex.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - nodetemplateApex.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) if useCrossDerivatives: - nodetemplate = nodes.createNodetemplate() - nodetemplate.defineField(coordinates) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) - else: - nodetemplate = nodetemplateApex + if useCubicHermiteThroughWall: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) - eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) - eft = eftfactory.createEftBasic() + cache = fm.createFieldcache() + mesh = fm.findMeshByDimension(3) - elementtemplate = mesh.createElementtemplate() - elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) - elementtemplate.defineField(coordinates, -1, eft) + nodeIdentifier = 1 + elementIdentifier = 1 - neckGroup = AnnotationGroup(region, get_bladder_term("neck of urinary bladder")) + # Extract length of each group along bladder from central path + arcLengthOfGroupsAlong = [] + bladderTermsAlong = [None, 'dome of the bladder', 'neck of urinary bladder'] + for i in range(len(bladderTermsAlong)): + 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=bladderTermsAlong[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 + + print('arcLengthOfGroupsAlong', arcLengthOfGroupsAlong) + sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, len(cx)) + sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) + sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) + + # Create annotation groups for bladder + bladderCentralPathLength = sum(arcLengthOfGroupsAlong[1:]) + allAnnotationGroups = [] bodyGroup = AnnotationGroup(region, get_bladder_term("dome of the bladder")) - urinaryBladderGroup = AnnotationGroup(region, get_bladder_term("urinary bladder")) - annotationGroups = [neckGroup, bodyGroup, urinaryBladderGroup] + neckGroup = AnnotationGroup(region, get_bladder_term("neck of urinary bladder")) + bladderGroup = AnnotationGroup(region, get_bladder_term("urinary bladder")) - neckMeshGroup = neckGroup.getMeshGroup(mesh) - bodyMeshGroup = bodyGroup.getMeshGroup(mesh) - urinaryBladderMeshGroup = urinaryBladderGroup.getMeshGroup(mesh) + annotationGroupAlong = [[bladderGroup, bodyGroup], [bladderGroup, neckGroup]] + annotationGroupsAround = [[]] + for i in range(elementsCountAroundBladder): + annotationGroupsAround.append([]) + annotationGroupsThroughWall = [] + for i in range(elementsCountThroughWall): + annotationGroupsThroughWall.append([]) - # create nodes - # create neck of the bladder - nodeIdentifier = 1 - radiansPerElementAround = 2.0*math.pi/elementsCountAround - radiansPerElementUpNeck = (math.pi/4)/elementsCountUpNeck - - # create lower part of the ellipsoidal - neckHeight = height - height * math.cos(math.pi / 4) - ellipsoidal_x = [] - ellipsoidal_d1 = [] - ellipsoidal_d2 = [] - for n2 in range(0, elementsCountUpNeck+1): - radiansUp = n2 * radiansPerElementUpNeck - cosRadiansUp = math.cos(radiansUp) - sinRadiansUp = math.sin(radiansUp) - majorRadius = 0.5 * majorDiameter * sinRadiansUp - minorRadius = 0.5 * minorDiameter * sinRadiansUp - if n2 == 0: - for n1 in range(elementsCountAround): - radiansAround = n1 * radiansPerElementAround - cosRadiansAround = math.cos(radiansAround) - sinRadiansAround = math.sin(radiansAround) - x = [ - -majorRadius * sinRadiansAround, - minorRadius * cosRadiansAround, - -height - neckHeight - ] - dx_ds1 = [ - -majorRadius * cosRadiansAround * radiansPerElementAround, - minorRadius * -sinRadiansAround * radiansPerElementAround, - 0.0 - ] - dx_ds2 = [ - -0.5 * majorDiameter * sinRadiansAround * cosRadiansUp * radiansPerElementUpNeck, - 0.5 * minorDiameter * cosRadiansAround * cosRadiansUp * radiansPerElementUpNeck, - height * sinRadiansUp * radiansPerElementUpNeck - ] - ellipsoidal_x.append(x) - ellipsoidal_d1.append(dx_ds1) - ellipsoidal_d2.append(dx_ds2) - else: - for n1 in range(elementsCountAround): - neckHeight = height - height * math.cos(math.pi/4) - radiansAround = n1 * radiansPerElementAround - cosRadiansAround = math.cos(radiansAround) - sinRadiansAround = math.sin(radiansAround) - x = [ - -majorRadius * sinRadiansAround, - minorRadius * cosRadiansAround, - -height - neckHeight + n2 * 2 * neckHeight / elementsCountUpNeck - ] - dx_ds1 = [ - -majorRadius * cosRadiansAround * radiansPerElementAround, - minorRadius * -sinRadiansAround * radiansPerElementAround, - 0.0 - ] - dx_ds2 = [ - -0.5 * majorDiameter * sinRadiansAround * cosRadiansUp * radiansPerElementUpNeck, - 0.5 * minorDiameter * cosRadiansAround * cosRadiansUp * radiansPerElementUpNeck, - height * sinRadiansUp * radiansPerElementUpNeck - ] - ellipsoidal_x.append(x) - ellipsoidal_d1.append(dx_ds1) - ellipsoidal_d2.append(dx_ds2) - - # create tube nodes - radiansPerElementAround = 2.0 * math.pi / elementsCountAround - tube_x = [] - tube_d1 = [] - tube_d2 = [] - for n2 in range(0, elementsCountUpNeck + 1): - radiansUp = n2 * radiansPerElementUpNeck - cosRadiansUp = math.cos(radiansUp) - sinRadiansUp = math.sin(radiansUp) - if n2 == 0: - for n1 in range(elementsCountAround): - radiansAround = n1 * radiansPerElementAround - cosRadiansAround = math.cos(radiansAround) - sinRadiansAround = math.sin(radiansAround) - x = [ - -radius * sinRadiansAround, - radius * cosRadiansAround, - -height - neckHeight - ] - dx_ds1 = [ - -radiansPerElementAround * radius * cosRadiansAround, - radiansPerElementAround * radius * -sinRadiansAround, - 0.0 - ] - dx_ds2 = [0, 0, height / (2 * elementsCountUpNeck)] - tube_x.append(x) - tube_d1.append(dx_ds1) - tube_d2.append(dx_ds2) + # annotation fiducial points + markerGroup = findOrCreateFieldGroup(fm, "marker") + markerName = findOrCreateFieldStoredString(fm, name="marker_name") + markerLocation = findOrCreateFieldStoredMeshLocation(fm, mesh, name="marker_location") + + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() + markerTemplateInternal = nodes.createNodetemplate() + markerTemplateInternal.defineField(markerName) + markerTemplateInternal.defineField(markerLocation) + + # Fundus diameter + fundusRadius = vector.magnitude(sd2[0]) + lengthElementAlongTrackSurface = bladderCentralPathLength / elementsCountAlongBladder + elementsAlongFundus = int(fundusRadius / lengthElementAlongTrackSurface) + + d2Apex = [] + d2 = sd2[0] + # print('sd1[0]', sd1[0]) + # print('sd2[0]', sd2[0]) + # print('vector.normalise(sd2[0]', vector.normalise(sd2[0])) + # print('sd3[0]', sd3[0]) + # print('vector.normalise(sd3[0]', vector.normalise(sd3[0])) + for n1 in range(elementsCountAroundBladder): + rotAngle = n1 * 2.0 * math.pi / elementsCountAroundBladder + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) + d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + d2Apex.append(d2Rot) + # if n1 == 1: + # print('rotAngle', rotAngle) + # print('rotAxis', rotAxis) + # print('rotFrame', rotFrame) + # print('d2Rot', d2Rot) + + xEllipses = [] + d1Ellipses = [] + print('len(sx)', len(sx)) + # print('elementsAlongFundus', elementsAlongFundus) + for n in range(1, len(sx)): + px, pd1 = createEllipsePoints(sx[n], 2 * math.pi, sd2[n], sd3[n], elementsCountAroundBladder, + startRadians=0.0) + xEllipses.append(px) + d1Ellipses.append(pd1) + # print('xEllipses', xEllipses) + print('len(xEllipses)', len(xEllipses)) + # print('len(xEllipses[0])', len(xEllipses[0])) + # print('len(xEllipses[0][0])', len(xEllipses[0][0])) + + # Find d2 + d2Raw = [] + for n1 in range(elementsCountAroundBladder): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses) - 1): + v1 = xEllipses[n2][n1] + v2 = xEllipses[n2 + 1][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v1) + d2Along.append(d2) + xAlong.append(xEllipses[-1][n1]) + d2Along.append(d2) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Raw.append(d2Smoothed) + + # Rearrange d2 + d2Ellipses = [] + for n2 in range(len(xEllipses)): + d2Around = [] + for n1 in range(elementsCountAroundBladder): + d2 = d2Raw[n1][n2] + d2Around.append(d2) + d2Ellipses.append(d2Around) + + # Merge fundus apex and body + xAll = [[sx[0]] * elementsCountAroundBladder] + xEllipses + d2All = [d2Apex] + d2Ellipses + print('len(xAll)', len(xAll)) + + + # Spread out elements + xRaw = [] + d2Raw = [] + for n1 in range(elementsCountAroundBladder): + xAlong = [] + d2Along = [] + for n2 in range(len(xAll)): + xAlong.append(xAll[n2][n1]) + d2Along.append(d2All[n2][n1]) + xSampledAlong, d2SampledAlong = interp.sampleCubicHermiteCurves(xAlong, d2Along, + elementsCountAlongBladder, + arcLengthDerivatives=True)[0:2] + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlong, d2SampledAlong) + xRaw.append(xSampledAlong) + d2Raw.append(d2Smoothed) + + # Rearrange x and d2 + xSampledAll = [] + d1SampledAll = [] + d2SampledAll = [] + for n2 in range(elementsCountAlongBladder + 1): + xAround = [] + d1Around = [] + d2Around = [] + for n1 in range(elementsCountAroundBladder): + x = xRaw[n1][n2] + d2 = d2Raw[n1][n2] + xAround.append(x) + d2Around.append(d2) + + # Calculate d1 + if n2 > 0: + v1 = xRaw[n1][n2] + v2 = xRaw[n1 + 1 if n1 < elementsCountAroundBladder - 2 else 0][n2] + d1 = findDerivativeBetweenPoints(v1, v2) + d1Around.append(d1) + else: + d1Around.append(d2Raw[int(elementsCountAroundBladder * 0.75)][0]) + + if n2 > 0: + d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) else: - for n1 in range(elementsCountAround): - neckHeight = height - height* math.cos(math.pi/4) - radiansAround = n1 * radiansPerElementAround - cosRadiansAround = math.cos(radiansAround) - sinRadiansAround = math.sin(radiansAround) - x = [ - -radius * sinRadiansAround, - radius * cosRadiansAround, - -height - neckHeight + n2 * 2 * neckHeight / elementsCountUpNeck - ] - dx_ds1 = [ - -radiansPerElementAround * radius * cosRadiansAround, - radiansPerElementAround * radius * -sinRadiansAround, - 0.0 - ] - dx_ds2 = [0, 0, height / elementsCountUpNeck] - tube_x.append(x) - tube_d1.append(dx_ds1) - tube_d2.append(dx_ds2) - - # interpolation between the lower part of the ellipsoidal and the tube - m1 = 0 - z_bottom = ellipsoidal_x[-1][2] - z_top = ellipsoidal_x[0][2] - delta_z = z_top - z_bottom - interpolatedNodes = [] - interpolatedNodes_d1 = [] - interpolatedNodes_d2 = [] - for n2 in range(elementsCountUpNeck+1): - xi = 1.0 - (ellipsoidal_x[m1][2] - z_bottom) / delta_z - for n1 in range(elementsCountAround): - phi_inner, _, phi_outer, _ = getCubicHermiteBasis(xi) - x = [(phi_inner*tube_x[m1][c] + phi_outer*ellipsoidal_x[m1][c]) for c in range(3)] - d1 = [(phi_inner*tube_d1[m1][c] + phi_outer*ellipsoidal_d1[m1][c]) for c in range(3)] - d2 = [(phi_inner*tube_d2[m1][c] + phi_outer*ellipsoidal_d2[m1][c]) for c in range(3)] - interpolatedNodes.append(x) - interpolatedNodes_d1.append(d1) - interpolatedNodes_d2.append(d2) - m1 += 1 - - # smoothing the derivatives - sd2Raw = [] - for n1 in range(elementsCountAround): - lineSmoothingNodes = [] - lineSmoothingNodes_d2 = [] - for n2 in range(elementsCountUpNeck+1): - lineSmoothingNodes.append(interpolatedNodes[n1 + n2 * elementsCountAround]) - lineSmoothingNodes_d2.append(interpolatedNodes_d2[n1 + n2 * elementsCountAround]) - sd2 = smoothCubicHermiteDerivativesLine(lineSmoothingNodes, lineSmoothingNodes_d2, - fixAllDirections=False, - fixStartDerivative=True, fixEndDerivative=True, - fixStartDirection=False, fixEndDirection=False) - sd2Raw.append(sd2) - - # re-arrange the derivatives order - d2RearrangedList = [] - for n2 in range(elementsCountUpNeck+1): - for n1 in range(elementsCountAround): - d2 = sd2Raw[n1][n2] - d2RearrangedList.append(d2) - - # create tracksurface at the outer layer of the neck - nodesOnTrackSurface = [] - nodesOnTrackSurface_d1 = [] - nodesOnTrackSurface_d2 = [] - for n2 in range(elementsCountUpNeck+1): - for n1 in range(elementsCountAround): - if (n1 <= elementsCountAround / 2): - nodesOnTrackSurface.append(interpolatedNodes[n2 * elementsCountAround + n1]) - nodesOnTrackSurface_d1.append(interpolatedNodes_d1[n2 * elementsCountAround + n1]) - nodesOnTrackSurface_d2.append(d2RearrangedList[n2 * elementsCountAround + n1]) - - # nodes and derivatives of the neck of the bladder - listOuterNeck_x = [] - listOuterNeck_d1 = [] - listOuterNeck_d2 = [] - elementsCount1 = elementsCountAround // 2 - elementsCount2 = elementsCountUpNeck - tracksurfaceOstium1 = TrackSurface(elementsCount1, elementsCount2, nodesOnTrackSurface, nodesOnTrackSurface_d1, - nodesOnTrackSurface_d2) - ostium1Position = tracksurfaceOstium1.createPositionProportion(ostiumPositionAround, ostiumPositionUp) - ostium1Position.xi1 = 1.0 - ostium1Position.xi2 = 1.0 - ostiumElementPositionAround = ostium1Position.e1 - ostiumElementPositionUp = ostium1Position.e2 - for n2 in range(len(interpolatedNodes)): - listOuterNeck_x.append(interpolatedNodes[n2]) - listOuterNeck_d1.append(interpolatedNodes_d1[n2]) - listOuterNeck_d2.append(d2RearrangedList[n2]) - - # create body of the bladder - radiansPerElementAround = 2.0 * math.pi / elementsCountAround - radiansPerElementUpBody = (3 * math.pi / 4) / elementsCountUpBody - # create regular rows - listOuterBody_x = [] - listOuterBody_d1 = [] - listOuterBody_d2 = [] - for n2 in range(1, elementsCountUpBody): - radiansUp = (math.pi / 4) + n2 * radiansPerElementUpBody - cosRadiansUp = math.cos(radiansUp) - sinRadiansUp = math.sin(radiansUp) - majorRadius = 0.5 * majorDiameter * sinRadiansUp - minorRadius = 0.5 * minorDiameter * sinRadiansUp - for n1 in range(elementsCountAround): - radiansAround = n1 * radiansPerElementAround - cosRadiansAround = math.cos(radiansAround) - sinRadiansAround = math.sin(radiansAround) - x = [ - -majorRadius * sinRadiansAround, - minorRadius * cosRadiansAround, - -height * cosRadiansUp - ] - dx_ds1 = [ - -majorRadius * cosRadiansAround * radiansPerElementAround, - minorRadius * -sinRadiansAround * radiansPerElementAround, - 0.0 - ] - dx_ds2 = [ - -0.5 * majorDiameter * sinRadiansAround * cosRadiansUp * radiansPerElementUpBody, - 0.5 * minorDiameter * cosRadiansAround * cosRadiansUp * radiansPerElementUpBody, - height*sinRadiansUp * radiansPerElementUpBody - ] - listOuterBody_x.append(x) - listOuterBody_d1.append(dx_ds1) - listOuterBody_d2.append(dx_ds2) - - # create outer apex node - outerApexNode_x = [] - outerApexNode_d1 = [] - outerApexNode_d2 = [] - x = [0.0, 0.0, height] - dx_ds1 = [height*radiansPerElementUpBody/2, 0.0, 0.0] - dx_ds2 = [0.0, height*radiansPerElementUpBody/2, 0.0] - outerApexNode_x.append(x) - outerApexNode_d1.append(dx_ds1) - outerApexNode_d2.append(dx_ds2) - - # set nodes of outer layer of the bladder - listTotalOuter_x = listOuterNeck_x + listOuterBody_x + outerApexNode_x - listTotalOuter_d1 = listOuterNeck_d1 + listOuterBody_d1 + outerApexNode_d1 - listTotalOuter_d2 = listOuterNeck_d2 + listOuterBody_d2 + outerApexNode_d2 - - outerLayer_x = [] - outerLayer_d1 = [] - outerLayer_d2 = [] - for n2 in range(len(listTotalOuter_x)): - if (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + ostiumElementPositionAround + 1) and\ - (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 1): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, listTotalOuter_x[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, listTotalOuter_d1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, listTotalOuter_d2[n2]) - nodeIdentifier += 1 - outerLayer_x.append(listTotalOuter_x[n2]) - outerLayer_d1.append(listTotalOuter_d1[n2]) - outerLayer_d2.append(listTotalOuter_d2[n2]) - - # create and set nodes of inner layer of the bladder - listTotalInner_x = [] - listTotalInner_d1 = [] - listTotalInner_d2 = [] - for n2 in range(elementsCountUpNeck + elementsCountUpBody): - loop_x = [listTotalOuter_x[n2 * elementsCountAround + n1] for n1 in range(elementsCountAround)] - loop_d1 = [listTotalOuter_d1[n2 * elementsCountAround + n1] for n1 in range(elementsCountAround)] - loop_d2 = [listTotalOuter_d2[n2 * elementsCountAround + n1] for n1 in range(elementsCountAround)] - for n1 in range(elementsCountAround): - x, d1, _, _ = interp.projectHermiteCurvesThroughWall(loop_x, loop_d1, loop_d2, n1, - -bladderWallThickness, loop=True) - listTotalInner_x.append(x) - listTotalInner_d1.append(d1) - - listInner_d2 = [] - for n2 in range(elementsCountAround): - nx = [listTotalOuter_x[n1 * elementsCountAround + n2] for n1 in range(elementsCountUpNeck + elementsCountUpBody)] - nd1 = [listTotalOuter_d1[n1 * elementsCountAround + n2] for n1 in range(elementsCountUpNeck + elementsCountUpBody)] - nd2 = [listTotalOuter_d2[n1 * elementsCountAround + n2] for n1 in range(elementsCountUpNeck + elementsCountUpBody)] - for n1 in range(elementsCountUpNeck + elementsCountUpBody): - _, d2, _, _ = interp.projectHermiteCurvesThroughWall(nx, nd2, nd1, n1, - bladderWallThickness, loop=False) - listInner_d2.append(d2) - - # re-arrange the derivatives order - for n2 in range(elementsCountUpNeck + elementsCountUpBody): - for n1 in range(elementsCountAround): - rearranged_d2 = listInner_d2[n1 * (elementsCountUpNeck + elementsCountUpBody) + n2] - listTotalInner_d2.append(rearranged_d2) - - innerLayer_x = [] - innerLayer_d1 = [] - innerLayer_d2 = [] - for n2 in range(len(listTotalInner_x)): - if (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + ostiumElementPositionAround + 1) and \ - (n2 != (ostiumElementPositionUp + 1) * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 1): + d1Smoothed = d1Around + + xSampledAll.append(xAround) + d1SampledAll.append(d1Smoothed) + d2SampledAll.append(d2Around) + print('len(xSampledAll)', len(xSampledAll)) + print('', xSampledAll[0]) + + for n2 in range(elementsCountAlongBladder + 1): + # if n2 == 0: + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][0]) + # nodeIdentifier += 1 + # else: + for n1 in range(elementsCountAroundBladder): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, listTotalInner_x[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, listTotalInner_d1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, listTotalInner_d2[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n2]) + # if useCrossDerivatives: + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nodeIdentifier += 1 - innerLayer_x.append(listTotalInner_x[n2]) - innerLayer_d1.append(listTotalInner_d1[n2]) - innerLayer_d2.append(listTotalInner_d2[n2]) - - # create inner apex node - x = [0.0, 0.0, height - bladderWallThickness] - dx_ds1 = [height*radiansPerElementUpBody/2, 0.0, 0.0] - dx_ds2 = [0.0, height*radiansPerElementUpBody/2, 0.0] - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dx_ds1) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dx_ds2) - listTotalInner_x.append(x) - listTotalInner_d1.append(dx_ds1) - listTotalInner_d2.append(dx_ds2) - innerLayer_x.append(x) - innerLayer_d1.append(dx_ds1) - innerLayer_d2.append(dx_ds2) - nodeIdentifier += 1 - - # create ureters on the surface - elementIdentifier = 1 - # ureter 1 - centerUreter1_x, centerUreter1_d1, centerUreter1_d2 = tracksurfaceOstium1.evaluateCoordinates(ostium1Position, derivatives=True) - td1, td2, td3 = calculate_surface_axes(centerUreter1_d1, centerUreter1_d2, [1.0, 0.0, 0.0]) - m1 = ostiumElementPositionUp * elementsCountAround + ostiumElementPositionAround - ureter1StartCornerx = listOuterNeck_x[m1] - v1 = [(ureter1StartCornerx[c] - centerUreter1_x[c]) for c in range(3)] - ostium1Direction = vector.crossproduct3(td3, v1) - nodeIdentifier, elementIdentifier, (o1_x, o1_d1, o1_d2, _, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, ostiumDefaultOptions, tracksurfaceOstium1, ostium1Position, ostium1Direction, - startNodeIdentifier=nodeIdentifier, startElementIdentifier=elementIdentifier) - - # ureter 2 - tracksurfaceOstium2 = tracksurfaceOstium1.createMirrorX() - ostium2Position = TrackSurfacePosition(elementsCountAround - ostiumElementPositionAround, ostiumElementPositionUp - 1, 0.0, 1.0) - centerUreter2_x, centerUreter2_d1, centerUreter2_d2 = tracksurfaceOstium2.evaluateCoordinates(ostium2Position, derivatives =True) - ad1, ad2, ad3 = calculate_surface_axes(centerUreter2_d1, centerUreter2_d2, [1.0, 0.0, 0.0]) - if elementsCountAroundOstium == 4: - m2 = ostiumElementPositionUp * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 1 - else: - m2 = ostiumElementPositionUp * elementsCountAround + elementsCountAround - ostiumElementPositionAround - 2 - ureter2StartCornerx = listOuterNeck_x[m2] - v2 = [(ureter2StartCornerx[c] - centerUreter2_x[c]) for c in range(3)] - ostium2Direction = vector.crossproduct3(ad3, v2) - nodeIdentifier, elementIdentifier, (o2_x, o2_d1, o2_d2, _, o2_NodeId, o2_Positions) = \ - generateOstiumMesh(region, ostiumDefaultOptions, tracksurfaceOstium2, ostium2Position, ostium2Direction, - startNodeIdentifier=nodeIdentifier, startElementIdentifier=elementIdentifier) - - # create annulus mesh around ostium - endPoints1_x = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endPoints1_d1 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endPoints1_d2 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endNode1_Id = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endDerivativesMap = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endPoints2_x = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endPoints2_d1 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endPoints2_d2 = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - endNode2_Id = [[None] * elementsCountAroundOstium, [None] * elementsCountAroundOstium] - - nodeCountsEachWallLayer = (elementsCountUpNeck + elementsCountUpBody) * elementsCountAround - 1 - for n3 in range(2): - n1 = 0 - endNode1_Id[n3][n1] = ((1 - n3) * nodeCountsEachWallLayer) + (ostiumElementPositionUp * elementsCountAround) + ostiumElementPositionAround + 1 - endNode1_Id[n3][n1 + 1] = endNode1_Id[n3][n1] + elementsCountAround - endNode1_Id[n3][n1 + 2] = endNode1_Id[n3][n1 + 1] + elementsCountAround - 2 - endNode1_Id[n3][n1 + 3] = endNode1_Id[n3][n1 + 2] + 1 - endNode1_Id[n3][n1 + 4] = endNode1_Id[n3][n1 + 3] + 1 - endNode1_Id[n3][n1 + 5] = endNode1_Id[n3][n1 + 1] + 1 - endNode1_Id[n3][n1 + 6] = endNode1_Id[n3][n1] + 2 - endNode1_Id[n3][n1 + 7] = endNode1_Id[n3][n1] + 1 - if ostiumElementPositionAround == 0: - endNode2_Id[n3][n1] = ((1 - n3) * nodeCountsEachWallLayer) + (ostiumElementPositionUp * elementsCountAround)\ - + elementsCountAround - ostiumElementPositionAround - 1 - endNode2_Id[n3][n1 + 1] = endNode2_Id[n3][n1] + elementsCountAround - 1 - endNode2_Id[n3][n1 + 2] = endNode2_Id[n3][n1 + 1] + elementsCountAround - 1 - endNode2_Id[n3][n1 + 3] = endNode2_Id[n3][n1 + 2] + 1 - endNode2_Id[n3][n1 + 4] = endNode2_Id[n3][n1 + 3] - elementsCountAround + 1 - endNode2_Id[n3][n1 + 5] = endNode2_Id[n3][n1 + 4] - elementsCountAround + 2 - endNode2_Id[n3][n1 + 6] = endNode2_Id[n3][n1 + 5] - elementsCountAround - endNode2_Id[n3][n1 + 7] = endNode2_Id[n3][n1] + 1 - else: - endNode2_Id[n3][n1] = ((1 - n3) * nodeCountsEachWallLayer) + (ostiumElementPositionUp * elementsCountAround)\ - + elementsCountAround - ostiumElementPositionAround - 1 - endNode2_Id[n3][n1 + 1] = endNode2_Id[n3][n1] + elementsCountAround - 1 - endNode2_Id[n3][n1 + 2] = endNode2_Id[n3][n1 + 1] + elementsCountAround - 1 - endNode2_Id[n3][n1 + 3] = endNode2_Id[n3][n1 + 2] + 1 - endNode2_Id[n3][n1 + 4] = endNode2_Id[n3][n1 + 3] + 1 - endNode2_Id[n3][n1 + 5] = endNode2_Id[n3][n1 + 1] + 1 - endNode2_Id[n3][n1 + 6] = endNode2_Id[n3][n1] + 2 - endNode2_Id[n3][n1 + 7] = endNode2_Id[n3][n1] + 1 - - for n3 in range(2): - for n1 in range(elementsCountAroundOstium): - nc1 = endNode1_Id[n3][n1] - (1 - n3) * nodeCountsEachWallLayer - 1 - endPoints1_x[n3][n1] = innerLayer_x[nc1] - endPoints1_d1[n3][n1] = innerLayer_d1[nc1] - endPoints1_d2[n3][n1] = [innerLayer_d2[nc1][c] for c in range(3)] - nc2 = endNode2_Id[n3][n1] - (1 - n3) * nodeCountsEachWallLayer - 1 - endPoints2_x[n3][n1] = innerLayer_x[nc2] - endPoints2_d1[n3][n1] = innerLayer_d1[nc2] - endPoints2_d2[n3][n1] = innerLayer_d2[nc2] - - for n1 in range(elementsCountAroundOstium): - if n1 == 0: - endDerivativesMap[0][n1] = ((-1, 0, 0), (-1, -1, 0), None, (0, 1, 0)) - endDerivativesMap[1][n1] = ((-1, 0, 0), (-1, -1, 0), None, (0, 1, 0)) - elif n1 == 1: - endDerivativesMap[0][n1] = ((0, 1, 0), (-1, 0, 0), None) - endDerivativesMap[1][n1] = ((0, 1, 0), (-1, 0, 0), None) - elif n1 == 2: - endDerivativesMap[0][n1] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) - endDerivativesMap[1][n1] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) - elif n1 == 3: - endDerivativesMap[0][n1] = ((1, 0, 0), (0, 1, 0), None) - endDerivativesMap[1][n1] = ((1, 0, 0), (0, 1, 0), None) - elif n1 == 4: - endDerivativesMap[0][n1] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - endDerivativesMap[1][n1] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - elif n1 == 5: - endDerivativesMap[0][n1] = ((0, -1, 0), (1, 0, 0), None) - endDerivativesMap[1][n1] = ((0, -1, 0), (1, 0, 0), None) - elif n1 == 6: - endDerivativesMap[0][n1] = ((0, -1, 0), (1, -1, 0), None, (-1, 0, 0)) - endDerivativesMap[1][n1] = ((0, -1, 0), (1, -1, 0), None, (-1, 0, 0)) - else: - endDerivativesMap[0][n1] = ((-1, 0, 0), (0, -1, 0), None) - endDerivativesMap[1][n1] = ((-1, 0, 0), (0, -1, 0), None) - - nodeIdentifier, elementIdentifier = createAnnulusMesh3d( - nodes, mesh, nodeIdentifier, elementIdentifier, - o1_x, o1_d1, o1_d2, None, o1_NodeId, None, - endPoints1_x, endPoints1_d1, endPoints1_d2, None, endNode1_Id, endDerivativesMap, - elementsCountRadial=elementsCountAnnulusRadially, meshGroups=[neckMeshGroup, urinaryBladderMeshGroup]) - - nodeIdentifier, elementIdentifier = createAnnulusMesh3d( - nodes, mesh, nodeIdentifier, elementIdentifier, - o2_x, o2_d1, o2_d2, None, o2_NodeId, None, - endPoints2_x, endPoints2_d1, endPoints2_d2, None, endNode2_Id, endDerivativesMap, - elementsCountRadial=elementsCountAnnulusRadially, meshGroups=[neckMeshGroup, urinaryBladderMeshGroup]) - - # create elements - for e3 in range(1): - newl = (e3 + 1) * ((elementsCountUpNeck + elementsCountUpBody) * elementsCountAround - 1) - # create bladder neck elements - for e2 in range(elementsCountUpNeck): - for e1 in range(elementsCountAround): - if e2 == ostiumElementPositionUp: - if (e1 == ostiumElementPositionAround or e1 == ostiumElementPositionAround + 1): - pass - elif (e1 == elementsCountAround - ostiumElementPositionAround - 2 or e1 == elementsCountAround - 1 - ostiumElementPositionAround): - pass - else: - bni1 = e2 * elementsCountAround + e1 + 1 - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 - if e1 < ostiumElementPositionAround: - bni3 = bni1 + elementsCountAround - bni4 = bni2 + elementsCountAround - elif (ostiumElementPositionAround + 1 < e1 < elementsCountAround - ostiumElementPositionAround - 2): - bni3 = bni1 + elementsCountAround - 1 - bni4 = bni2 + elementsCountAround - 1 - elif e1 > elementsCountAround - ostiumElementPositionAround - 1: - bni3 = bni1 + elementsCountAround - 2 - if e1 == elementsCountAround - 1: - bni4 = bni2 + elementsCountAround - else: - bni4 = bni2 + elementsCountAround - 2 - element = mesh.createElement(elementIdentifier, elementtemplate) - nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, - bni1, bni2, bni3, bni4] - result = element.setNodesByIdentifier(eft, nodeIdentifiers) - neckMeshGroup.addElement(element) - urinaryBladderMeshGroup.addElement(element) - elementIdentifier += 1 - elif e2 == ostiumElementPositionUp + 1: - if (e1 == ostiumElementPositionAround or e1 == ostiumElementPositionAround + 1): - pass - elif (e1 == elementsCountAround - ostiumElementPositionAround - 2 or e1 == elementsCountAround - 1 - ostiumElementPositionAround): - pass - else: - if e1 < ostiumElementPositionAround: - bni1 = e2 * elementsCountAround + e1 + 1 - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 - bni3 = bni1 + elementsCountAround - 2 - bni4 = bni2 + elementsCountAround - 2 - elif (ostiumElementPositionAround + 1 < e1 < elementsCountAround - ostiumElementPositionAround - 2): - bni1 = e2 * elementsCountAround + e1 - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround - bni3 = bni1 + elementsCountAround - 1 - bni4 = bni2 + elementsCountAround - 1 - elif e1 > elementsCountAround - ostiumElementPositionAround - 1: - bni1 = e2 * elementsCountAround + e1 - 1 - bni3 = bni1 + elementsCountAround - if e1 == elementsCountAround - 1: - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 - bni4 = bni2 + elementsCountAround - 2 - else: - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround - 1 - bni4 = bni2 + elementsCountAround - element = mesh.createElement(elementIdentifier, elementtemplate) - nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, - bni1, bni2, bni3, bni4] - result = element.setNodesByIdentifier(eft, nodeIdentifiers) - neckMeshGroup.addElement(element) - urinaryBladderMeshGroup.addElement(element) - elementIdentifier += 1 - elif e2 > ostiumElementPositionUp + 1: - element = mesh.createElement(elementIdentifier, elementtemplate) - bni1 = e2 * elementsCountAround + e1 - 1 - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround - 1 - bni3 = bni1 + elementsCountAround - bni4 = bni2 + elementsCountAround - nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, - bni1, bni2, bni3, bni4] - result = element.setNodesByIdentifier(eft, nodeIdentifiers) - neckMeshGroup.addElement(element) - urinaryBladderMeshGroup.addElement(element) - elementIdentifier += 1 - else: - element = mesh.createElement(elementIdentifier, elementtemplate) - bni1 = e2 * elementsCountAround + e1 + 1 - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround + 1 - bni3 = bni1 + elementsCountAround - bni4 = bni2 + elementsCountAround - nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, - bni1, bni2, bni3, bni4] - result = element.setNodesByIdentifier(eft, nodeIdentifiers) - neckMeshGroup.addElement(element) - urinaryBladderMeshGroup.addElement(element) - elementIdentifier += 1 - - # create bladder body elements - for e2 in range(elementsCountUpNeck, (elementsCountUpNeck + elementsCountUpBody - 1)): - for e1 in range(elementsCountAround): - element = mesh.createElement(elementIdentifier, elementtemplate) - bni1 = e2 * elementsCountAround + e1 - 1 - bni2 = e2 * elementsCountAround + (e1 + 1) % elementsCountAround - 1 - bni3 = bni1 + elementsCountAround - bni4 = bni2 + elementsCountAround - nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni4 + newl, - bni1, bni2, bni3, bni4] - result = element.setNodesByIdentifier(eft, nodeIdentifiers) - bodyMeshGroup.addElement(element) - urinaryBladderMeshGroup.addElement(element) - elementIdentifier += 1 - # create apex elements - bni3 = (elementsCountUpNeck + elementsCountUpBody) * elementsCountAround - 1 - elementtemplateApex = mesh.createElementtemplate() - elementtemplateApex.setElementShapeType(Element.SHAPE_TYPE_CUBE) - for e1 in range(elementsCountAround): - va = e1 - vb = (e1 + 1) % elementsCountAround - eftApex = eftfactory.createEftShellPoleTop(va, vb) - elementtemplateApex.defineField(coordinates, -1, eftApex) - # redefine field in template for changes to eftApex: - element = mesh.createElement(elementIdentifier, elementtemplateApex) - bni1 = bni3 - elementsCountAround + e1 - bni2 = bni3 - elementsCountAround + (e1 + 1) % elementsCountAround - nodeIdentifiers = [bni1 + newl, bni2 + newl, bni3 + newl, bni1, bni2, bni3] - result = element.setNodesByIdentifier(eftApex, nodeIdentifiers) - bodyMeshGroup.addElement(element) - urinaryBladderMeshGroup.addElement(element) - elementIdentifier += 1 fm.endChange() - return annotationGroups - @classmethod - def refineMesh(cls, meshrefinement, options): - assert isinstance(meshrefinement, MeshRefinement) - refineElementsCountAround = options['Refine number of elements around'] - refineElementsCountUp = options['Refine number of elements up'] - refineElementsCountThroughWall = options['Refine number of elements through wall'] - element = meshrefinement._sourceElementiterator.next() - while element.isValid(): - numberInXi1 = refineElementsCountAround - numberInXi2 = refineElementsCountUp - numberInXi3 = refineElementsCountThroughWall - meshrefinement.refineElementCubeStandard3d(element, numberInXi1, numberInXi2, numberInXi3) - element = meshrefinement._sourceElementiterator.next() + return allAnnotationGroups @classmethod - def defineFaceAnnotations(cls, region, options, annotationGroups): + def refineMesh(cls, meshrefinement, options): """ - 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. + 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(). - :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() - neckGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("neck of urinary bladder")) - bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("dome of the bladder")) - urinaryBladderGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("urinary bladder")) - mesh2d = fm.findMeshByDimension(2) - is_exterior = fm.createFieldIsExterior() - is_exterior_face_xi3_1 = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) - is_exterior_face_xi3_0 = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) - - is_body = bodyGroup.getFieldElementGroup(mesh2d) - is_body_serosa = fm.createFieldAnd(is_body, is_exterior_face_xi3_1) - is_body_lumen = fm.createFieldAnd(is_body, is_exterior_face_xi3_0) - - is_neck = neckGroup.getFieldElementGroup(mesh2d) - is_neck_serosa = fm.createFieldAnd(is_neck, is_exterior_face_xi3_1) - is_neck_lumen = fm.createFieldAnd(is_neck, is_exterior_face_xi3_0) - - serosaOfBody = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("serosa of body of urinary bladder")) - serosaOfBody.getMeshGroup(mesh2d).addElementsConditional(is_body_serosa) - lumenOfBody = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("lumen of body of urinary bladder")) - lumenOfBody.getMeshGroup(mesh2d).addElementsConditional(is_body_lumen) - - SerosaOfNeck =findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("serosa of neck of urinary bladder")) - SerosaOfNeck.getMeshGroup(mesh2d).addElementsConditional(is_neck_serosa) - lumenOfNeck = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("lumen of neck of urinary bladder")) - lumenOfNeck.getMeshGroup(mesh2d).addElementsConditional(is_neck_lumen) + refineElementsCountAround = options['Refine number of elements surface'] + refineElementsCountAlong = options['Refine number of elements surface'] + refineElementsCountThroughWall = options['Refine number of elements through wall'] + meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, + refineElementsCountThroughWall) + return + +def findDerivativeBetweenPoints(v1, v2): + """ + Find vector difference between two points and rescale vector difference using cubic hermite arclength + between the points to derive the derivative between the points. + :param v1: start vector + :param v2: end vector + :return: derivative of between v1 and v2 + """ + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + d = [c * arcLengthAround for c in vector.normalise(d)] + + return d From 60caa65f4f7546b1b2dd63b09b4d22b2c974434d Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Tue, 12 Jul 2022 14:40:54 +1200 Subject: [PATCH 02/26] Made the bladder nodes and elements. --- .../meshtypes/meshtype_3d_bladder1.py | 1050 +++++++++++++---- 1 file changed, 801 insertions(+), 249 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 9bf03091..d9c6477f 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -3,18 +3,15 @@ numbers of elements around , along and through wall. """ -from __future__ import division - import copy import math -from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates, findOrCreateFieldGroup, \ - findOrCreateFieldStoredString, findOrCreateFieldStoredMeshLocation, findOrCreateFieldNodeGroup -from opencmiss.utils.zinc.finiteelement import get_element_node_identifiers +from opencmiss.utils.zinc.field import findOrCreateFieldGroup, findOrCreateFieldStoredString, \ + findOrCreateFieldStoredMeshLocation, findOrCreateFieldNodeGroup from opencmiss.zinc.element import Element from opencmiss.zinc.field import Field from opencmiss.zinc.node import Node -from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups, \ +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, \ getAnnotationGroupForTerm, findOrCreateAnnotationGroupForTerm from scaffoldmaker.annotation.bladder_terms import get_bladder_term from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1, extractPathParametersFromRegion @@ -22,16 +19,17 @@ from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp from scaffoldmaker.utils import matrix +from scaffoldmaker.utils import tubemesh from scaffoldmaker.utils import vector from scaffoldmaker.utils.geometry import createEllipsePoints -from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues, mesh_destroy_elements_and_nodes_by_identifiers - +from scaffoldmaker.utils.tracksurface import TrackSurface +from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues class MeshType_3d_bladder1(Scaffold_base): """ Generates a 3-D bladder mesh with variable numbers of elements around, along the central line, and through wall. The bladder is created using a central path as the longitudinal axis of the bladder. Magnitude of D2 and D3 are - the radii of the bladder in the respective direction. + the radii of the bladder in the respective directions. """ centralPathDefaultScaffoldPackages_Bladder = { 'Cat 1': ScaffoldPackage(MeshType_1d_path1, { @@ -44,15 +42,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[70.80, 72.30, 0.00], [-6.62, -16.41, -1.20], [38.60, -15.67, 1.49], [-8.82, -10.04, -1.62], [-2.26, -1.91, 38.59], [4.19, 4.77, 4.06]], - [[57.51, 51.14, -0.10], [-19.84, -25.60, 1.02], [30.18, -23.37, 0.26], [-8.02, -5.36, -0.83], [0.57, 1.21, 41.38], [1.49, 1.45, 1.53]], - [[30.29, 22.36, 2.55], [-25.83, -23.54, -0.03], [22.79, -25.01, 0.06], [-8.14, 1.29, 0.15], [-0.08, 0.03, 40.90], [-1.33, -0.83, -5.13]], - [[6.64, 3.83, 0.48], [-22.06, -14.48, -1.56], [14.08, -21.50, 0.48], [-6.95, 3.05, 0.10], [-1.93, -0.54, 32.24], [-0.40, -0.03, -9.52]], - [[-13.27, -6.98, -0.63], [-21.39, -9.64, -1.27], [8.45, -18.80, 0.34], [-4.94, 3.33, 0.35], [-1.24, -0.16, 22.07], [0.24, 0.77, -7.46]], - [[-36.03, -15.27, -2.05], [-21.61, -6.31, -1.44], [4.24, -14.80, 1.22], [-3.51, 4.96, 0.69], [-1.47, 1.02, 17.51], [0.02, 0.97, -6.00]], - [[-56.31, -19.78, -3.49], [-25.21, -4.17, -2.30], [1.33, -9.02, 1.75], [-2.24, 4.68, 0.72], [-1.24, 1.81, 10.27], [0.21, 0.99, -5.74]], - [[-86.41, -23.06, -6.84], [-34.94, -2.39, -4.40], [0.06, -5.95, 2.75], [-0.30, 1.46, 1.27], [-1.06, 3.10, 6.73], [0.15, 1.57, -1.34]]]), - + [[70.80, 72.30, 0.00], [-20.79, -22.78, 0.52], [18.43, -16.77, 1.98], [1.58, -5.87, -2.59], [-1.33, 1.87, 28.21], [1.21, -2.78, 20.33]], + [[49.64, 51.56, 0.11], [-21.49, -18.65, -0.31], [19.75, -22.76, 0.28], [1.06, -6.10, -0.81], [-0.59, -0.01, 41.40], [0.27, -0.96, 6.06]], + [[28.03, 34.99, -0.59], [-23.01, -16.34, -0.47], [20.57, -28.97, 0.28], [-2.00, -1.83, 0.44], [-0.75, -0.13, 40.89], [-0.26, 0.40, -4.19]], + [[3.63, 18.98, -0.82], [-26.42, -15.76, -0.50], [15.55, -26.11, 1.19], [-6.09, 5.90, -0.06], [-1.12, 0.83, 32.77], [0.03, -0.01, -9.44]], + [[-24.82, 3.62, -1.62], [-23.44, -11.53, -0.83], [8.28, -16.84, 0.05], [-4.41, 6.01, -0.02], [-0.65, -0.25, 21.87], [0.08, 0.02, -8.87]], + [[-43.01, -4.49, -2.39], [-19.63, -8.66, -0.84], [5.63, -12.84, 0.73], [-2.80, 5.02, 0.06], [-0.81, 0.45, 14.26], [0.01, 0.10, -6.72]], + [[-64.08, -13.68, -3.31], [-22.03, -8.81, -1.71], [2.65, -6.64, 0.07], [-2.12, 4.29, -0.34], [-0.60, -0.16, 8.58], [-0.01, -0.33, -3.96]], + [[-87.03, -22.04, -5.85], [-23.83, -7.91, -3.38], [1.45, -4.39, 0.06], [-0.29, 0.22, 0.33], [-0.85, -0.19, 6.45], [-0.48, 0.26, -0.30]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -78,16 +75,15 @@ class MeshType_3d_bladder1(Scaffold_base): 'Number of elements': 7 }, 'meshEdits': exnodeStringFromNodeValues( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [ [ 70.80, 72.30, 0.00], [ -6.62, -16.41, -1.20], [ 38.60, -15.67, 1.49], [ -8.82, -10.04, -1.62], [ -2.26, -1.91, 38.59], [ 4.19, 4.77, 4.06] ], - [ [ 57.51, 51.14, -0.10], [ -19.84, -25.60, 1.02], [ 30.18, -23.37, 0.26], [ -8.02, -5.36, -0.83], [ 0.57, 1.21, 41.38], [ 1.49, 1.45, 1.53] ], - [ [ 30.29, 22.36, 2.55], [ -25.83, -23.54, -0.03], [ 22.79, -25.01, 0.06], [ -8.14, 1.29, 0.15], [ -0.08, 0.03, 40.90], [ -1.33, -0.83, -5.13] ], - [ [ 6.64, 3.83, 0.48], [ -22.06, -14.48, -1.56], [ 14.08, -21.50, 0.48], [ -6.95, 3.05, 0.10], [ -1.93, -0.54, 32.24], [ -0.40, -0.03, -9.52] ], - [ [ -13.27, -6.98, -0.63], [ -21.39, -9.64, -1.27], [ 8.45, -18.80, 0.34], [ -4.94, 3.33, 0.35], [ -1.24, -0.16, 22.07], [ 0.24, 0.77, -7.46] ], - [ [ -36.03, -15.27, -2.05], [ -21.61, -6.31, -1.44], [ 4.24, -14.80, 1.22], [ -3.51, 4.96, 0.69], [ -1.47, 1.02, 17.51], [ 0.02, 0.97, -6.00] ], - [ [ -56.31, -19.78, -3.49], [ -25.21, -4.17, -2.30], [ 1.33, -9.02, 1.75], [ -2.24, 4.68, 0.72], [ -1.24, 1.81, 10.27], [ 0.21, 0.99, -5.74] ], - [ [ -86.41, -23.06, -6.84], [ -34.94, -2.39, -4.40], [ 0.06, -5.95, 2.75], [ -0.30, 1.46, 1.27], [ -1.06, 3.10, 6.73], [ 0.15, 1.57, -1.34] ] ] ), - + [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], [ + [[139.76, 57.34, -16.27], [-52.81, -23.11, 12.04], [32.18, -67.08, 12.44], [19.63, -43.90, 9.31], [9.08, 18.22, 74.78], [-3.39, 2.26, 15.96]], + [[91.35, 36.27, -6.50], [-43.98, -19.02, 7.49], [46.88, -100.51, 20.06], [9.76, -22.95, 5.93], [6.26, 20.79, 89.53], [-2.24, 2.88, 13.53]], + [[51.89, 19.32, -1.00], [-41.04, -17.52, 5.91], [52.65, -115.01, 24.63], [3.38, -8.05, 4.65], [4.48, 23.91, 102.07], [-1.86, 3.01, 6.14]], + [[9.27, 1.23, 5.33], [-42.36, -18.03, 5.83], [53.45, -116.09, 29.37], [-1.80, 3.69, 2.43], [2.54, 26.79, 101.30], [-2.09, 0.92, -4.28]], + [[-32.82, -16.73, 10.66], [-39.90, -16.88, 4.78], [49.10, -107.71, 29.52], [-7.52, 15.61, -2.65], [0.30, 25.77, 93.56], [-1.92, -4.03, -16.55]], + [[-70.51, -32.54, 14.91], [-38.96, -16.55, 3.81], [38.76, -85.65, 24.37], [-16.39, 35.55, -9.99], [-1.33, 19.07, 69.15], [-0.57, -7.85, -26.68]], + [[-110.73, -49.84, 18.24], [-40.20, -17.01, 3.47], [15.89, -35.68, 9.21], [-17.74, 39.03, -11.30], [-0.78, 9.99, 40.04], [0.66, -8.57, -30.42]], + [[-150.90, -66.56, 21.84], [-40.14, -16.43, 3.72], [3.25, -7.53, 1.75], [-7.56, 17.27, -3.62], [-0.02, 1.93, 8.32], [0.86, -7.55, -33.03]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -110,21 +106,18 @@ class MeshType_3d_bladder1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 8 + 'Number of elements': 7 }, 'meshEdits': exnodeStringFromNodeValues( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, - Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [ [ 0.9, 3.7, 0.0 ], [ -0.8, -3.6, 0.0 ], [ 3.2, -0.6, 0.0 ], [ -1.3, -0.5, 0.0 ], [ 0.0, 0.0, 2.6 ], [ 0.0, 0.0, 0.9 ] ], - [ [ -0.1, 0.7, 0.0 ], [ -1.2, -2.4, 0.0 ], [ 2.0, -1.5, 0.0 ], [ -1.1, -1.3, 0.0 ], [ 0.0, 0.0, 3.1 ], [ 0.0, 0.0, 0.1 ] ], - [ [ -1.4, -1.1, 0.0 ], [ -1.6, -1.1, 0.0 ], [ 1.0, -3.0, 0.0 ], [ -1.3, -0.8, 0.0 ], [ 0.0, 0.0, 3.0 ], [ 0.0, 0.0, -0.2 ] ], - [ [ -2.9, -1.6, 0.0 ], [ -1.6, 0.2, 0.0 ], [ -0.6, -3.3, 0.0 ], [ -1.4, 0.2, 0.0 ], [ 0.0, 0.0, 2.8 ], [ 0.0, 0.0, -0.1 ] ], - [ [ -4.3, -0.8, 0.0 ], [ -1.2, 1.1, 0.0 ], [ -1.8, -2.5, 0.0 ], [ -0.8, 1.1, 0.0 ], [ 0.0, 0.0, 2.9 ], [ 0.0, 0.0, -0.1 ] ], - [ [ -5.2, 0.6, 0.0 ], [ -0.8, 1.6, 0.0 ], [ -2.2, -1.1, 0.0 ], [ 0.2, 1.1, 0.0 ], [ 0.0, 0.0, 2.5 ], [ 0.0, 0.0, -0.7 ] ], - [ [ -5.9, 2.3, 0.0 ], [ -0.5, 1.3, 0.0 ], [ -1.3, -0.4, 0.0 ], [ 0.6, 0.3, 0.0 ], [ 0.0, 0.0, 1.4 ], [ 0.0, 0.0, -0.7 ] ], - [ [ -6.2, 3.2, 0.0 ], [ -0.4, 0.9, 0.0 ], [ -0.8, -0.3, 0.0 ], [ 0.1, -0.0, 0.0 ], [ 0.0, 0.0, 0.9 ], [ 0.0, 0.0, -0.2 ] ], - [ [ -6.8, 4.1, 0.0 ], [ -0.7, 0.9, 0.0 ], [ -1.1, -0.5, 0.0 ], [ -0.7, -0.4, 0.0 ], [ 0.0, 0.0, 1.1 ], [ 0.0, 0.0, 0.6 ] ] ] ), - + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [[54.13, 48.48, 12.30], [-7.00, -7.20, -1.74], [2.81, -2.80, 0.27], [8.05, -8.69, 0.83], [-0.56, -0.25, 3.28], [-1.03, -0.38, 5.83]], + [[45.64, 40.32, 10.27], [-9.99, -9.12, -2.31], [9.36, -10.47, 0.88], [5.04, -6.65, 0.39], [-1.44, -0.57, 8.47], [-0.71, -0.27, 4.55]], + [[34.10, 30.30, 7.68], [-11.90, -9.54, -2.50], [12.45, -15.79, 0.99], [1.92, -4.02, -0.41], [-1.95, -0.77, 12.19], [-0.23, -0.37, 2.65]], + [[21.85, 21.25, 5.27], [-12.81, -9.14, -2.63], [13.20, -18.51, 0.06], [-0.36, -1.77, -0.92], [-1.90, -1.31, 13.78], [0.21, -0.36, 0.38]], + [[8.49, 12.04, 2.41], [-14.44, -8.62, -2.68], [11.66, -19.26, -0.86], [-2.78, 1.37, -0.56], [-1.51, -1.48, 12.86], [0.47, 0.09, -1.85]], + [[-6.98, 4.11, -0.07], [-14.87, -7.05, -2.20], [7.56, -15.62, -1.03], [-4.79, 7.26, -0.08], [-0.95, -1.12, 10.03], [0.68, 0.11, -3.53]], + [[-21.21, -2.10, -2.00], [-16.58, -6.58, -1.81], [2.15, -5.14, -1.02], [-3.60, 6.99, 0.36], [-0.15, -1.23, 5.87], [0.48, 0.38, -3.79]], + [[-40.17, -8.90, -3.57], [-21.33, -7.01, -1.33], [0.89, -2.66, -0.20], [1.07, -2.03, 1.29], [-0.09, -0.22, 2.55], [-0.35, 1.65, -2.85]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -151,15 +144,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [ [ 73.1, 50.2, 0.0 ], [ -18.5, -35.4, 0.0 ], [ 18.5, -10.9, 0.0 ], [ 18.6, -8.2, 0.0 ], [ 0.0, 0.0, 27.8 ], [ 0.0, 0.0, 8.6 ] ], - [ [ 57.3, 20.3, 0.0 ], [ -13.1, -24.4, 0.0 ], [ 30.1, -17.0, 0.0 ], [ 4.6, -4.0, 0.0 ], [ 0.0, 0.0, 33.3 ], [ 0.0, 0.0, 2.4 ] ], - [ [ 47.0, 1.4, 0.0 ], [ -12.6, -19.8, 0.0 ], [ 30.2, -19.7, 0.0 ], [ -4.3, -4.5, 0.0 ], [ 0.0, 0.0, 33.7 ], [ 0.0, 0.0, -0.7 ] ], - [ [ 32.0, -18.9, 0.0 ], [ -19.5, -14.4, 0.0 ], [ 20.7, -26.4, 0.0 ], [ -13.7, -4.9, 0.0 ], [ 0.0, 0.0, 31.6 ], [ 0.0, 0.0, -3.7 ] ], - [ [ 10.7, -26.3, 0.0 ], [ -24.3, 1.9, 0.0 ], [ 3.1, -29.7, 0.0 ], [ -16.7, 4.8, 0.0 ], [ 0.0, 0.0, 26.5 ], [ 0.0, 0.0, -8.8 ] ], - [ [ -11.3, -14.4, 0.0 ], [ -14.4, 19.6, 0.0 ], [ -12.7, -15.9, 0.0 ], [ -4.1, 13.5, 0.0 ], [ 0.0, 0.0, 13.5 ], [ 0.0, 0.0, -7.8 ] ], - [ [ -15.8, 7.8, 0.0 ], [ -8.3, 18.3, 0.0 ], [ -6.4, -2.7, 0.0 ], [ 2.8, 4.4, 0.0 ], [ 0.0, 0.0, 10.4 ], [ 0.0, 0.0, -1.7 ] ], - [ [ -26.2, 21.4, 0.0 ], [ -11.8, 8.4, 0.0 ], [ -6.3, -4.9, 0.0 ], [ -2.6, -8.8, 0.0 ], [ 0.0, 0.0, 9.8 ], [ 0.0, 0.0, 0.5 ] ] ] ), - + [[150.30, 61.10, -12.86], [-47.11, -20.16, 6.83], [30.80, -67.69, 12.69], [27.21, -60.65, 11.72], [4.10, 16.06, 75.71], [0.28, 9.33, 47.19]], + [[103.17, 40.96, -6.43], [-47.13, -20.11, 6.03], [50.46, -111.70, 21.82], [12.12, -27.37, 6.55], [4.11, 23.30, 109.78], [-0.27, 5.16, 20.95]], + [[56.04, 20.87, -0.79], [-46.95, -19.87, 5.88], [55.04, -122.46, 25.78], [2.12, -1.88, 3.69], [3.57, 26.38, 117.64], [-1.13, 4.30, 6.43]], + [[9.27, 1.23, 5.33], [-41.12, -18.12, 5.34], [54.72, -115.54, 29.21], [-1.45, 8.26, 1.45], [1.86, 31.89, 122.66], [-2.07, 0.43, -8.11]], + [[-26.27, -15.18, 9.90], [-33.31, -15.33, 4.01], [52.40, -106.25, 29.14], [-7.06, 15.91, -2.71], [-0.49, 28.39, 104.42], [-1.72, -5.12, -21.84]], + [[-57.34, -29.43, 13.39], [-33.25, -15.20, 3.49], [41.21, -84.57, 24.12], [-17.19, 34.68, -9.70], [-1.65, 21.85, 79.44], [-0.13, -9.00, -31.73]], + [[-92.77, -45.59, 16.85], [-33.04, -15.33, 3.34], [17.20, -35.10, 9.08], [-18.39, 37.88, -10.95], [-0.62, 10.06, 40.03], [0.80, -9.84, -35.29]], + [[-123.44, -60.05, 20.05], [-28.30, -13.60, 3.06], [3.71, -7.33, 1.70], [-8.60, 17.67, -3.81], [-0.03, 1.92, 8.32], [0.39, -6.43, -28.12]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -182,20 +174,18 @@ class MeshType_3d_bladder1(Scaffold_base): 'D2 derivatives': True, 'D3 derivatives': True, 'Length': 1.0, - 'Number of elements': 8 + 'Number of elements': 7 }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [ [ 11.3, 13.4, 0.0 ], [ 0.3, -13.4, 0.0 ], [ 9.4, -1.3, 0.0 ], [ -1.0, -5.6, 0.0 ], [ 0.0, 0.0, 7.4 ], [ 0.0, 0.0, 1.5 ] ], - [ [ 9.3, 2.1, 0.0 ], [ -4.4, -8.7, 0.0 ], [ 7.4, -6.1, 0.0 ], [ -3.0, -3.9, 0.0 ], [ 0.0, 0.0, 8.5 ], [ 0.0, 0.0, 0.7 ] ], - [ [ 4.0, -3.6, 0.0 ], [ -6.8, -3.8, 0.0 ], [ 3.7, -9.4, 0.0 ], [ -4.9, -2.4, 0.0 ], [ 0.0, 0.0, 9.0 ], [ 0.0, 0.0, 0.1 ] ], - [ [ -3.4, -5.1, 0.0 ], [ -6.4, 0.6, 0.0 ], [ -2.4, -10.9, 0.0 ], [ -5.0, 0.9, 0.0 ], [ 0.0, 0.0, 8.8 ], [ 0.0, 0.0, -0.5 ] ], - [ [ -8.1, -3.2, 0.0 ], [ -4.4, 3.8, 0.0 ], [ -6.7, -8.3, 0.0 ], [ -2.5, 3.4, 0.0 ], [ 0.0, 0.0, 8.1 ], [ 0.0, 0.0, -1.2 ] ], - [ [ -11.4, 2.3, 0.0 ], [ -1.4, 6.4, 0.0 ], [ -6.9, -4.0, 0.0 ], [ 1.9, 4.2, 0.0 ], [ 0.0, 0.0, 6.2 ], [ 0.0, 0.0, -2.8 ] ], - [ [ -10.7, 8.9, 0.0 ], [ 0.3, 5.0, 0.0 ], [ -2.9, 0.0, 0.0 ], [ 0.9, 1.1, 0.0 ], [ 0.0, 0.0, 2.4 ], [ 0.0, 0.0, -0.6 ] ], - [ [ -10.7, 12.2, 0.0 ], [ -0.3, 3.0, 0.0 ], [ -3.5, -0.3, 0.0 ], [ -0.3, -0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, 0.4 ] ], - [ [ -11.3, 14.8, 0.0 ], [ -0.9, 2.2, 0.0 ], [ -3.5, -0.3, 0.0 ], [ 0.3, 0.1, 0.0 ], [ 0.0, 0.0, 3.4 ], [ 0.0, 0.0, -0.4 ] ] ] ), - + [[26.51, 16.41, 4.08], [-9.57, -8.90, -0.96], [4.88, -5.26, 0.16], [1.94, -3.51, 0.19], [-0.47, -0.23, 6.83], [-0.95, -0.39, 8.28]], + [[16.73, 8.32, 2.96], [-9.96, -7.26, -1.27], [6.35, -8.72, -0.01], [1.01, -3.40, -0.53], [-1.09, -0.82, 13.21], [-0.30, -0.78, 4.48]], + [[6.67, 1.90, 1.56], [-10.64, -6.01, -1.39], [6.93, -12.06, -0.88], [-0.36, -1.94, -0.43], [-1.08, -1.78, 15.91], [-0.04, -0.39, 1.12]], + [[-4.52, -3.64, 0.18], [-10.61, -4.65, -1.28], [5.60, -12.53, -0.85], [-1.88, 1.30, -0.10], [-1.18, -1.56, 15.38], [0.03, -0.00, -1.59]], + [[-14.49, -7.47, -1.01], [-8.85, -2.84, -1.10], [3.25, -9.72, -1.06], [-2.15, 3.53, 0.17], [-1.04, -1.75, 12.88], [0.25, 0.35, -3.93]], + [[-22.12, -9.45, -1.99], [-7.82, -1.62, -0.91], [1.25, -5.66, -0.61], [-1.42, 3.63, 0.34], [-0.71, -1.00, 7.89], [0.41, 0.62, -4.91]], + [[-30.11, -10.70, -2.82], [-8.26, -1.29, -0.82], [0.42, -2.47, -0.38], [-0.55, 2.36, 0.22], [-0.22, -0.51, 3.06], [0.30, 0.34, -3.06]], + [[-38.65, -12.04, -3.63], [-8.81, -1.38, -0.79], [0.17, -1.00, -0.16], [0.04, 0.58, 0.21], [-0.12, -0.33, 1.88], [-0.09, 0.02, 0.71]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -242,12 +232,12 @@ def getDefaultOptions(cls, parameterSetName='Default'): centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Cat 1'] options = { 'Central path': copy.deepcopy(centralPathOption), - 'Number of elements along bladder': 12, + 'Number of elements along dome': 8, + 'Number of elements along neck': 4, 'Number of elements around bladder': 8, 'Number of elements through wall': 1, - 'Wall thickness': 0.5, + 'Wall thickness': 1.5, 'Ureter position around': 0.67, - 'Ureter position down': 0.8, 'Use linear through wall': True, 'Refine': False, 'Refine number of elements along bladder': 4, @@ -255,41 +245,37 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Human 1' in parameterSetName: - options['Number of elements along bladder'] = 8 + options['Number of elements along dome'] = 8 options['Number of elements around bladder'] = 12 - options['Wall thickness'] = 1.0 - options['Ureter position around'] = 0.82 # should be on the dorsal part (> 0.5) - options['Ureter position down'] = 0.63 + options['Wall thickness'] = 2.0 + options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) if 'Mouse 1' in parameterSetName: - options['Number of elements along bladder'] = 10 - options['Number of elements around bladder'] = 4 - options['Wall thickness'] = 0.2 + options['Number of elements along dome'] = 10 + # options['Number of elements around bladder'] = 8 + options['Wall thickness'] = 0.5 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) - options['Ureter position down'] = 0.865 if 'Pig 1' in parameterSetName: - options['Number of elements along bladder'] = 6 + options['Number of elements along dome'] = 10 options['Number of elements around bladder'] = 16 - options['Wall thickness'] = 2.0 + options['Wall thickness'] = 3.0 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) - options['Ureter position down'] = 0.865 if 'Rat 1' in parameterSetName: - options['Number of elements along bladder'] = 12 + options['Number of elements along dome'] = 12 options['Number of elements around bladder'] = 12 - options['Wall thickness'] = 0.1 + options['Wall thickness'] = 0.2 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) - options['Ureter position down'] = 0.83 return options @staticmethod def getOrderedOptionNames(): optionNames = [ 'Central path', - 'Number of elements along bladder', + 'Number of elements along dome', + 'Number of elements along neck', 'Number of elements around bladder', 'Number of elements through wall', 'Wall thickness', 'Ureter position around', - 'Ureter position down', 'Use linear through wall', 'Refine', 'Refine number of elements around bladder', @@ -333,7 +319,6 @@ 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 elements along bladder', 'Number of elements around bladder', 'Number of elements through wall', 'Refine number of elements along bladder', @@ -341,23 +326,16 @@ def checkOptions(cls, options): 'Refine number of elements through wall']: if options[key] < 1: options[key] = 1 - # if options['Number of elements around bladder'] % 2: - # options['Number of elements around bladder'] += 1 if options['Number of elements around bladder'] % 2 != 0: - options['Number of elements around bladder'] += 1 + if options['Number of elements around bladder'] % 4 > 1: + options['Number of elements around bladder'] += 1 + else: + options['Number of elements around bladder'] -= 1 + else: + if options['Number of elements around bladder'] % 4 != 0: + options['Number of elements around bladder'] += 2 if options['Ureter position around'] < 0.5: options['Ureter position around'] = 0.5 # ureters are on the dorsal part of the bladder - # elif options['Ureter position around'] > 0.9: - # options['Ureter position around'] = 0.9 - # if options['Ureter position down'] < 0.15: - # options['Ureter position down'] = 0.15 - # elif options['Ureter position down'] > 0.95: - # options['Ureter position down'] = 0.95 - - # if options['Number of elements around bladder'] < 12: - # options['Number of elements around bladder'] = 12 - # if options['Number of elements through wall'] != (1 or 4): - # options['Number of elements through wall'] = 4 @classmethod def generateBaseMesh(cls, region, options): @@ -368,186 +346,182 @@ def generateBaseMesh(cls, region, options): :return: None """ centralPath = options['Central path'] - elementsCountAlongBladder = options['Number of elements along bladder'] + elementsCountAlongDome = options['Number of elements along dome'] + elementsCountAlongNeck = options['Number of elements along neck'] elementsCountAroundBladder = options['Number of elements around bladder'] elementsCountThroughWall = options['Number of elements through wall'] wallThickness = options['Wall thickness'] useCrossDerivatives = False useCubicHermiteThroughWall = not (options['Use linear through wall']) + elementsCountAlongBladder = elementsCountAlongDome + elementsCountAlongNeck + ureterPositionAroundFactor = options['Ureter position around'] / 2 + fm = region.getFieldmodule() fm.beginChange() - - coordinates = findOrCreateFieldCoordinates(fm) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - nodetemplate = nodes.createNodetemplate() - nodetemplate.defineField(coordinates) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - if useCrossDerivatives: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) - if useCubicHermiteThroughWall: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) - if useCrossDerivatives: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) - cache = fm.createFieldcache() mesh = fm.findMeshByDimension(3) - nodeIdentifier = 1 - elementIdentifier = 1 - - # Extract length of each group along bladder from central path - arcLengthOfGroupsAlong = [] - bladderTermsAlong = [None, 'dome of the bladder', 'neck of urinary bladder'] - for i in range(len(bladderTermsAlong)): - 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=bladderTermsAlong[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 - - print('arcLengthOfGroupsAlong', arcLengthOfGroupsAlong) - sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, len(cx)) - sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) - sd3, sd13 = interp.interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) - - # Create annotation groups for bladder - bladderCentralPathLength = sum(arcLengthOfGroupsAlong[1:]) - allAnnotationGroups = [] - bodyGroup = AnnotationGroup(region, get_bladder_term("dome of the bladder")) - neckGroup = AnnotationGroup(region, get_bladder_term("neck of urinary bladder")) - bladderGroup = AnnotationGroup(region, get_bladder_term("urinary bladder")) + firstNodeIdentifier = 1 + firstElementIdentifier = 1 - annotationGroupAlong = [[bladderGroup, bodyGroup], [bladderGroup, neckGroup]] - annotationGroupsAround = [[]] - for i in range(elementsCountAroundBladder): - annotationGroupsAround.append([]) - annotationGroupsThroughWall = [] - for i in range(elementsCountThroughWall): - annotationGroupsThroughWall.append([]) + # # Central path + # tmpRegion = region.createRegion() + # centralPath.generate(tmpRegion) + # arcLengthOfGroupsAlong = [] + # bladderTermsAlong = ['dome of the bladder', 'neck of urinary bladder'] + # for i in range(len(bladderTermsAlong)): + # # 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=bladderTermsAlong[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_dome = cxGroup + # cd1_dome = cd1Group + # cd2_dome = cd2Group + # cd3_dome = cd3Group + # cd12_dome = cd12Group + # cd13_dome = cd13Group + # else: + # cx_neck = cxGroup + # cd1_neck = cd1Group + # cd2_neck = cd2Group + # cd3_neck = cd3Group + # cd12_neck = cd12Group + # cd13_neck = cd13Group + # del tmpRegion + # + # domeLength = arcLengthOfGroupsAlong[0] + # neckLength = arcLengthOfGroupsAlong[1] + # domeSegmentLength = arcLengthOfGroupsAlong[0] / elementsCountAlongDome + # neckSegmentLength = arcLengthOfGroupsAlong[1] / elementsCountAlongNeck + # # total = arcLengthOfGroupsAlong[0] + arcLengthOfGroupsAlong[1] + # bladderCentralPathLength = sum(arcLengthOfGroupsAlong) + # # print('total', total) + # print('bladderCentralPathLength', bladderCentralPathLength) - # annotation fiducial points - markerGroup = findOrCreateFieldGroup(fm, "marker") - markerName = findOrCreateFieldStoredString(fm, name="marker_name") - markerLocation = findOrCreateFieldStoredMeshLocation(fm, mesh, name="marker_location") + # Central path + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + cx_dome, cd1_dome, cd2_dome, cd3_dome, cd12_dome, cd13_dome = \ + 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='dome of the bladder') + cx_neck, cd1_neck, cd2_neck, cd3_neck, cd12_neck, cd13_neck = \ + 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='neck of urinary bladder') - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() - markerTemplateInternal = nodes.createNodetemplate() - markerTemplateInternal.defineField(markerName) - markerTemplateInternal.defineField(markerLocation) + # Find arcLength + # Dome + domeLength = 0.0 + elementsCountInDome = len(cx_dome) - 1 + for e in range(elementsCountInDome): + arcLength = interp.getCubicHermiteArcLength(cx_dome[e], cd1_dome[e], + cx_dome[e + 1], cd1_dome[e + 1]) + domeLength += arcLength + domeSegmentLength = domeLength / elementsCountAlongDome + # Neck + neckLength = 0.0 + elementsCountInNeck = len(cx_neck) - 1 + for e in range(elementsCountInNeck): + arcLength = interp.getCubicHermiteArcLength(cx_neck[e], cd1_neck[e], + cx_neck[e + 1], cd1_neck[e + 1]) + neckLength += arcLength + neckSegmentLength = neckLength / elementsCountAlongNeck + bladderCentralPathLength = domeLength + neckLength + del tmpRegion - # Fundus diameter - fundusRadius = vector.magnitude(sd2[0]) - lengthElementAlongTrackSurface = bladderCentralPathLength / elementsCountAlongBladder - elementsAlongFundus = int(fundusRadius / lengthElementAlongTrackSurface) + # Sample central path + # Dome + sx_dome, sd1_dome, se_dome, sxi_dome, ssf_dome = interp.sampleCubicHermiteCurves(cx_dome, cd1_dome, len(cx_dome)) + sd2_dome, sd12_dome = interp.interpolateSampleCubicHermite(cd2_dome, cd12_dome, se_dome, sxi_dome, ssf_dome) + sd3_dome, sd13_dome = interp.interpolateSampleCubicHermite(cd3_dome, cd13_dome, se_dome, sxi_dome, ssf_dome) + # Neck + sx_neck, sd1_neck, se_neck, sxi_neck, ssf_neck = interp.sampleCubicHermiteCurves(cx_neck, cd1_neck, elementsCountAlongNeck) + sd2_neck, sd12_neck = interp.interpolateSampleCubicHermite(cd2_neck, cd12_neck, se_neck, sxi_neck, ssf_neck) + sd3_neck, sd13_neck = interp.interpolateSampleCubicHermite(cd3_neck, cd13_neck, se_neck, sxi_neck, ssf_neck) + # Find Apex nodes d2 d2Apex = [] - d2 = sd2[0] - # print('sd1[0]', sd1[0]) - # print('sd2[0]', sd2[0]) - # print('vector.normalise(sd2[0]', vector.normalise(sd2[0])) - # print('sd3[0]', sd3[0]) - # print('vector.normalise(sd3[0]', vector.normalise(sd3[0])) + d2 = sd2_dome[0] for n1 in range(elementsCountAroundBladder): rotAngle = n1 * 2.0 * math.pi / elementsCountAroundBladder - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2[0]), vector.normalise(sd3[0]))) + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2_dome[0]), vector.normalise(sd3_dome[0]))) rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] d2Apex.append(d2Rot) - # if n1 == 1: - # print('rotAngle', rotAngle) - # print('rotAxis', rotAxis) - # print('rotFrame', rotFrame) - # print('d2Rot', d2Rot) - - xEllipses = [] - d1Ellipses = [] - print('len(sx)', len(sx)) - # print('elementsAlongFundus', elementsAlongFundus) - for n in range(1, len(sx)): - px, pd1 = createEllipsePoints(sx[n], 2 * math.pi, sd2[n], sd3[n], elementsCountAroundBladder, + + # Create ellipses along dome around the central path + xEllipses_dome = [] + d1Ellipses_dome = [] + for n in range(1, len(sx_dome)): + px, pd1 = createEllipsePoints(sx_dome[n], 2 * math.pi, sd2_dome[n], sd3_dome[n], elementsCountAroundBladder, startRadians=0.0) - xEllipses.append(px) - d1Ellipses.append(pd1) - # print('xEllipses', xEllipses) - print('len(xEllipses)', len(xEllipses)) - # print('len(xEllipses[0])', len(xEllipses[0])) - # print('len(xEllipses[0][0])', len(xEllipses[0][0])) + xEllipses_dome.append(px) + d1Ellipses_dome.append(pd1) # Find d2 d2Raw = [] for n1 in range(elementsCountAroundBladder): xAlong = [] d2Along = [] - for n2 in range(len(xEllipses) - 1): - v1 = xEllipses[n2][n1] - v2 = xEllipses[n2 + 1][n1] + for n2 in range(len(xEllipses_dome) - 1): + v1 = xEllipses_dome[n2][n1] + v2 = xEllipses_dome[n2 + 1][n1] d2 = findDerivativeBetweenPoints(v1, v2) xAlong.append(v1) d2Along.append(d2) - xAlong.append(xEllipses[-1][n1]) + xAlong.append(xEllipses_dome[-1][n1]) d2Along.append(d2) d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) d2Raw.append(d2Smoothed) # Rearrange d2 - d2Ellipses = [] - for n2 in range(len(xEllipses)): + d2Ellipses_dome = [] + for n2 in range(len(xEllipses_dome)): d2Around = [] for n1 in range(elementsCountAroundBladder): d2 = d2Raw[n1][n2] d2Around.append(d2) - d2Ellipses.append(d2Around) - - # Merge fundus apex and body - xAll = [[sx[0]] * elementsCountAroundBladder] + xEllipses - d2All = [d2Apex] + d2Ellipses - print('len(xAll)', len(xAll)) + d2Ellipses_dome.append(d2Around) + # Merge apex and dome + xDome = [[sx_dome[0]] * elementsCountAroundBladder] + xEllipses_dome + d2Dome = [d2Apex] + d2Ellipses_dome - # Spread out elements + # Spread out elements along dome of the bladder xRaw = [] d2Raw = [] for n1 in range(elementsCountAroundBladder): xAlong = [] d2Along = [] - for n2 in range(len(xAll)): - xAlong.append(xAll[n2][n1]) - d2Along.append(d2All[n2][n1]) - xSampledAlong, d2SampledAlong = interp.sampleCubicHermiteCurves(xAlong, d2Along, - elementsCountAlongBladder, + for n2 in range(len(xDome)): + xAlong.append(xDome[n2][n1]) + d2Along.append(d2Dome[n2][n1]) + xSampledAlongDome, d2SampledAlongDome = interp.sampleCubicHermiteCurves(xAlong, d2Along, + elementsCountAlongDome, arcLengthDerivatives=True)[0:2] - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlong, d2SampledAlong) - xRaw.append(xSampledAlong) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongDome, d2SampledAlongDome) + xRaw.append(xSampledAlongDome) d2Raw.append(d2Smoothed) # Rearrange x and d2 xSampledAll = [] d1SampledAll = [] d2SampledAll = [] - for n2 in range(elementsCountAlongBladder + 1): + for n2 in range(elementsCountAlongDome + 1): xAround = [] d1Around = [] d2Around = [] @@ -556,7 +530,6 @@ def generateBaseMesh(cls, region, options): d2 = d2Raw[n1][n2] xAround.append(x) d2Around.append(d2) - # Calculate d1 if n2 > 0: v1 = xRaw[n1][n2] @@ -564,46 +537,311 @@ def generateBaseMesh(cls, region, options): d1 = findDerivativeBetweenPoints(v1, v2) d1Around.append(d1) else: - d1Around.append(d2Raw[int(elementsCountAroundBladder * 0.75)][0]) - + d1Around.append(d2Raw[n2][0]) if n2 > 0: d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) else: d1Smoothed = d1Around + xSampledAll.append(xAround) + d1SampledAll.append(d1Smoothed) + # d2SampledAll.append(d2Around) + if n2 == elementsCountAlongDome: + pass + else: + d2SampledAll.append(d2Around) + + # Transition + transitLength = (domeSegmentLength + neckSegmentLength) / 2 + if transitLength < neckSegmentLength: + e = 1 + xi = transitLength / neckSegmentLength + else: + e = int(transitLength / neckSegmentLength) + 1 + xi = transitLength / (e * neckSegmentLength) + xTransition = interp.interpolateCubicHermite(sx_dome[-1], sd1_dome[-1], sx_neck[e], sd1_neck[e], xi) + # d1Transition = interp.interpolateCubicHermiteDerivative(sx_dome[-1], sd1_dome[-1], sx_neck[e], sd1_neck[e], xi) + d2Transition = interp.interpolateCubicHermite(sd2_dome[-1], sd12_dome[-1], sd2_neck[e], sd12_neck[e], xi) + d3Transition = interp.interpolateCubicHermite(sd3_dome[-1], sd13_dome[-1], sd3_neck[e], sd13_neck[e], xi) + px_transit, pd1_transit = createEllipsePoints(xTransition, 2 * math.pi, d2Transition, d3Transition, elementsCountAroundBladder, + startRadians=0.0) + d2Around = [] + for n1 in range(elementsCountAroundBladder): + v1 = xSampledAll[-1][n1] + v2 = px_transit[n1] + d2 = findDerivativeBetweenPoints(v1, v2) + # xAlong.append(v1) + d2Around.append(d2) + d2SampledAll += [d2Around] + + # Create ellipses along neck around the central path + sx_neck_new = [xTransition] + sx_neck[e:] + sd2_neck_new = [d2Transition] + sd2_neck[e:] + sd3_neck_new = [d3Transition] + sd3_neck[e:] + xEllipses_neck = [] + d1Ellipses_neck = [] + for n in range(0, len(sx_neck_new)): + px, pd1 = createEllipsePoints(sx_neck_new[n], 2 * math.pi, sd2_neck_new[n], sd3_neck_new[n], elementsCountAroundBladder, + startRadians=0.0) + xEllipses_neck.append(px) + d1Ellipses_neck.append(pd1) + # Find d2 + d2Raw = [] + for n1 in range(elementsCountAroundBladder): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses_neck) - 1): + v1 = xEllipses_neck[n2][n1] + v2 = xEllipses_neck[n2 + 1][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v1) + d2Along.append(d2) + xAlong.append(xEllipses_neck[-1][n1]) + d2Along.append(d2) + # d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Raw.append(d2Along) + + # Rearrange d2 + d2Ellipses_neck_new = [] + for n2 in range(len(xEllipses_neck)): + d2Around = [] + for n1 in range(elementsCountAroundBladder): + d2 = d2Raw[n1][n2] + d2Around.append(d2) + d2Ellipses_neck_new.append(d2Around) + + # Spread out elements along neck of the bladder + xRawNeck = [] + d2RawNeck = [] + for n1 in range(elementsCountAroundBladder): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses_neck)): + xAlong.append(xEllipses_neck[n2][n1]) + d2Along.append(d2Ellipses_neck_new[n2][n1]) + xSampledAlongNeck, d2SampledAlongNeck = interp.sampleCubicHermiteCurves(xAlong, d2Along, + elementsCountAlongNeck-1, + arcLengthDerivatives=True)[0:2] + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongNeck, d2SampledAlongNeck) + xRawNeck.append(xSampledAlongNeck) + d2RawNeck.append(d2Smoothed) + + # Rearrange x and d2 + for n2 in range(elementsCountAlongNeck): + xAround = [] + d1Around = [] + d2Around = [] + for n1 in range(elementsCountAroundBladder): + x = xRawNeck[n1][n2] + d2 = d2RawNeck[n1][n2] + xAround.append(x) + d2Around.append(d2) + # Calculate d1 + v1 = xRawNeck[n1][n2] + v2 = xRawNeck[n1 + 1 if n1 < elementsCountAroundBladder - 1 else 0][n2] + d1 = findDerivativeBetweenPoints(v1, v2) + d1Around.append(d1) + d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) xSampledAll.append(xAround) d1SampledAll.append(d1Smoothed) d2SampledAll.append(d2Around) - print('len(xSampledAll)', len(xSampledAll)) - print('', xSampledAll[0]) + # Smoothing d2 from apex to down the neck + d2Raw = [] + for n1 in range(elementsCountAroundBladder): + xAlong = [] + d2Along = [] + for n2 in range(elementsCountAlongBladder): + v1 = xSampledAll[n2][n1] + v2 = xSampledAll[n2 + 1][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v1) + d2Along.append(d2) + xAlong.append(xSampledAll[-1][n1]) + d2Along.append(xSampledAll[-1][n1]) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Raw.append(d2Smoothed) + # Rearrange d2 + d2Total = [] for n2 in range(elementsCountAlongBladder + 1): - # if n2 == 0: - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][0]) - # nodeIdentifier += 1 - # else: + d2Around = [] for n1 in range(elementsCountAroundBladder): - node = nodes.createNode(nodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xSampledAll[n2][n1]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1SampledAll[n2][n1]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2SampledAll[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n2]) - # if useCrossDerivatives: - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) - nodeIdentifier += 1 + d2 = d2Raw[n1][n2] + d2Around.append(d2) + d2Total.append(d2Around) + d3UnitOuter = [] + for n2 in range(1, elementsCountAlongBladder + 1): + d3Around = [] + for n1 in range(elementsCountAroundBladder): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1SampledAll[n2][n1]), vector.normalise(d2Total[n2][n1])))) + d3UnitOuter.append(d3Around) - fm.endChange() + # Inner nodes + xInner = [] + d1Inner = [] + d2Inner = [] + d3Inner = [] + for n2 in range(elementsCountAlongBladder + 1): + for n1 in range(elementsCountAroundBladder): + x = xSampledAll[n2][n1] + d1 = d1SampledAll[n2][n1] + d2 = d2Total[n2][n1] + d3 = d3UnitOuter[n2-1][n1] + xInner.append(x) + d1Inner.append(d1) + d2Inner.append(d2) + d3Inner.append(d3) + + # Create outer layers from the inner nodes + wallThicknessList = [wallThickness] * (elementsCountAlongBladder + 1) + relativeThicknessList = [] + transitElementList = [0] * elementsCountAroundBladder + xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xInner, d1Inner, + d2Inner, d3Inner, + wallThicknessList, + relativeThicknessList, + elementsCountAroundBladder, + elementsCountAlongBladder, + elementsCountThroughWall, + transitElementList) + + # Deal with multiple nodes at the start point for closed proximal end + xApexInner = xList[0] + # Arclength between apex point and corresponding point on next face + mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], xList[2 * elementsCountAroundBladder], + d2List[2 * elementsCountAroundBladder]) + d2ApexInner = vector.setMagnitude(sd2_dome[0], mag) + + d1ApexInner = vector.crossproduct3(sd1_dome[0], d2ApexInner) + d1ApexInner = vector.setMagnitude(d1ApexInner, mag) + d3ApexUnit = vector.normalise( + vector.crossproduct3(vector.normalise(d1ApexInner), vector.normalise(d2ApexInner))) + d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] + + xFinal = [] + d1Final = [] + d2Final = [] + d3Final = [] + for n3 in range(elementsCountThroughWall + 1): + xApex = [xApexInner[c] + + d3ApexUnit[c] * wallThickness / elementsCountThroughWall * n3 for c in range(3)] + xFinal.append(xApex) + d1Final.append(d1ApexInner) + d2Final.append(d2ApexInner) + d3Final.append(d3ApexInner) + + xFinal += xList[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] + d1Final += d1List[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] + d2Final += d2List[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] + d3Final += d3List[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] - return allAnnotationGroups + xFlat = d1Flat = d2Flat = [] + # neckDiameter = vector.magnitude(sd2_neck[-1]) + # # xApexInner = xFinal[0] + # # d2ApexInner = d2Final[0] + # # Obtain flat nodes coordinates + # xFlat, d1Flat, d2Flat = obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAroundBladder, elementsCountThroughWall, + # xFinal, d1Final, d2Final, bladderCentralPathLength, neckDiameter, xApexInner, d2ApexInner, + # wallThickness) + + xOrgan = d1Organ = d2Organ = [] + + # Create annotation groups for bladder + bodyGroup = AnnotationGroup(region, get_bladder_term("dome of the bladder")) + neckGroup = AnnotationGroup(region, get_bladder_term("neck of urinary bladder")) + bladderGroup = AnnotationGroup(region, get_bladder_term("urinary bladder")) + bladderDorsalGroup = AnnotationGroup(region, get_bladder_term("dorsal part of bladder")) + bladderVentralGroup = AnnotationGroup(region, get_bladder_term("ventral part of bladder")) + + elementsCountAlongGroups = [elementsCountAlongDome, elementsCountAlongNeck] + annotationGroupAlong = [[bladderGroup, bodyGroup], [bladderGroup, neckGroup]] + annotationGroupsAlong = [] + for i in range(len(elementsCountAlongGroups)): + elementsCount = elementsCountAlongGroups[i] + for n in range(elementsCount): + annotationGroupsAlong.append(annotationGroupAlong[i]) + + elementsCountAroundGroups = [elementsCountAroundBladder // 4, elementsCountAroundBladder // 2, elementsCountAroundBladder // 4] + annotationGroupAround = [[bladderGroup, bladderVentralGroup], [bladderGroup, bladderDorsalGroup], [bladderGroup, bladderVentralGroup]] + annotationGroupsAround = [] + for i in range(len(elementsCountAroundGroups)): + elementsCount = elementsCountAroundGroups[i] + for n in range(elementsCount): + annotationGroupsAround.append(annotationGroupAround[i]) + + annotationGroupsThroughWall = [] + for i in range(elementsCountThroughWall): + annotationGroupsThroughWall.append([]) + + # Create nodes and elements + nodeIdentifier, elementIdentifier, annotationGroups = tubemesh.createNodesAndElements( + region, xFinal, d1Final, d2Final, d3Final, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, + elementsCountAroundBladder, elementsCountAlongBladder, elementsCountThroughWall, + annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, + firstNodeIdentifier, firstElementIdentifier, + useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=True) + + # Define trackSurface to put the ureters on + xTrackSurface = [] + d1TrackSurface = [] + d2TrackSurface = [] + for n2 in range(elementsCountAlongBladder + 1): + for n1 in range(elementsCountAroundBladder): + idx = n2 * elementsCountAroundBladder + elementsCountAroundBladder + n1 + xTrackSurface.append(xList[idx]) + d1TrackSurface.append(d1List[idx]) + d2TrackSurface.append(d2List[idx]) + trackSurfaceBladder = TrackSurface(elementsCountAroundBladder, elementsCountAlongBladder, + xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) + + # Ureter position + neckStartPositionAlongFactor = domeLength / bladderCentralPathLength + # neckStartPositionAlongFactor = arcLengthOfGroupsAlong[0] / bladderCentralPathLength + ureter1Position = trackSurfaceBladder.createPositionProportion(ureterPositionAroundFactor, neckStartPositionAlongFactor) + ureterElementPositionAround = ureter1Position.e1 + + # Annotation fiducial point + 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) + + # Define markers for apex and ureter junctions with bladder + apexGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("apex of urinary bladder")) + leftUreterGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("left ureter junction with bladder")) + rightUreterGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("right ureter junction with bladder")) + + idx1 = 1 + xi1 = [0.0, 0.0, 0.0] + markerList = [] + markerList.append({"group": apexGroup, "elementId": idx1, "xi": xi1}) + idx2 = elementsCountAlongDome * elementsCountAroundBladder * elementsCountThroughWall + ureterElementPositionAround + 1 + xi2 = [ureter1Position.xi1, 0.0, 0.0] + markerList.append({"group": leftUreterGroup, "elementId": idx2, "xi": xi2}) + idx3 = elementsCountAlongDome * elementsCountAroundBladder * elementsCountThroughWall + elementsCountAroundBladder - ureterElementPositionAround + xi3 = [1 - ureter1Position.xi1, 0.0, 0.0] + markerList.append({"group": rightUreterGroup, "elementId": idx3, "xi": xi3}) + + bladderNodesetGroup = bladderGroup.getNodesetGroup(nodes) + for marker in markerList: + annotationGroup = marker["group"] + markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) + cache.setNode(markerPoint) + markerLocation.assignMeshLocation(cache, mesh.findElementByIdentifier(marker["elementId"]), marker["xi"]) + markerName.assignString(cache, annotationGroup.getName()) + annotationGroup.getNodesetGroup(nodes).addNode(markerPoint) + bladderNodesetGroup.addNode(markerPoint) + nodeIdentifier += 1 + + fm.endChange() + return annotationGroups @classmethod def refineMesh(cls, meshrefinement, options): @@ -612,14 +850,148 @@ def refineMesh(cls, meshrefinement, options): :param meshrefinement: MeshRefinement, which knows source and target region. :param options: Dict containing options. See getDefaultOptions(). """ - refineElementsCountAround = options['Refine number of elements surface'] - refineElementsCountAlong = options['Refine number of elements surface'] + refineElementsCountAround = options['Refine number of elements along bladder'] + refineElementsCountAlong = options['Refine number of elements around bladder'] 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() + bodyGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("dome of the bladder")) + neckGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("neck of urinary bladder")) + urinaryBladderGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("urinary bladder")) + bladderVentralGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("ventral part of bladder")) + bladderDorsalGroup = getAnnotationGroupForTerm(annotationGroups, get_bladder_term("dorsal part of bladder")) + + mesh2d = fm.findMeshByDimension(2) + + is_exterior = fm.createFieldIsExterior() + is_exterior_face_xi3_1 = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_1)) + is_exterior_face_xi3_0 = fm.createFieldAnd(is_exterior, fm.createFieldIsOnFace(Element.FACE_TYPE_XI3_0)) + + is_body = bodyGroup.getFieldElementGroup(mesh2d) + is_body_serosa = fm.createFieldAnd(is_body, is_exterior_face_xi3_1) + is_body_lumen = fm.createFieldAnd(is_body, is_exterior_face_xi3_0) + + is_neck = neckGroup.getFieldElementGroup(mesh2d) + is_neck_serosa = fm.createFieldAnd(is_neck, is_exterior_face_xi3_1) + is_neck_lumen = fm.createFieldAnd(is_neck, is_exterior_face_xi3_0) + + is_urinaryBladder = urinaryBladderGroup.getFieldElementGroup(mesh2d) + is_urinaryBladder_serosa = fm.createFieldAnd(is_urinaryBladder, is_exterior_face_xi3_1) + is_urinaryBladder_lumen = fm.createFieldAnd(is_urinaryBladder, is_exterior_face_xi3_0) + + is_dorsal_bladder = bladderDorsalGroup.getFieldElementGroup(mesh2d) + is_ventral_bladder = bladderVentralGroup.getFieldElementGroup(mesh2d) + + serosaOfUrinaryBladder = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("serosa of urinary bladder")) + serosaOfUrinaryBladder.getMeshGroup(mesh2d).addElementsConditional(is_urinaryBladder_serosa) + lumenOfUrinaryBladder = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("bladder lumen")) + lumenOfUrinaryBladder.getMeshGroup(mesh2d).addElementsConditional(is_urinaryBladder_lumen) + + serosaOfBody = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("serosa of body of urinary bladder")) + serosaOfBody.getMeshGroup(mesh2d).addElementsConditional(is_body_serosa) + lumenOfBody = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("lumen of body of urinary bladder")) + lumenOfBody.getMeshGroup(mesh2d).addElementsConditional(is_body_lumen) + + serosaOfNeck = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("serosa of neck of urinary bladder")) + serosaOfNeck.getMeshGroup(mesh2d).addElementsConditional(is_neck_serosa) + lumenOfNeck = findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("lumen of neck of urinary bladder")) + lumenOfNeck.getMeshGroup(mesh2d).addElementsConditional(is_neck_lumen) + + is_bladder_serosa_dorsal = fm.createFieldAnd(is_urinaryBladder_serosa, is_dorsal_bladder) + serosaOfBladder_dorsal = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("dorsal part of serosa of urinary bladder")) + serosaOfBladder_dorsal.getMeshGroup(mesh2d).addElementsConditional(is_bladder_serosa_dorsal) + + is_bladder_serosa_ventral = fm.createFieldAnd(is_urinaryBladder_serosa, is_ventral_bladder) + serosaOfBladder_ventral = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("ventral part of serosa of urinary bladder")) + serosaOfBladder_ventral.getMeshGroup(mesh2d).addElementsConditional(is_bladder_serosa_ventral) + + is_bladder_lumen_dorsal = fm.createFieldAnd(is_urinaryBladder_lumen, is_dorsal_bladder) + lumenOfBladder_dorsal = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("dorsal part of urinary bladder lumen")) + lumenOfBladder_dorsal.getMeshGroup(mesh2d).addElementsConditional(is_bladder_lumen_dorsal) + + is_bladder_lumen_ventral = fm.createFieldAnd(is_urinaryBladder_lumen, is_ventral_bladder) + lumenOfBladder_ventral = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("ventral part of urinary bladder lumen")) + lumenOfBladder_ventral.getMeshGroup(mesh2d).addElementsConditional(is_bladder_lumen_ventral) + + is_body_serosa_dorsal = fm.createFieldAnd(is_body_serosa, is_dorsal_bladder) + serosaOfBody_dorsal = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("dorsal part of serosa of body of urinary bladder")) + serosaOfBody_dorsal.getMeshGroup(mesh2d).addElementsConditional(is_body_serosa_dorsal) + + is_body_serosa_ventral = fm.createFieldAnd(is_body_serosa, is_ventral_bladder) + serosaOfBody_ventral = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("ventral part of serosa of body of urinary bladder")) + serosaOfBody_ventral.getMeshGroup(mesh2d).addElementsConditional(is_body_serosa_ventral) + + is_body_lumen_dorsal = fm.createFieldAnd(is_body_lumen, is_dorsal_bladder) + lumenOfBody_dorsal = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("dorsal part of lumen of body of urinary bladder")) + lumenOfBody_dorsal.getMeshGroup(mesh2d).addElementsConditional(is_body_lumen_dorsal) + + is_body_lumen_ventral = fm.createFieldAnd(is_body_lumen, is_ventral_bladder) + lumenOfBody_ventral = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("ventral part of lumen of body of urinary bladder")) + lumenOfBody_ventral.getMeshGroup(mesh2d).addElementsConditional(is_body_lumen_ventral) + + is_neck_serosa_dorsal = fm.createFieldAnd(is_neck_serosa, is_dorsal_bladder) + serosaOfNeck_dorsal = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("dorsal part of serosa of neck of urinary bladder")) + serosaOfNeck_dorsal.getMeshGroup(mesh2d).addElementsConditional(is_neck_serosa_dorsal) + + is_neck_serosa_ventral = fm.createFieldAnd(is_neck_serosa, is_ventral_bladder) + serosaOfNeck_ventral = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("ventral part of serosa of neck of urinary bladder")) + serosaOfNeck_ventral.getMeshGroup(mesh2d).addElementsConditional(is_neck_serosa_ventral) + + is_neck_lumen_dorsal = fm.createFieldAnd(is_neck_lumen, is_dorsal_bladder) + lumenOfNeck_dorsal = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("dorsal part of lumen of neck of urinary bladder")) + lumenOfNeck_dorsal.getMeshGroup(mesh2d).addElementsConditional(is_neck_lumen_dorsal) + + is_neck_lumen_ventral = fm.createFieldAnd(is_neck_lumen, is_ventral_bladder) + lumenOfNeck_ventral = \ + findOrCreateAnnotationGroupForTerm(annotationGroups, region, + get_bladder_term("ventral part of lumen of neck of urinary bladder")) + lumenOfNeck_ventral.getMeshGroup(mesh2d).addElementsConditional(is_neck_lumen_ventral) + def findDerivativeBetweenPoints(v1, v2): """ Find vector difference between two points and rescale vector difference using cubic hermite arclength @@ -633,3 +1005,183 @@ def findDerivativeBetweenPoints(v1, v2): d = [c * arcLengthAround for c in vector.normalise(d)] return d + +def obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, elementsCountThroughWall, + xFinal, d1Final, d2Final, bladderLength, neckDiameter1, xApexInner, d2ApexInner, + bladderWallThickness): + """ + Calculates flat coordinates for the bladder when it is opened into a flat preparation. + :param elementsCountAlongBladder: Number of elements along bladder. + :param elementsCountAround: Number of elements around bladder. + :param elementsCountThroughWall: Number of elements through wall. + :param xFinal, d1Final, d2Final: Coordinates and derivatives of all nodes of coordinates field. + :param bladderLength: Bladder length along the central path. + :param neckDiameter1: Major diameter of the bladder neck. + :param xApexInner, d2ApexInner: Coordinates and d2 of the apex located on the lumen of the bladder. + :param bladderWallThickness: Thickness of wall. + :return: Coordinates and derivatives of flat coordinates field. + """ + # Calculate ellipses circumference along the bladder inner layer(lumen) + circumferenceList = [] + minorNodeAlong_x = [] + minorNodeAlong_d2 = [] + for n1 in range(1, elementsCountAlongBladder + 1): + xNodesOnEllipse = [] + d1NodesOnEllipse = [] + idMinor = (n1 - 1) * elementsCountAround * (elementsCountThroughWall + 1) + elementsCountThroughWall + 1 + minorNodeAlong_x.append(xFinal[idMinor]) + minorNodeAlong_d2.append(d2Final[idMinor]) + for n2 in range(elementsCountAround): + id = n2 + idMinor + x = xFinal[id] + d1 = d1Final[id] + xNodesOnEllipse.append(x) + d1NodesOnEllipse.append(d1) + xNodesOnEllipse.append(xFinal[idMinor]) + d1NodesOnEllipse.append(d1Final[idMinor]) + circumference = interp.getCubicHermiteCurvesLength(xNodesOnEllipse, d1NodesOnEllipse) + circumferenceList.append(circumference) + maxCircumference = max(circumferenceList) + + # Find the angle at the bottom of the bladder neck + v1 = [0.0, 0.0, bladderLength] + v2 = [0.5 * neckDiameter1, 0.0, bladderLength] + alpha = vector.angleBetweenVectors(v1, v2) + + # Find apex to urethra arcLength in minor radius + minorNodeAlong_x.insert(0, xApexInner) + minorNodeAlong_d2.insert(0, d2ApexInner) + minorarcLength = interp.getCubicHermiteCurvesLength(minorNodeAlong_x, minorNodeAlong_d2) + + # calculate nodes coordinates based on Hammer projection formulation + xfnList = [] + angleAlongUnit = (math.pi - alpha) / elementsCountAlongBladder + angleAroundUnit = 2 * math.pi / elementsCountAround + for n2 in range(1, elementsCountAlongBladder + 1): + for n1 in range(elementsCountAround + 1): + phi = -math.pi / 2 - alpha + n2 * angleAlongUnit + if n1 < elementsCountAround // 2 + 1: + theta = n1 * angleAroundUnit + else: + theta = math.pi - n1 * angleAroundUnit + t = math.sqrt(1 + math.cos(phi) * math.cos(theta / 2)) + xScale = maxCircumference / 2 + yScale = bladderLength / 2 + x = [xScale * math.cos(phi) * math.sin(theta / 2) / t, + yScale * (math.sin(phi) / t + 1), + 0.0] + xfnList.append(x) + + # Rearrange the nodes + xfnListRearranged = [] + for n2 in range(elementsCountAlongBladder): + for n1 in range(elementsCountAround + 1): + if n1 < elementsCountAround // 2 + 1: + nodeIndex = n2 * (elementsCountAround + 1) + elementsCountAround // 2 - n1 + else: + nodeIndex = n2 * (elementsCountAround + 1) + n1 + xfnListRearranged.append(xfnList[nodeIndex]) + + # Define d1 for flat nodes + d1fnListRearranged = [] + for n2 in range(elementsCountAlongBladder): + for n1 in range(elementsCountAround + 1): + if n1 == elementsCountAround: + id = (elementsCountAround + 1) * n2 + d1 = [d1fnListRearranged[id][0], -d1fnListRearranged[id][1], d1fnListRearranged[id][2]] + else: + v1 = xfnListRearranged[(elementsCountAround + 1) * n2 + n1] + v2 = xfnListRearranged[(elementsCountAround + 1) * n2 + n1 + 1] + d1 = [v2[c] - v1[c] for c in range(3)] + d1fnListRearranged.append(d1) + # Smoothing the derivatives + smoothed_d1 = [] + for n2 in range(elementsCountAlongBladder): + xLineSmoothing = [] + d1LineSmoothing = [] + for n1 in range(elementsCountAround + 1): + xLineSmoothing.append(xfnListRearranged[n2 * (elementsCountAround + 1) + n1]) + d1LineSmoothing.append(d1fnListRearranged[n2 * (elementsCountAround + 1) + n1]) + smd1 = interp.smoothCubicHermiteDerivativesLine(xLineSmoothing, d1LineSmoothing, fixAllDirections=False, + fixStartDerivative=True, fixEndDerivative=True, + fixStartDirection=False, fixEndDirection=False) + smoothed_d1 += smd1 + + # Define d2 for flat nodes + # Create lines from top go down the bladder + xNodesToDown = [] + d2NodesToDown = [] + for n2 in range(elementsCountAround + 1): + x = [xfnListRearranged[n1 * (elementsCountAround + 1) + n2] for n1 in range(0, elementsCountAlongBladder)] + xNodesToDown += x + for n1 in range(1, elementsCountAlongBladder + 1): + if n1 == elementsCountAlongBladder: + d2 = [0.0, minorarcLength / elementsCountAlongBladder, 0.0] + else: + v1 = xNodesToDown[elementsCountAlongBladder * n2 + n1 - 1] + v2 = xNodesToDown[elementsCountAlongBladder * n2 + n1] + d2 = [v2[c] - v1[c] for c in range(3)] + d2NodesToDown.append(d2) + # Smoothing the derivatives + smoothed_d2 = [] + for n1 in range(elementsCountAround + 1): + lineSmoothingNodes = [] + lineSmoothingNodes_d2 = [] + for n2 in range(elementsCountAlongBladder): + lineSmoothingNodes.append(xNodesToDown[n1 * elementsCountAlongBladder + n2]) + lineSmoothingNodes_d2.append(d2NodesToDown[n1 * elementsCountAlongBladder + n2]) + smd2 = interp.smoothCubicHermiteDerivativesLine(lineSmoothingNodes, lineSmoothingNodes_d2, fixAllDirections=False, + fixStartDerivative=False, fixEndDerivative=True, + fixStartDirection=False, fixEndDirection=False) + smoothed_d2 += smd2 + # Re-arrange the derivatives order + d2fnListRearranged = [] + for n2 in range(elementsCountAlongBladder): + for n1 in range(elementsCountAround + 1): + rd2 = smoothed_d2[n1 * elementsCountAlongBladder + n2] + d2fnListRearranged.append(rd2) + + # Create the nodes through the wall + xflatList = [] + d1flatList = [] + d2flatList = [] + for n2 in range(elementsCountThroughWall + 1): + for n1 in range(len(xfnListRearranged)): + x = [xfnListRearranged[n1][0], xfnListRearranged[n1][1], n2 * bladderWallThickness / elementsCountThroughWall] + d1 = smoothed_d1[n1] + d2 = d2fnListRearranged[n1] + xflatList.append(x) + d1flatList.append(d1) + d2flatList.append(d2) + + # Apex derivatives + v1 = xApexInner + v1 = [0.0, 0.0, 0.0] + v2 = xfnListRearranged[0] + v3 = xfnListRearranged[elementsCountAround // 2] + v21 = [v2[c] - v1[c] for c in range(3)] + v31 = [v3[c] - v1[c] for c in range(3)] + d1Mag = vector.magnitude(v21) + d2Mag = vector.magnitude(v31) + + # Add apex nodes to the list + xFlat = [] + d1Flat = [] + d2Flat = [] + for n1 in range(elementsCountThroughWall + 1): + # xApex = [xApexInner[0], xApexInner[1], xApexInner[2] + n1 * bladderWallThickness / elementsCountThroughWall] + xApex = [0.0, 0.0, 0.0 + n1 * bladderWallThickness / elementsCountThroughWall] + xFlat.append(xApex) + d1Flat.append([-d1Mag, 0.0, 0.0]) + d2Flat.append([0.0, d2Mag, 0.0]) + + # Re-arrange the nodes + for n3 in range(1, elementsCountAlongBladder + 1): + for n2 in range(elementsCountThroughWall + 1): + for n1 in range(elementsCountAround + 1): + i = (n3 - 1) * (elementsCountAround + 1) + n2 * (elementsCountAround + 1) * elementsCountAlongBladder + n1 + xFlat.append(xflatList[i]) + d1Flat.append(d1flatList[i]) + d2Flat.append(d2flatList[i]) + + return xFlat, d1Flat, d2Flat \ No newline at end of file From 3dea64e42f20bd6c71386f2daf4dc23cd3ec6df8 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Wed, 3 Aug 2022 13:43:24 +1200 Subject: [PATCH 03/26] Modified the code. --- .../meshtypes/meshtype_3d_bladder1.py | 769 +++++++----------- 1 file changed, 284 insertions(+), 485 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index d9c6477f..3a7014b4 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -76,14 +76,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[139.76, 57.34, -16.27], [-52.81, -23.11, 12.04], [32.18, -67.08, 12.44], [19.63, -43.90, 9.31], [9.08, 18.22, 74.78], [-3.39, 2.26, 15.96]], - [[91.35, 36.27, -6.50], [-43.98, -19.02, 7.49], [46.88, -100.51, 20.06], [9.76, -22.95, 5.93], [6.26, 20.79, 89.53], [-2.24, 2.88, 13.53]], - [[51.89, 19.32, -1.00], [-41.04, -17.52, 5.91], [52.65, -115.01, 24.63], [3.38, -8.05, 4.65], [4.48, 23.91, 102.07], [-1.86, 3.01, 6.14]], - [[9.27, 1.23, 5.33], [-42.36, -18.03, 5.83], [53.45, -116.09, 29.37], [-1.80, 3.69, 2.43], [2.54, 26.79, 101.30], [-2.09, 0.92, -4.28]], - [[-32.82, -16.73, 10.66], [-39.90, -16.88, 4.78], [49.10, -107.71, 29.52], [-7.52, 15.61, -2.65], [0.30, 25.77, 93.56], [-1.92, -4.03, -16.55]], - [[-70.51, -32.54, 14.91], [-38.96, -16.55, 3.81], [38.76, -85.65, 24.37], [-16.39, 35.55, -9.99], [-1.33, 19.07, 69.15], [-0.57, -7.85, -26.68]], - [[-110.73, -49.84, 18.24], [-40.20, -17.01, 3.47], [15.89, -35.68, 9.21], [-17.74, 39.03, -11.30], [-0.78, 9.99, 40.04], [0.66, -8.57, -30.42]], - [[-150.90, -66.56, 21.84], [-40.14, -16.43, 3.72], [3.25, -7.53, 1.75], [-7.56, 17.27, -3.62], [-0.02, 1.93, 8.32], [0.86, -7.55, -33.03]]]), + [[139.76, 57.34, -16.27], [-48.91, -19.25, 7.52], [25.22, -60.05, 10.30], [13.84, -27.31, 3.97], [4.34, 11.87, 58.57], [0.50, 3.10, 20.20]], + [[93.16, 38.43, -9.34], [-44.30, -18.57, 6.33], [37.80, -85.02, 15.07], [11.31, -22.63, 5.57], [4.61, 16.17, 79.63], [0.05, 5.49, 21.92]], + [[51.16, 20.26, -3.58], [-42.36, -18.06, 5.86], [47.96, -105.53, 21.36], [5.99, -12.80, 6.16], [4.45, 22.74, 102.34], [-1.40, 5.62, 13.90]], + [[8.43, 2.30, 2.37], [-42.52, -17.82, 5.26], [49.71, -110.52, 27.39], [0.24, -1.20, 4.10], [1.79, 27.40, 107.31], [-2.40, 1.97, -2.17]], + [[-33.87, -15.38, 6.95], [-39.81, -16.66, 4.39], [48.45, -107.98, 29.59], [-5.06, 13.34, -1.82], [-0.35, 26.73, 98.10], [-0.90, -4.12, -19.76]], + [[-71.20, -31.01, 11.15], [-38.71, -16.87, 4.70], [40.03, -85.11, 24.22], [-15.45, 35.80, -10.05], [-0.15, 19.57, 69.02], [0.48, -8.03, -29.10]], + [[-111.26, -49.16, 16.38], [-39.85, -17.77, 5.34], [16.93, -35.23, 9.08], [-18.25, 38.75, -11.22], [0.63, 10.58, 39.89], [0.21, -8.76, -30.38]], + [[-150.90, -66.56, 21.84], [-39.43, -17.02, 5.58], [3.46, -7.44, 1.72], [-8.70, 16.83, -3.49], [0.29, 2.05, 8.29], [-0.90, -8.30, -32.83]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -144,14 +144,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[150.30, 61.10, -12.86], [-47.11, -20.16, 6.83], [30.80, -67.69, 12.69], [27.21, -60.65, 11.72], [4.10, 16.06, 75.71], [0.28, 9.33, 47.19]], - [[103.17, 40.96, -6.43], [-47.13, -20.11, 6.03], [50.46, -111.70, 21.82], [12.12, -27.37, 6.55], [4.11, 23.30, 109.78], [-0.27, 5.16, 20.95]], - [[56.04, 20.87, -0.79], [-46.95, -19.87, 5.88], [55.04, -122.46, 25.78], [2.12, -1.88, 3.69], [3.57, 26.38, 117.64], [-1.13, 4.30, 6.43]], - [[9.27, 1.23, 5.33], [-41.12, -18.12, 5.34], [54.72, -115.54, 29.21], [-1.45, 8.26, 1.45], [1.86, 31.89, 122.66], [-2.07, 0.43, -8.11]], - [[-26.27, -15.18, 9.90], [-33.31, -15.33, 4.01], [52.40, -106.25, 29.14], [-7.06, 15.91, -2.71], [-0.49, 28.39, 104.42], [-1.72, -5.12, -21.84]], - [[-57.34, -29.43, 13.39], [-33.25, -15.20, 3.49], [41.21, -84.57, 24.12], [-17.19, 34.68, -9.70], [-1.65, 21.85, 79.44], [-0.13, -9.00, -31.73]], - [[-92.77, -45.59, 16.85], [-33.04, -15.33, 3.34], [17.20, -35.10, 9.08], [-18.39, 37.88, -10.95], [-0.62, 10.06, 40.03], [0.80, -9.84, -35.29]], - [[-123.44, -60.05, 20.05], [-28.30, -13.60, 3.06], [3.71, -7.33, 1.70], [-8.60, 17.67, -3.81], [-0.03, 1.92, 8.32], [0.39, -6.43, -28.12]]]), + [[177.93, 203.27, -6.98], [-39.04, -53.00, 0.83], [30.11, -22.17, 0.29], [51.78, -52.34, -1.70], [0.03, 0.42, 28.30], [1.06, -1.92, 120.97]], + [[133.76, 151.30, -6.66], [-49.17, -50.77, -0.19], [66.66, -64.55, -1.68], [21.33, -32.41, -2.24], [1.30, -1.69, 116.41], [1.47, -2.29, 55.25]], + [[79.63, 102.22, -7.39], [-55.84, -46.38, -0.19], [71.68, -86.28, -4.21], [-0.40, -15.45, 2.49], [3.00, -4.17, 136.47], [-0.79, 2.99, 6.58]], + [[22.26, 58.63, -7.05], [-62.26, -42.93, 1.27], [65.94, -95.54, 3.23], [-9.21, -3.67, 4.74], [-0.25, 4.21, 129.76], [-1.86, 5.07, -12.37]], + [[-44.89, 16.76, -4.76], [-67.15, -38.10, 1.57], [52.92, -93.08, 5.01], [-16.55, 14.33, 1.48], [-0.59, 5.64, 111.17], [-0.96, 1.25, -22.72]], + [[-111.81, -17.62, -3.87], [-64.44, -31.46, 0.87], [33.03, -67.48, 6.20], [-19.80, 30.23, -1.80], [-2.14, 6.72, 84.52], [0.49, -1.71, -32.39]], + [[-173.66, -46.27, -3.03], [-63.30, -25.43, 1.60], [13.32, -33.05, 1.69], [-14.90, 28.31, -1.76], [0.19, 2.48, 46.94], [0.94, -1.85, -35.99]], + [[-238.18, -68.39, -0.67], [-65.62, -18.77, 3.11], [3.23, -10.86, 2.68], [-5.27, 16.06, 3.74], [-0.27, 3.02, 12.55], [-1.86, 2.93, -32.79]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -234,35 +234,34 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Central path': copy.deepcopy(centralPathOption), 'Number of elements along dome': 8, 'Number of elements along neck': 4, - 'Number of elements around bladder': 8, + 'Number of elements around': 8, 'Number of elements through wall': 1, 'Wall thickness': 1.5, 'Ureter position around': 0.67, 'Use linear through wall': True, 'Refine': False, - 'Refine number of elements along bladder': 4, - 'Refine number of elements around bladder': 4, + 'Refine number of elements along': 4, + 'Refine Number of elements around': 4, 'Refine number of elements through wall': 1 } if 'Human 1' in parameterSetName: - options['Number of elements along dome'] = 8 - options['Number of elements around bladder'] = 12 - options['Wall thickness'] = 2.0 + options['Number of elements along dome'] = 10 + options['Number of elements along neck'] = 6 + options['Number of elements around'] = 12 + options['Wall thickness'] = 3.0 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) if 'Mouse 1' in parameterSetName: - options['Number of elements along dome'] = 10 - # options['Number of elements around bladder'] = 8 + options['Number of elements along neck'] = 6 options['Wall thickness'] = 0.5 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) if 'Pig 1' in parameterSetName: options['Number of elements along dome'] = 10 - options['Number of elements around bladder'] = 16 - options['Wall thickness'] = 3.0 + options['Number of elements along neck'] = 5 + options['Number of elements around'] = 12 + options['Wall thickness'] = 2.5 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) if 'Rat 1' in parameterSetName: - options['Number of elements along dome'] = 12 - options['Number of elements around bladder'] = 12 - options['Wall thickness'] = 0.2 + options['Wall thickness'] = 0.3 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) return options @@ -272,14 +271,14 @@ def getOrderedOptionNames(): 'Central path', 'Number of elements along dome', 'Number of elements along neck', - 'Number of elements around bladder', + 'Number of elements around', 'Number of elements through wall', 'Wall thickness', 'Ureter position around', 'Use linear through wall', 'Refine', - 'Refine number of elements around bladder', - 'Refine number of elements along bladder', + 'Refine Number of elements around', + 'Refine number of elements along', 'Refine number of elements through wall'] return optionNames @@ -319,21 +318,23 @@ 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 elements around bladder', + 'Number of elements along dome', + 'Number of elements along neck', + 'Number of elements around', 'Number of elements through wall', - 'Refine number of elements along bladder', - 'Refine number of elements around bladder', + 'Refine number of elements along', + 'Refine Number of elements around', 'Refine number of elements through wall']: if options[key] < 1: options[key] = 1 - if options['Number of elements around bladder'] % 2 != 0: - if options['Number of elements around bladder'] % 4 > 1: - options['Number of elements around bladder'] += 1 + if options['Number of elements around'] % 2 != 0: + if options['Number of elements around'] % 4 > 1: + options['Number of elements around'] += 1 else: - options['Number of elements around bladder'] -= 1 + options['Number of elements around'] -= 1 else: - if options['Number of elements around bladder'] % 4 != 0: - options['Number of elements around bladder'] += 2 + if options['Number of elements around'] % 4 != 0: + options['Number of elements around'] += 2 if options['Ureter position around'] < 0.5: options['Ureter position around'] = 0.5 # ureters are on the dorsal part of the bladder @@ -348,14 +349,13 @@ def generateBaseMesh(cls, region, options): centralPath = options['Central path'] elementsCountAlongDome = options['Number of elements along dome'] elementsCountAlongNeck = options['Number of elements along neck'] - elementsCountAroundBladder = options['Number of elements around bladder'] + elementsCountAround = options['Number of elements around'] elementsCountThroughWall = options['Number of elements through wall'] wallThickness = options['Wall thickness'] useCrossDerivatives = False useCubicHermiteThroughWall = not (options['Use linear through wall']) elementsCountAlongBladder = elementsCountAlongDome + elementsCountAlongNeck - ureterPositionAroundFactor = options['Ureter position around'] / 2 fm = region.getFieldmodule() fm.beginChange() @@ -365,50 +365,6 @@ def generateBaseMesh(cls, region, options): firstNodeIdentifier = 1 firstElementIdentifier = 1 - # # Central path - # tmpRegion = region.createRegion() - # centralPath.generate(tmpRegion) - # arcLengthOfGroupsAlong = [] - # bladderTermsAlong = ['dome of the bladder', 'neck of urinary bladder'] - # for i in range(len(bladderTermsAlong)): - # # 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=bladderTermsAlong[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_dome = cxGroup - # cd1_dome = cd1Group - # cd2_dome = cd2Group - # cd3_dome = cd3Group - # cd12_dome = cd12Group - # cd13_dome = cd13Group - # else: - # cx_neck = cxGroup - # cd1_neck = cd1Group - # cd2_neck = cd2Group - # cd3_neck = cd3Group - # cd12_neck = cd12Group - # cd13_neck = cd13Group - # del tmpRegion - # - # domeLength = arcLengthOfGroupsAlong[0] - # neckLength = arcLengthOfGroupsAlong[1] - # domeSegmentLength = arcLengthOfGroupsAlong[0] / elementsCountAlongDome - # neckSegmentLength = arcLengthOfGroupsAlong[1] / elementsCountAlongNeck - # # total = arcLengthOfGroupsAlong[0] + arcLengthOfGroupsAlong[1] - # bladderCentralPathLength = sum(arcLengthOfGroupsAlong) - # # print('total', total) - # print('bladderCentralPathLength', bladderCentralPathLength) - # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) @@ -422,7 +378,6 @@ def generateBaseMesh(cls, region, options): Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D2_DS1DS3], groupName='neck of urinary bladder') - # Find arcLength # Dome domeLength = 0.0 @@ -453,202 +408,31 @@ def generateBaseMesh(cls, region, options): sd2_neck, sd12_neck = interp.interpolateSampleCubicHermite(cd2_neck, cd12_neck, se_neck, sxi_neck, ssf_neck) sd3_neck, sd13_neck = interp.interpolateSampleCubicHermite(cd3_neck, cd13_neck, se_neck, sxi_neck, ssf_neck) - # Find Apex nodes d2 - d2Apex = [] - d2 = sd2_dome[0] - for n1 in range(elementsCountAroundBladder): - rotAngle = n1 * 2.0 * math.pi / elementsCountAroundBladder - rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sd2_dome[0]), vector.normalise(sd3_dome[0]))) - rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) - d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - d2Apex.append(d2Rot) - - # Create ellipses along dome around the central path - xEllipses_dome = [] - d1Ellipses_dome = [] - for n in range(1, len(sx_dome)): - px, pd1 = createEllipsePoints(sx_dome[n], 2 * math.pi, sd2_dome[n], sd3_dome[n], elementsCountAroundBladder, - startRadians=0.0) - xEllipses_dome.append(px) - d1Ellipses_dome.append(pd1) - - # Find d2 - d2Raw = [] - for n1 in range(elementsCountAroundBladder): - xAlong = [] - d2Along = [] - for n2 in range(len(xEllipses_dome) - 1): - v1 = xEllipses_dome[n2][n1] - v2 = xEllipses_dome[n2 + 1][n1] - d2 = findDerivativeBetweenPoints(v1, v2) - xAlong.append(v1) - d2Along.append(d2) - xAlong.append(xEllipses_dome[-1][n1]) - d2Along.append(d2) - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) - d2Raw.append(d2Smoothed) - - # Rearrange d2 - d2Ellipses_dome = [] - for n2 in range(len(xEllipses_dome)): - d2Around = [] - for n1 in range(elementsCountAroundBladder): - d2 = d2Raw[n1][n2] - d2Around.append(d2) - d2Ellipses_dome.append(d2Around) - - # Merge apex and dome - xDome = [[sx_dome[0]] * elementsCountAroundBladder] + xEllipses_dome - d2Dome = [d2Apex] + d2Ellipses_dome + # Find nodes of bladder dome and neck + sx_dome_group = [sx_dome, sd1_dome, sd2_dome, sd12_dome, sd3_dome, sd13_dome] + sx_neck_group = [sx_neck, sd1_neck, sd2_neck, sd12_neck, sd3_neck, sd13_neck] - # Spread out elements along dome of the bladder - xRaw = [] - d2Raw = [] - for n1 in range(elementsCountAroundBladder): - xAlong = [] - d2Along = [] - for n2 in range(len(xDome)): - xAlong.append(xDome[n2][n1]) - d2Along.append(d2Dome[n2][n1]) - xSampledAlongDome, d2SampledAlongDome = interp.sampleCubicHermiteCurves(xAlong, d2Along, - elementsCountAlongDome, - arcLengthDerivatives=True)[0:2] - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongDome, d2SampledAlongDome) - xRaw.append(xSampledAlongDome) - d2Raw.append(d2Smoothed) + xDome, d1Dome, d2Dome = findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountAlongDome) - # Rearrange x and d2 - xSampledAll = [] - d1SampledAll = [] - d2SampledAll = [] - for n2 in range(elementsCountAlongDome + 1): - xAround = [] - d1Around = [] - d2Around = [] - for n1 in range(elementsCountAroundBladder): - x = xRaw[n1][n2] - d2 = d2Raw[n1][n2] - xAround.append(x) - d2Around.append(d2) - # Calculate d1 - if n2 > 0: - v1 = xRaw[n1][n2] - v2 = xRaw[n1 + 1 if n1 < elementsCountAroundBladder - 2 else 0][n2] - d1 = findDerivativeBetweenPoints(v1, v2) - d1Around.append(d1) - else: - d1Around.append(d2Raw[n2][0]) - if n2 > 0: - d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - else: - d1Smoothed = d1Around - xSampledAll.append(xAround) - d1SampledAll.append(d1Smoothed) - # d2SampledAll.append(d2Around) - if n2 == elementsCountAlongDome: - pass - else: - d2SampledAll.append(d2Around) + xNeck, d1Neck, d2Neck, px_transit = findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, neckSegmentLength, elementsCountAround, \ + elementsCountAlongNeck, xDome, d2Dome) - # Transition - transitLength = (domeSegmentLength + neckSegmentLength) / 2 - if transitLength < neckSegmentLength: - e = 1 - xi = transitLength / neckSegmentLength - else: - e = int(transitLength / neckSegmentLength) + 1 - xi = transitLength / (e * neckSegmentLength) - xTransition = interp.interpolateCubicHermite(sx_dome[-1], sd1_dome[-1], sx_neck[e], sd1_neck[e], xi) - # d1Transition = interp.interpolateCubicHermiteDerivative(sx_dome[-1], sd1_dome[-1], sx_neck[e], sd1_neck[e], xi) - d2Transition = interp.interpolateCubicHermite(sd2_dome[-1], sd12_dome[-1], sd2_neck[e], sd12_neck[e], xi) - d3Transition = interp.interpolateCubicHermite(sd3_dome[-1], sd13_dome[-1], sd3_neck[e], sd13_neck[e], xi) - px_transit, pd1_transit = createEllipsePoints(xTransition, 2 * math.pi, d2Transition, d3Transition, elementsCountAroundBladder, - startRadians=0.0) + # Replace d2 for the last layer of the dome based on the transition nodes d2Around = [] - for n1 in range(elementsCountAroundBladder): - v1 = xSampledAll[-1][n1] + for n1 in range(elementsCountAround): + v1 = xDome[-1][n1] v2 = px_transit[n1] d2 = findDerivativeBetweenPoints(v1, v2) # xAlong.append(v1) d2Around.append(d2) - d2SampledAll += [d2Around] - - # Create ellipses along neck around the central path - sx_neck_new = [xTransition] + sx_neck[e:] - sd2_neck_new = [d2Transition] + sd2_neck[e:] - sd3_neck_new = [d3Transition] + sd3_neck[e:] - xEllipses_neck = [] - d1Ellipses_neck = [] - for n in range(0, len(sx_neck_new)): - px, pd1 = createEllipsePoints(sx_neck_new[n], 2 * math.pi, sd2_neck_new[n], sd3_neck_new[n], elementsCountAroundBladder, - startRadians=0.0) - xEllipses_neck.append(px) - d1Ellipses_neck.append(pd1) - - # Find d2 - d2Raw = [] - for n1 in range(elementsCountAroundBladder): - xAlong = [] - d2Along = [] - for n2 in range(len(xEllipses_neck) - 1): - v1 = xEllipses_neck[n2][n1] - v2 = xEllipses_neck[n2 + 1][n1] - d2 = findDerivativeBetweenPoints(v1, v2) - xAlong.append(v1) - d2Along.append(d2) - xAlong.append(xEllipses_neck[-1][n1]) - d2Along.append(d2) - # d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) - d2Raw.append(d2Along) + d2Dome = d2Dome[:-1] + [d2Around] - # Rearrange d2 - d2Ellipses_neck_new = [] - for n2 in range(len(xEllipses_neck)): - d2Around = [] - for n1 in range(elementsCountAroundBladder): - d2 = d2Raw[n1][n2] - d2Around.append(d2) - d2Ellipses_neck_new.append(d2Around) - - # Spread out elements along neck of the bladder - xRawNeck = [] - d2RawNeck = [] - for n1 in range(elementsCountAroundBladder): - xAlong = [] - d2Along = [] - for n2 in range(len(xEllipses_neck)): - xAlong.append(xEllipses_neck[n2][n1]) - d2Along.append(d2Ellipses_neck_new[n2][n1]) - xSampledAlongNeck, d2SampledAlongNeck = interp.sampleCubicHermiteCurves(xAlong, d2Along, - elementsCountAlongNeck-1, - arcLengthDerivatives=True)[0:2] - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongNeck, d2SampledAlongNeck) - xRawNeck.append(xSampledAlongNeck) - d2RawNeck.append(d2Smoothed) - - # Rearrange x and d2 - for n2 in range(elementsCountAlongNeck): - xAround = [] - d1Around = [] - d2Around = [] - for n1 in range(elementsCountAroundBladder): - x = xRawNeck[n1][n2] - d2 = d2RawNeck[n1][n2] - xAround.append(x) - d2Around.append(d2) - # Calculate d1 - v1 = xRawNeck[n1][n2] - v2 = xRawNeck[n1 + 1 if n1 < elementsCountAroundBladder - 1 else 0][n2] - d1 = findDerivativeBetweenPoints(v1, v2) - d1Around.append(d1) - d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - xSampledAll.append(xAround) - d1SampledAll.append(d1Smoothed) - d2SampledAll.append(d2Around) + xSampledAll = xDome + xNeck + d1SampledAll = d1Dome + d1Neck - # Smoothing d2 from apex to down the neck + # Smoothing d2 from apex to down the neck d2Raw = [] - for n1 in range(elementsCountAroundBladder): + for n1 in range(elementsCountAround): xAlong = [] d2Along = [] for n2 in range(elementsCountAlongBladder): @@ -661,21 +445,22 @@ def generateBaseMesh(cls, region, options): d2Along.append(xSampledAll[-1][n1]) d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) d2Raw.append(d2Smoothed) + # Rearrange d2 - d2Total = [] + d2SampledAll = [] for n2 in range(elementsCountAlongBladder + 1): d2Around = [] - for n1 in range(elementsCountAroundBladder): + for n1 in range(elementsCountAround): d2 = d2Raw[n1][n2] d2Around.append(d2) - d2Total.append(d2Around) + d2SampledAll.append(d2Around) d3UnitOuter = [] for n2 in range(1, elementsCountAlongBladder + 1): d3Around = [] - for n1 in range(elementsCountAroundBladder): + for n1 in range(elementsCountAround): d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1SampledAll[n2][n1]), vector.normalise(d2Total[n2][n1])))) + vector.crossproduct3(vector.normalise(d1SampledAll[n2][n1]), vector.normalise(d2SampledAll[n2][n1])))) d3UnitOuter.append(d3Around) # Inner nodes @@ -684,10 +469,10 @@ def generateBaseMesh(cls, region, options): d2Inner = [] d3Inner = [] for n2 in range(elementsCountAlongBladder + 1): - for n1 in range(elementsCountAroundBladder): + for n1 in range(elementsCountAround): x = xSampledAll[n2][n1] d1 = d1SampledAll[n2][n1] - d2 = d2Total[n2][n1] + d2 = d2SampledAll[n2][n1] d3 = d3UnitOuter[n2-1][n1] xInner.append(x) d1Inner.append(d1) @@ -697,12 +482,12 @@ def generateBaseMesh(cls, region, options): # Create outer layers from the inner nodes wallThicknessList = [wallThickness] * (elementsCountAlongBladder + 1) relativeThicknessList = [] - transitElementList = [0] * elementsCountAroundBladder + transitElementList = [0] * elementsCountAround xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xInner, d1Inner, d2Inner, d3Inner, wallThicknessList, relativeThicknessList, - elementsCountAroundBladder, + elementsCountAround, elementsCountAlongBladder, elementsCountThroughWall, transitElementList) @@ -710,8 +495,8 @@ def generateBaseMesh(cls, region, options): # Deal with multiple nodes at the start point for closed proximal end xApexInner = xList[0] # Arclength between apex point and corresponding point on next face - mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], xList[2 * elementsCountAroundBladder], - d2List[2 * elementsCountAroundBladder]) + mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], xList[2 * elementsCountAround], + d2List[2 * elementsCountAround]) d2ApexInner = vector.setMagnitude(sd2_dome[0], mag) d1ApexInner = vector.crossproduct3(sd1_dome[0], d2ApexInner) @@ -720,6 +505,7 @@ def generateBaseMesh(cls, region, options): vector.crossproduct3(vector.normalise(d1ApexInner), vector.normalise(d2ApexInner))) d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] + # Final nodes on the bladder xFinal = [] d1Final = [] d2Final = [] @@ -732,20 +518,12 @@ def generateBaseMesh(cls, region, options): d2Final.append(d2ApexInner) d3Final.append(d3ApexInner) - xFinal += xList[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] - d1Final += d1List[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] - d2Final += d2List[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] - d3Final += d3List[(elementsCountThroughWall + 1) * elementsCountAroundBladder:] + xFinal += xList[(elementsCountThroughWall + 1) * elementsCountAround:] + d1Final += d1List[(elementsCountThroughWall + 1) * elementsCountAround:] + d2Final += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] + d3Final += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] xFlat = d1Flat = d2Flat = [] - # neckDiameter = vector.magnitude(sd2_neck[-1]) - # # xApexInner = xFinal[0] - # # d2ApexInner = d2Final[0] - # # Obtain flat nodes coordinates - # xFlat, d1Flat, d2Flat = obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAroundBladder, elementsCountThroughWall, - # xFinal, d1Final, d2Final, bladderCentralPathLength, neckDiameter, xApexInner, d2ApexInner, - # wallThickness) - xOrgan = d1Organ = d2Organ = [] # Create annotation groups for bladder @@ -763,7 +541,7 @@ def generateBaseMesh(cls, region, options): for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) - elementsCountAroundGroups = [elementsCountAroundBladder // 4, elementsCountAroundBladder // 2, elementsCountAroundBladder // 4] + elementsCountAroundGroups = [elementsCountAround // 4, elementsCountAround // 2, elementsCountAround // 4] annotationGroupAround = [[bladderGroup, bladderVentralGroup], [bladderGroup, bladderDorsalGroup], [bladderGroup, bladderVentralGroup]] annotationGroupsAround = [] for i in range(len(elementsCountAroundGroups)): @@ -778,27 +556,27 @@ def generateBaseMesh(cls, region, options): # Create nodes and elements nodeIdentifier, elementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xFinal, d1Final, d2Final, d3Final, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, - elementsCountAroundBladder, elementsCountAlongBladder, elementsCountThroughWall, + elementsCountAround, elementsCountAlongBladder, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=True) - # Define trackSurface to put the ureters on + # Define trackSurface to put the ureter markers on xTrackSurface = [] d1TrackSurface = [] d2TrackSurface = [] for n2 in range(elementsCountAlongBladder + 1): - for n1 in range(elementsCountAroundBladder): - idx = n2 * elementsCountAroundBladder + elementsCountAroundBladder + n1 + for n1 in range(elementsCountAround): + idx = n2 * elementsCountAround + elementsCountAround + n1 xTrackSurface.append(xList[idx]) d1TrackSurface.append(d1List[idx]) d2TrackSurface.append(d2List[idx]) - trackSurfaceBladder = TrackSurface(elementsCountAroundBladder, elementsCountAlongBladder, + trackSurfaceBladder = TrackSurface(elementsCountAround, elementsCountAlongBladder, xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) # Ureter position neckStartPositionAlongFactor = domeLength / bladderCentralPathLength - # neckStartPositionAlongFactor = arcLengthOfGroupsAlong[0] / bladderCentralPathLength + ureterPositionAroundFactor = options['Ureter position around'] / 2 ureter1Position = trackSurfaceBladder.createPositionProportion(ureterPositionAroundFactor, neckStartPositionAlongFactor) ureterElementPositionAround = ureter1Position.e1 @@ -822,10 +600,10 @@ def generateBaseMesh(cls, region, options): xi1 = [0.0, 0.0, 0.0] markerList = [] markerList.append({"group": apexGroup, "elementId": idx1, "xi": xi1}) - idx2 = elementsCountAlongDome * elementsCountAroundBladder * elementsCountThroughWall + ureterElementPositionAround + 1 + idx2 = elementsCountAlongDome * elementsCountAround * elementsCountThroughWall + ureterElementPositionAround + 1 xi2 = [ureter1Position.xi1, 0.0, 0.0] markerList.append({"group": leftUreterGroup, "elementId": idx2, "xi": xi2}) - idx3 = elementsCountAlongDome * elementsCountAroundBladder * elementsCountThroughWall + elementsCountAroundBladder - ureterElementPositionAround + idx3 = elementsCountAlongDome * elementsCountAround * elementsCountThroughWall + elementsCountAround - ureterElementPositionAround xi3 = [1 - ureter1Position.xi1, 0.0, 0.0] markerList.append({"group": rightUreterGroup, "elementId": idx3, "xi": xi3}) @@ -850,8 +628,8 @@ def refineMesh(cls, meshrefinement, options): :param meshrefinement: MeshRefinement, which knows source and target region. :param options: Dict containing options. See getDefaultOptions(). """ - refineElementsCountAround = options['Refine number of elements along bladder'] - refineElementsCountAlong = options['Refine number of elements around bladder'] + refineElementsCountAround = options['Refine number of elements along'] + refineElementsCountAlong = options['Refine Number of elements around'] refineElementsCountThroughWall = options['Refine number of elements through wall'] meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, @@ -1006,182 +784,203 @@ def findDerivativeBetweenPoints(v1, v2): return d -def obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, elementsCountThroughWall, - xFinal, d1Final, d2Final, bladderLength, neckDiameter1, xApexInner, d2ApexInner, - bladderWallThickness): - """ - Calculates flat coordinates for the bladder when it is opened into a flat preparation. - :param elementsCountAlongBladder: Number of elements along bladder. - :param elementsCountAround: Number of elements around bladder. - :param elementsCountThroughWall: Number of elements through wall. - :param xFinal, d1Final, d2Final: Coordinates and derivatives of all nodes of coordinates field. - :param bladderLength: Bladder length along the central path. - :param neckDiameter1: Major diameter of the bladder neck. - :param xApexInner, d2ApexInner: Coordinates and d2 of the apex located on the lumen of the bladder. - :param bladderWallThickness: Thickness of wall. - :return: Coordinates and derivatives of flat coordinates field. - """ - # Calculate ellipses circumference along the bladder inner layer(lumen) - circumferenceList = [] - minorNodeAlong_x = [] - minorNodeAlong_d2 = [] - for n1 in range(1, elementsCountAlongBladder + 1): - xNodesOnEllipse = [] - d1NodesOnEllipse = [] - idMinor = (n1 - 1) * elementsCountAround * (elementsCountThroughWall + 1) + elementsCountThroughWall + 1 - minorNodeAlong_x.append(xFinal[idMinor]) - minorNodeAlong_d2.append(d2Final[idMinor]) - for n2 in range(elementsCountAround): - id = n2 + idMinor - x = xFinal[id] - d1 = d1Final[id] - xNodesOnEllipse.append(x) - d1NodesOnEllipse.append(d1) - xNodesOnEllipse.append(xFinal[idMinor]) - d1NodesOnEllipse.append(d1Final[idMinor]) - circumference = interp.getCubicHermiteCurvesLength(xNodesOnEllipse, d1NodesOnEllipse) - circumferenceList.append(circumference) - maxCircumference = max(circumferenceList) - - # Find the angle at the bottom of the bladder neck - v1 = [0.0, 0.0, bladderLength] - v2 = [0.5 * neckDiameter1, 0.0, bladderLength] - alpha = vector.angleBetweenVectors(v1, v2) - - # Find apex to urethra arcLength in minor radius - minorNodeAlong_x.insert(0, xApexInner) - minorNodeAlong_d2.insert(0, d2ApexInner) - minorarcLength = interp.getCubicHermiteCurvesLength(minorNodeAlong_x, minorNodeAlong_d2) - - # calculate nodes coordinates based on Hammer projection formulation - xfnList = [] - angleAlongUnit = (math.pi - alpha) / elementsCountAlongBladder - angleAroundUnit = 2 * math.pi / elementsCountAround - for n2 in range(1, elementsCountAlongBladder + 1): - for n1 in range(elementsCountAround + 1): - phi = -math.pi / 2 - alpha + n2 * angleAlongUnit - if n1 < elementsCountAround // 2 + 1: - theta = n1 * angleAroundUnit - else: - theta = math.pi - n1 * angleAroundUnit - t = math.sqrt(1 + math.cos(phi) * math.cos(theta / 2)) - xScale = maxCircumference / 2 - yScale = bladderLength / 2 - x = [xScale * math.cos(phi) * math.sin(theta / 2) / t, - yScale * (math.sin(phi) / t + 1), - 0.0] - xfnList.append(x) - - # Rearrange the nodes - xfnListRearranged = [] - for n2 in range(elementsCountAlongBladder): - for n1 in range(elementsCountAround + 1): - if n1 < elementsCountAround // 2 + 1: - nodeIndex = n2 * (elementsCountAround + 1) + elementsCountAround // 2 - n1 - else: - nodeIndex = n2 * (elementsCountAround + 1) + n1 - xfnListRearranged.append(xfnList[nodeIndex]) - - # Define d1 for flat nodes - d1fnListRearranged = [] - for n2 in range(elementsCountAlongBladder): - for n1 in range(elementsCountAround + 1): - if n1 == elementsCountAround: - id = (elementsCountAround + 1) * n2 - d1 = [d1fnListRearranged[id][0], -d1fnListRearranged[id][1], d1fnListRearranged[id][2]] - else: - v1 = xfnListRearranged[(elementsCountAround + 1) * n2 + n1] - v2 = xfnListRearranged[(elementsCountAround + 1) * n2 + n1 + 1] - d1 = [v2[c] - v1[c] for c in range(3)] - d1fnListRearranged.append(d1) - # Smoothing the derivatives - smoothed_d1 = [] - for n2 in range(elementsCountAlongBladder): - xLineSmoothing = [] - d1LineSmoothing = [] - for n1 in range(elementsCountAround + 1): - xLineSmoothing.append(xfnListRearranged[n2 * (elementsCountAround + 1) + n1]) - d1LineSmoothing.append(d1fnListRearranged[n2 * (elementsCountAround + 1) + n1]) - smd1 = interp.smoothCubicHermiteDerivativesLine(xLineSmoothing, d1LineSmoothing, fixAllDirections=False, - fixStartDerivative=True, fixEndDerivative=True, - fixStartDirection=False, fixEndDirection=False) - smoothed_d1 += smd1 - - # Define d2 for flat nodes - # Create lines from top go down the bladder - xNodesToDown = [] - d2NodesToDown = [] - for n2 in range(elementsCountAround + 1): - x = [xfnListRearranged[n1 * (elementsCountAround + 1) + n2] for n1 in range(0, elementsCountAlongBladder)] - xNodesToDown += x - for n1 in range(1, elementsCountAlongBladder + 1): - if n1 == elementsCountAlongBladder: - d2 = [0.0, minorarcLength / elementsCountAlongBladder, 0.0] +def findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountAlongDome): + + # Find Apex nodes d2 + d2Apex = [] + d2 = sx_dome_group[2][0] + for n1 in range(elementsCountAround): + rotAngle = n1 * 2.0 * math.pi / elementsCountAround + rotAxis = vector.normalise(vector.crossproduct3(vector.normalise(sx_dome_group[2][0]), vector.normalise(sx_dome_group[4][0]))) + rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, rotAngle) + d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] + d2Apex.append(d2Rot) + + # Create ellipses along dome around the central path + xEllipses_dome = [] + d1Ellipses_dome = [] + for n in range(1, len(sx_dome_group[0])): + px, pd1 = createEllipsePoints(sx_dome_group[0][n], 2 * math.pi, sx_dome_group[2][n], sx_dome_group[4][n], elementsCountAround, + startRadians=0.0) + xEllipses_dome.append(px) + d1Ellipses_dome.append(pd1) + + # Find d2 + d2Raw = [] + for n1 in range(elementsCountAround): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses_dome) - 1): + v1 = xEllipses_dome[n2][n1] + v2 = xEllipses_dome[n2 + 1][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v1) + d2Along.append(d2) + xAlong.append(xEllipses_dome[-1][n1]) + d2Along.append(d2) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Raw.append(d2Smoothed) + + # Rearrange d2 + d2Ellipses_dome = [] + for n2 in range(len(xEllipses_dome)): + d2Around = [] + for n1 in range(elementsCountAround): + d2 = d2Raw[n1][n2] + d2Around.append(d2) + d2Ellipses_dome.append(d2Around) + + # Merge apex and dome + domeNodes_x = [[sx_dome_group[0][0]] * elementsCountAround] + xEllipses_dome + domeNodes_d2 = [d2Apex] + d2Ellipses_dome + + # Spread out elements along dome of the bladder + xRaw = [] + d2Raw = [] + for n1 in range(elementsCountAround): + xAlong = [] + d2Along = [] + for n2 in range(len(domeNodes_x)): + xAlong.append(domeNodes_x[n2][n1]) + d2Along.append(domeNodes_d2[n2][n1]) + xSampledAlongDome, d2SampledAlongDome = interp.sampleCubicHermiteCurves(xAlong, d2Along, + elementsCountAlongDome, + arcLengthDerivatives=True)[0:2] + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongDome, d2SampledAlongDome) + xRaw.append(xSampledAlongDome) + d2Raw.append(d2Smoothed) + + # Rearrange x and d2 + xSampledDome = [] + d1SampledDome = [] + d2SampledDome = [] + for n2 in range(elementsCountAlongDome + 1): + xAround = [] + d1Around = [] + d2Around = [] + for n1 in range(elementsCountAround): + x = xRaw[n1][n2] + d2 = d2Raw[n1][n2] + xAround.append(x) + d2Around.append(d2) + # Calculate d1 + if n2 > 0: + v1 = xRaw[n1][n2] + v2 = xRaw[n1 + 1 if n1 < elementsCountAround - 2 else 0][n2] + d1 = findDerivativeBetweenPoints(v1, v2) + d1Around.append(d1) else: - v1 = xNodesToDown[elementsCountAlongBladder * n2 + n1 - 1] - v2 = xNodesToDown[elementsCountAlongBladder * n2 + n1] - d2 = [v2[c] - v1[c] for c in range(3)] - d2NodesToDown.append(d2) - # Smoothing the derivatives - smoothed_d2 = [] - for n1 in range(elementsCountAround + 1): - lineSmoothingNodes = [] - lineSmoothingNodes_d2 = [] - for n2 in range(elementsCountAlongBladder): - lineSmoothingNodes.append(xNodesToDown[n1 * elementsCountAlongBladder + n2]) - lineSmoothingNodes_d2.append(d2NodesToDown[n1 * elementsCountAlongBladder + n2]) - smd2 = interp.smoothCubicHermiteDerivativesLine(lineSmoothingNodes, lineSmoothingNodes_d2, fixAllDirections=False, - fixStartDerivative=False, fixEndDerivative=True, - fixStartDirection=False, fixEndDirection=False) - smoothed_d2 += smd2 - # Re-arrange the derivatives order - d2fnListRearranged = [] - for n2 in range(elementsCountAlongBladder): - for n1 in range(elementsCountAround + 1): - rd2 = smoothed_d2[n1 * elementsCountAlongBladder + n2] - d2fnListRearranged.append(rd2) - - # Create the nodes through the wall - xflatList = [] - d1flatList = [] - d2flatList = [] - for n2 in range(elementsCountThroughWall + 1): - for n1 in range(len(xfnListRearranged)): - x = [xfnListRearranged[n1][0], xfnListRearranged[n1][1], n2 * bladderWallThickness / elementsCountThroughWall] - d1 = smoothed_d1[n1] - d2 = d2fnListRearranged[n1] - xflatList.append(x) - d1flatList.append(d1) - d2flatList.append(d2) - - # Apex derivatives - v1 = xApexInner - v1 = [0.0, 0.0, 0.0] - v2 = xfnListRearranged[0] - v3 = xfnListRearranged[elementsCountAround // 2] - v21 = [v2[c] - v1[c] for c in range(3)] - v31 = [v3[c] - v1[c] for c in range(3)] - d1Mag = vector.magnitude(v21) - d2Mag = vector.magnitude(v31) - - # Add apex nodes to the list - xFlat = [] - d1Flat = [] - d2Flat = [] - for n1 in range(elementsCountThroughWall + 1): - # xApex = [xApexInner[0], xApexInner[1], xApexInner[2] + n1 * bladderWallThickness / elementsCountThroughWall] - xApex = [0.0, 0.0, 0.0 + n1 * bladderWallThickness / elementsCountThroughWall] - xFlat.append(xApex) - d1Flat.append([-d1Mag, 0.0, 0.0]) - d2Flat.append([0.0, d2Mag, 0.0]) - - # Re-arrange the nodes - for n3 in range(1, elementsCountAlongBladder + 1): - for n2 in range(elementsCountThroughWall + 1): - for n1 in range(elementsCountAround + 1): - i = (n3 - 1) * (elementsCountAround + 1) + n2 * (elementsCountAround + 1) * elementsCountAlongBladder + n1 - xFlat.append(xflatList[i]) - d1Flat.append(d1flatList[i]) - d2Flat.append(d2flatList[i]) - - return xFlat, d1Flat, d2Flat \ No newline at end of file + d1Around.append(d2Raw[n2][0]) + if n2 > 0: + d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) + else: + d1Smoothed = d1Around + xSampledDome.append(xAround) + d1SampledDome.append(d1Smoothed) + d2SampledDome.append(d2Around) + + return xSampledDome, d1SampledDome, d2SampledDome + +def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, neckSegmentLength, elementsCountAround, elementsCountAlongNeck, xDome, d2Dome): + + # Transition + transitLength = (domeSegmentLength + neckSegmentLength) / 2 + if transitLength < neckSegmentLength: + e = 1 + xi = transitLength / neckSegmentLength + else: + e = int(transitLength / neckSegmentLength) + 1 + xi = transitLength / (e * neckSegmentLength) + xTransition = interp.interpolateCubicHermite(sx_dome_group[0][-1], sx_dome_group[1][-1], sx_neck_group[0][e], sx_neck_group[1][e], xi) + # d1Transition = interp.interpolateCubicHermiteDerivative(sx_dome_group[0][-1], sx_dome_group[1][-1], sx_neck_group[0][e], sx_neck_group[1][e], xi) + d2Transition = interp.interpolateCubicHermite(sx_dome_group[2][-1], sx_dome_group[3][-1], sx_neck_group[2][e], sx_neck_group[3][e], xi) + d3Transition = interp.interpolateCubicHermite(sx_dome_group[4][-1], sx_dome_group[5][-1], sx_neck_group[4][e], sx_neck_group[5][e], xi) + px_transit, pd1_transit = createEllipsePoints(xTransition, 2 * math.pi, d2Transition, d3Transition, elementsCountAround, + startRadians=0.0) + + # d2Around = [] + # for n1 in range(elementsCountAround): + # v1 = xDome[-1][n1] + # v2 = px_transit[n1] + # d2 = findDerivativeBetweenPoints(v1, v2) + # # xAlong.append(v1) + # d2Around.append(d2) + # d2Dome = d2Dome[:-1] + [d2Around] + + # Create ellipses along neck around the central path + sx_neck_new = [xTransition] + sx_neck_group[0][e:] + sd2_neck_new = [d2Transition] + sx_neck_group[2][e:] + sd3_neck_new = [d3Transition] + sx_neck_group[4][e:] + xEllipses_neck = [] + d1Ellipses_neck = [] + for n in range(0, len(sx_neck_new)): + px, pd1 = createEllipsePoints(sx_neck_new[n], 2 * math.pi, sd2_neck_new[n], sd3_neck_new[n], elementsCountAround, + startRadians=0.0) + xEllipses_neck.append(px) + d1Ellipses_neck.append(pd1) + + # Find d2 + d2Raw = [] + for n1 in range(elementsCountAround): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses_neck) - 1): + v1 = xEllipses_neck[n2][n1] + v2 = xEllipses_neck[n2 + 1][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v1) + d2Along.append(d2) + xAlong.append(xEllipses_neck[-1][n1]) + d2Along.append(d2) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Raw.append(d2Along) + + # Rearrange d2 + d2Ellipses_neck_new = [] + for n2 in range(len(xEllipses_neck)): + d2Around = [] + for n1 in range(elementsCountAround): + d2 = d2Raw[n1][n2] + d2Around.append(d2) + d2Ellipses_neck_new.append(d2Around) + + # Spread out elements along neck of the bladder + xRawNeck = [] + d2RawNeck = [] + for n1 in range(elementsCountAround): + xAlong = [] + d2Along = [] + for n2 in range(len(xEllipses_neck)): + xAlong.append(xEllipses_neck[n2][n1]) + d2Along.append(d2Ellipses_neck_new[n2][n1]) + xSampledAlongNeck, d2SampledAlongNeck = interp.sampleCubicHermiteCurves(xAlong, d2Along, + elementsCountAlongNeck - 1, + arcLengthDerivatives=True)[0:2] + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongNeck, d2SampledAlongNeck) + xRawNeck.append(xSampledAlongNeck) + d2RawNeck.append(d2Smoothed) + + # Rearrange x and d2 + xSampledNeck = [] + d1SampledNeck = [] + d2SampledNeck = [] + for n2 in range(elementsCountAlongNeck): + xAround = [] + d1Around = [] + d2Around = [] + for n1 in range(elementsCountAround): + x = xRawNeck[n1][n2] + d2 = d2RawNeck[n1][n2] + xAround.append(x) + d2Around.append(d2) + # Calculate d1 + v1 = xRawNeck[n1][n2] + v2 = xRawNeck[n1 + 1 if n1 < elementsCountAround - 1 else 0][n2] + d1 = findDerivativeBetweenPoints(v1, v2) + d1Around.append(d1) + d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) + xSampledNeck.append(xAround) + d1SampledNeck.append(d1Smoothed) + d2SampledNeck.append(d2Around) + + return xSampledNeck, d1SampledNeck, d2SampledNeck, px_transit From d70d8ff50cdbb1fc52096fa4c63ee5add18807bd Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 8 Aug 2022 12:46:32 +1200 Subject: [PATCH 04/26] Added length for transition between dome and neck. --- .../meshtypes/meshtype_3d_bladder1.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 3a7014b4..5bfe9fda 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -885,7 +885,8 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n # Transition transitLength = (domeSegmentLength + neckSegmentLength) / 2 - if transitLength < neckSegmentLength: + addingLength = transitLength - neckSegmentLength + if transitLength <= neckSegmentLength: e = 1 xi = transitLength / neckSegmentLength else: @@ -913,8 +914,8 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n sd3_neck_new = [d3Transition] + sx_neck_group[4][e:] xEllipses_neck = [] d1Ellipses_neck = [] - for n in range(0, len(sx_neck_new)): - px, pd1 = createEllipsePoints(sx_neck_new[n], 2 * math.pi, sd2_neck_new[n], sd3_neck_new[n], elementsCountAround, + for n in range(0, len(sx_neck_group[0])): + px, pd1 = createEllipsePoints(sx_neck_group[0][n], 2 * math.pi, sx_neck_group[2][n], sx_neck_group[4][n], elementsCountAround, startRadians=0.0) xEllipses_neck.append(px) d1Ellipses_neck.append(pd1) @@ -954,7 +955,7 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n xAlong.append(xEllipses_neck[n2][n1]) d2Along.append(d2Ellipses_neck_new[n2][n1]) xSampledAlongNeck, d2SampledAlongNeck = interp.sampleCubicHermiteCurves(xAlong, d2Along, - elementsCountAlongNeck - 1, + elementsCountAlongNeck, addLengthStart=addingLength, arcLengthDerivatives=True)[0:2] d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongNeck, d2SampledAlongNeck) xRawNeck.append(xSampledAlongNeck) @@ -964,7 +965,7 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n xSampledNeck = [] d1SampledNeck = [] d2SampledNeck = [] - for n2 in range(elementsCountAlongNeck): + for n2 in range(elementsCountAlongNeck + 1): xAround = [] d1Around = [] d2Around = [] @@ -979,8 +980,9 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n d1 = findDerivativeBetweenPoints(v1, v2) d1Around.append(d1) d1Smoothed = interp.smoothCubicHermiteDerivativesLoop(xAround, d1Around) - xSampledNeck.append(xAround) - d1SampledNeck.append(d1Smoothed) - d2SampledNeck.append(d2Around) + if n2 != 0: + xSampledNeck.append(xAround) + d1SampledNeck.append(d1Smoothed) + d2SampledNeck.append(d2Around) return xSampledNeck, d1SampledNeck, d2SampledNeck, px_transit From 4fbd841ee3005eafca66f855b86e3963e2e45b95 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 8 Aug 2022 12:52:55 +1200 Subject: [PATCH 05/26] Fixed d2 for neck nodes --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 5bfe9fda..f29827ec 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -429,6 +429,7 @@ def generateBaseMesh(cls, region, options): xSampledAll = xDome + xNeck d1SampledAll = d1Dome + d1Neck + d2SampledAll = d2Dome + d2Neck # Smoothing d2 from apex to down the neck d2Raw = [] @@ -442,7 +443,7 @@ def generateBaseMesh(cls, region, options): xAlong.append(v1) d2Along.append(d2) xAlong.append(xSampledAll[-1][n1]) - d2Along.append(xSampledAll[-1][n1]) + d2Along.append(d2SampledAll[-1][n1]) d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) d2Raw.append(d2Smoothed) @@ -959,7 +960,7 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n arcLengthDerivatives=True)[0:2] d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xSampledAlongNeck, d2SampledAlongNeck) xRawNeck.append(xSampledAlongNeck) - d2RawNeck.append(d2Smoothed) + d2RawNeck.append(d2SampledAlongNeck) # Rearrange x and d2 xSampledNeck = [] From cb2d5bca1191c4a096c90a76ea70ea995e77437a Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 8 Aug 2022 16:00:34 +1200 Subject: [PATCH 06/26] Removed extra lines. --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index f29827ec..4ded5a04 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -900,19 +900,7 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n px_transit, pd1_transit = createEllipsePoints(xTransition, 2 * math.pi, d2Transition, d3Transition, elementsCountAround, startRadians=0.0) - # d2Around = [] - # for n1 in range(elementsCountAround): - # v1 = xDome[-1][n1] - # v2 = px_transit[n1] - # d2 = findDerivativeBetweenPoints(v1, v2) - # # xAlong.append(v1) - # d2Around.append(d2) - # d2Dome = d2Dome[:-1] + [d2Around] - # Create ellipses along neck around the central path - sx_neck_new = [xTransition] + sx_neck_group[0][e:] - sd2_neck_new = [d2Transition] + sx_neck_group[2][e:] - sd3_neck_new = [d3Transition] + sx_neck_group[4][e:] xEllipses_neck = [] d1Ellipses_neck = [] for n in range(0, len(sx_neck_group[0])): From 75bc5058b3106384f7191c67783c8ed611666216 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Tue, 9 Aug 2022 12:21:34 +1200 Subject: [PATCH 07/26] Minor changes. --- .../meshtypes/meshtype_3d_bladder1.py | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 4ded5a04..b40461b9 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -414,8 +414,8 @@ def generateBaseMesh(cls, region, options): xDome, d1Dome, d2Dome = findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountAlongDome) - xNeck, d1Neck, d2Neck, px_transit = findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, neckSegmentLength, elementsCountAround, \ - elementsCountAlongNeck, xDome, d2Dome) + xNeck, d1Neck, d2Neck, px_transit = findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, \ + neckSegmentLength, elementsCountAround, elementsCountAlongNeck) # Replace d2 for the last layer of the dome based on the transition nodes d2Around = [] @@ -431,30 +431,27 @@ def generateBaseMesh(cls, region, options): d1SampledAll = d1Dome + d1Neck d2SampledAll = d2Dome + d2Neck - # Smoothing d2 from apex to down the neck - d2Raw = [] - for n1 in range(elementsCountAround): - xAlong = [] - d2Along = [] - for n2 in range(elementsCountAlongBladder): - v1 = xSampledAll[n2][n1] - v2 = xSampledAll[n2 + 1][n1] - d2 = findDerivativeBetweenPoints(v1, v2) - xAlong.append(v1) - d2Along.append(d2) - xAlong.append(xSampledAll[-1][n1]) - d2Along.append(d2SampledAll[-1][n1]) - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) - d2Raw.append(d2Smoothed) - - # Rearrange d2 - d2SampledAll = [] - for n2 in range(elementsCountAlongBladder + 1): - d2Around = [] - for n1 in range(elementsCountAround): - d2 = d2Raw[n1][n2] - d2Around.append(d2) - d2SampledAll.append(d2Around) + # # Smoothing d2 from apex to down the neck + # d2Raw = [] + # for n1 in range(elementsCountAround): + # xAlong = [] + # d2Along = [] + # for n2 in range(elementsCountAlongBladder + 1): + # x = xSampledAll[n2][n1] + # d2 = d2SampledAll[n2][n1] + # xAlong.append(x) + # d2Along.append(d2) + # d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along, fixAllDirections=True) + # d2Raw.append(d2Smoothed) + # + # # Rearrange d2 + # d2SampledAll = [] + # for n2 in range(elementsCountAlongBladder + 1): + # d2Around = [] + # for n1 in range(elementsCountAround): + # d2 = d2Raw[n1][n2] + # d2Around.append(d2) + # d2SampledAll.append(d2Around) d3UnitOuter = [] for n2 in range(1, elementsCountAlongBladder + 1): @@ -882,7 +879,7 @@ def findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountA return xSampledDome, d1SampledDome, d2SampledDome -def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, neckSegmentLength, elementsCountAround, elementsCountAlongNeck, xDome, d2Dome): +def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, neckSegmentLength, elementsCountAround, elementsCountAlongNeck): # Transition transitLength = (domeSegmentLength + neckSegmentLength) / 2 @@ -926,13 +923,13 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n d2Raw.append(d2Along) # Rearrange d2 - d2Ellipses_neck_new = [] + d2Ellipses_neck = [] for n2 in range(len(xEllipses_neck)): d2Around = [] for n1 in range(elementsCountAround): d2 = d2Raw[n1][n2] d2Around.append(d2) - d2Ellipses_neck_new.append(d2Around) + d2Ellipses_neck.append(d2Around) # Spread out elements along neck of the bladder xRawNeck = [] @@ -942,7 +939,7 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n d2Along = [] for n2 in range(len(xEllipses_neck)): xAlong.append(xEllipses_neck[n2][n1]) - d2Along.append(d2Ellipses_neck_new[n2][n1]) + d2Along.append(d2Ellipses_neck[n2][n1]) xSampledAlongNeck, d2SampledAlongNeck = interp.sampleCubicHermiteCurves(xAlong, d2Along, elementsCountAlongNeck, addLengthStart=addingLength, arcLengthDerivatives=True)[0:2] From 4fe4049d000e696c0fc3c2e4dd04c27bd0edf2db Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Fri, 26 Aug 2022 11:09:44 +1200 Subject: [PATCH 08/26] Flat coordinates added. --- .../meshtypes/meshtype_3d_bladder1.py | 183 +++++++++++++++++- 1 file changed, 182 insertions(+), 1 deletion(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index b40461b9..08618893 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -521,7 +521,10 @@ def generateBaseMesh(cls, region, options): d2Final += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] d3Final += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] - xFlat = d1Flat = d2Flat = [] + # Obtain flat nodes coordinates + urethraOpeningRadius = vector.magnitude(sd2_neck[-1]) + xFlat, d1Flat, d2Flat = obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, elementsCountThroughWall, + xFinal, d1Final, d2Final, bladderCentralPathLength, urethraOpeningRadius, wallThickness) xOrgan = d1Organ = d2Organ = [] # Create annotation groups for bladder @@ -972,3 +975,181 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n d2SampledNeck.append(d2Around) return xSampledNeck, d1SampledNeck, d2SampledNeck, px_transit + +def obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, elementsCountThroughWall, + xFinal, d1Final, d2Final, bladderLength, urethraOpeningRadius, bladderWallThickness): + """ + Calculates flat coordinates for the bladder when it is opened into a flat preparation. + :param elementsCountAlongBladder: Number of elements along bladder. + :param elementsCountAround: Number of elements around bladder. + :param elementsCountThroughWall: Number of elements through wall. + :param xFinal, d1Final, d2Final: Coordinates and derivatives of all nodes of coordinates field. + :param bladderLength: Bladder length along the central path. + :param urethraOpeningRadius: Major diameter of the bladder opening to urethra. + :param bladderWallThickness: Thickness of wall. + :return: Coordinates and derivatives of flat coordinates field. + """ + # Calculate ellipses circumference along the bladder inner layer(lumen) + circumferenceList = [] + minorNodeAlong_x = [] + minorNodeAlong_d2 = [] + for n1 in range(1, elementsCountAlongBladder + 1): + xNodesOnEllipse = [] + d1NodesOnEllipse = [] + idMinor = (n1 - 1) * elementsCountAround * (elementsCountThroughWall + 1) + elementsCountThroughWall + 1 + minorNodeAlong_x.append(xFinal[idMinor]) + minorNodeAlong_d2.append(d2Final[idMinor]) + for n2 in range(elementsCountAround): + id = n2 + idMinor + x = xFinal[id] + d1 = d1Final[id] + xNodesOnEllipse.append(x) + d1NodesOnEllipse.append(d1) + xNodesOnEllipse.append(xFinal[idMinor]) + d1NodesOnEllipse.append(d1Final[idMinor]) + circumference = interp.getCubicHermiteCurvesLength(xNodesOnEllipse, d1NodesOnEllipse) + circumferenceList.append(circumference) + maxCircumference = max(circumferenceList) + + # Find the angle at the bottom of the bladder neck + v1 = [0.0, 0.0, bladderLength] + v2 = [urethraOpeningRadius, 0.0, bladderLength] + alpha = vector.angleBetweenVectors(v1, v2) + + # Find apex to urethra arcLength in minor radius + xApexInner = xFinal[0] + d2ApexInner = d2Final[0] + minorNodeAlong_x.insert(0, xApexInner) + minorNodeAlong_d2.insert(0, d2ApexInner) + minorarcLength = interp.getCubicHermiteCurvesLength(minorNodeAlong_x, minorNodeAlong_d2) + + # calculate nodes coordinates based on Hammer projection formulation + xfnList = [] + angleAlongUnit = (math.pi - alpha) / elementsCountAlongBladder + angleAroundUnit = 2 * math.pi / elementsCountAround + for n2 in range(1, elementsCountAlongBladder + 1): + for n1 in range(elementsCountAround + 1): + phi = -math.pi / 2 - alpha + n2 * angleAlongUnit + if n1 < elementsCountAround // 2 + 1: + theta = n1 * angleAroundUnit + else: + theta = math.pi - n1 * angleAroundUnit + t = math.sqrt(1 + math.cos(phi) * math.cos(theta / 2)) + xScale = maxCircumference / 2 + yScale = bladderLength / 2 + x = [xScale * math.cos(phi) * math.sin(theta / 2) / t, + yScale * (math.sin(phi) / t + 1), + 0.0] + xfnList.append(x) + + # Rearrange the nodes + xfnListRearranged = [] + for n2 in range(elementsCountAlongBladder): + for n1 in range(elementsCountAround + 1): + if n1 < elementsCountAround // 2 + 1: + nodeIndex = n2 * (elementsCountAround + 1) + elementsCountAround // 2 - n1 + else: + nodeIndex = n2 * (elementsCountAround + 1) + n1 + xfnListRearranged.append(xfnList[nodeIndex]) + + # Define d1 for flat nodes + d1fnListRearranged = [] + for n2 in range(elementsCountAlongBladder): + for n1 in range(elementsCountAround + 1): + if n1 == elementsCountAround: + id = (elementsCountAround + 1) * n2 + d1 = [d1fnListRearranged[id][0], -d1fnListRearranged[id][1], d1fnListRearranged[id][2]] + else: + v1 = xfnListRearranged[(elementsCountAround + 1) * n2 + n1] + v2 = xfnListRearranged[(elementsCountAround + 1) * n2 + n1 + 1] + d1 = [v2[c] - v1[c] for c in range(3)] + d1fnListRearranged.append(d1) + # Smoothing the derivatives + smoothed_d1 = [] + for n2 in range(elementsCountAlongBladder): + xLineSmoothing = [] + d1LineSmoothing = [] + for n1 in range(elementsCountAround + 1): + xLineSmoothing.append(xfnListRearranged[n2 * (elementsCountAround + 1) + n1]) + d1LineSmoothing.append(d1fnListRearranged[n2 * (elementsCountAround + 1) + n1]) + smd1 = interp.smoothCubicHermiteDerivativesLine(xLineSmoothing, d1LineSmoothing, fixAllDirections=False, + fixStartDerivative=True, fixEndDerivative=True, + fixStartDirection=False, fixEndDirection=False) + smoothed_d1 += smd1 + + # Define d2 for flat nodes + # Create lines from top go down the bladder + xNodesToDown = [] + d2NodesToDown = [] + for n2 in range(elementsCountAround + 1): + x = [xfnListRearranged[n1 * (elementsCountAround + 1) + n2] for n1 in range(0, elementsCountAlongBladder)] + xNodesToDown += x + for n1 in range(1, elementsCountAlongBladder + 1): + if n1 == elementsCountAlongBladder: + d2 = [0.0, minorarcLength / elementsCountAlongBladder, 0.0] + else: + v1 = xNodesToDown[elementsCountAlongBladder * n2 + n1 - 1] + v2 = xNodesToDown[elementsCountAlongBladder * n2 + n1] + d2 = [v2[c] - v1[c] for c in range(3)] + d2NodesToDown.append(d2) + # Smoothing the derivatives + smoothed_d2 = [] + for n1 in range(elementsCountAround + 1): + lineSmoothingNodes = [] + lineSmoothingNodes_d2 = [] + for n2 in range(elementsCountAlongBladder): + lineSmoothingNodes.append(xNodesToDown[n1 * elementsCountAlongBladder + n2]) + lineSmoothingNodes_d2.append(d2NodesToDown[n1 * elementsCountAlongBladder + n2]) + smd2 = interp.smoothCubicHermiteDerivativesLine(lineSmoothingNodes, lineSmoothingNodes_d2, fixAllDirections=False, + fixStartDerivative=False, fixEndDerivative=True, + fixStartDirection=False, fixEndDirection=False) + smoothed_d2 += smd2 + # Re-arrange the derivatives order + d2fnListRearranged = [] + for n2 in range(elementsCountAlongBladder): + for n1 in range(elementsCountAround + 1): + rd2 = smoothed_d2[n1 * elementsCountAlongBladder + n2] + d2fnListRearranged.append(rd2) + + # Create the nodes through the wall + xflatList = [] + d1flatList = [] + d2flatList = [] + for n2 in range(elementsCountThroughWall + 1): + for n1 in range(len(xfnListRearranged)): + x = [xfnListRearranged[n1][0], xfnListRearranged[n1][1], n2 * bladderWallThickness / elementsCountThroughWall] + d1 = smoothed_d1[n1] + d2 = d2fnListRearranged[n1] + xflatList.append(x) + d1flatList.append(d1) + d2flatList.append(d2) + + # Apex derivatives + v1 = [0.0, 0.0, 0.0] + v2 = xfnListRearranged[0] + v3 = xfnListRearranged[elementsCountAround // 2] + v21 = [v2[c] - v1[c] for c in range(3)] + v31 = [v3[c] - v1[c] for c in range(3)] + d1Mag = vector.magnitude(v21) + d2Mag = vector.magnitude(v31) + + # Add apex nodes to the list + xFlat = [] + d1Flat = [] + d2Flat = [] + for n1 in range(elementsCountThroughWall + 1): + xApex = [0.0, 0.0, 0.0 + n1 * bladderWallThickness / elementsCountThroughWall] + xFlat.append(xApex) + d1Flat.append([-d1Mag, 0.0, 0.0]) + d2Flat.append([0.0, d2Mag, 0.0]) + + # Re-arrange the nodes + for n3 in range(1, elementsCountAlongBladder + 1): + for n2 in range(elementsCountThroughWall + 1): + for n1 in range(elementsCountAround + 1): + i = (n3 - 1) * (elementsCountAround + 1) + n2 * (elementsCountAround + 1) * elementsCountAlongBladder + n1 + xFlat.append(xflatList[i]) + d1Flat.append(d1flatList[i]) + d2Flat.append(d2flatList[i]) + + return xFlat, d1Flat, d2Flat \ No newline at end of file From 7184a574c8db40e51e519f72f336f93055efa9d2 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 29 Sep 2022 16:46:11 +1300 Subject: [PATCH 09/26] Added apex element template for organ coordinates. --- src/scaffoldmaker/utils/tubemesh.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/scaffoldmaker/utils/tubemesh.py b/src/scaffoldmaker/utils/tubemesh.py index 34be1555..e12bb745 100644 --- a/src/scaffoldmaker/utils/tubemesh.py +++ b/src/scaffoldmaker/utils/tubemesh.py @@ -604,6 +604,9 @@ def createNodesAndElements(region, organElementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) organElementtemplate.defineField(organCoordinates, -1, eftOrgan) + organElementtemplateApex = mesh.createElementtemplate() + organElementtemplateApex.setElementShapeType(Element.SHAPE_TYPE_CUBE) + # Create nodes # Coordinates field for n in range(len(x)): @@ -699,6 +702,13 @@ def createNodesAndElements(region, nodeIdentifiers = [bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAround, bni3 + elementsCountAround] element.setNodesByIdentifier(eftApex, nodeIdentifiers) onOpening = e1 > elementsCountAround - 2 + if xOrgan: + vao = e1 + vbo = (e1 + 1) % elementsCountAround + eftApexOrgan = eftfactory.createEftShellPoleBottom(vao * 100, vbo * 100) + organElementtemplateApex.defineField(organCoordinates, -1, eftApexOrgan) + element.merge(organElementtemplateApex) + element.setNodesByIdentifier(eftApexOrgan, nodeIdentifiers) if xFlat: vaf = e1 + elementsCountAround vbf = vaf + 1 From 4f0bdaf2d570d16ca9c9eb67477284dfede05a1e Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 29 Sep 2022 17:05:16 +1300 Subject: [PATCH 10/26] Added organ coordinates. --- .../meshtypes/meshtype_3d_bladder1.py | 457 +++++++++++------- 1 file changed, 275 insertions(+), 182 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 08618893..07b63d2f 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -110,14 +110,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[54.13, 48.48, 12.30], [-7.00, -7.20, -1.74], [2.81, -2.80, 0.27], [8.05, -8.69, 0.83], [-0.56, -0.25, 3.28], [-1.03, -0.38, 5.83]], - [[45.64, 40.32, 10.27], [-9.99, -9.12, -2.31], [9.36, -10.47, 0.88], [5.04, -6.65, 0.39], [-1.44, -0.57, 8.47], [-0.71, -0.27, 4.55]], - [[34.10, 30.30, 7.68], [-11.90, -9.54, -2.50], [12.45, -15.79, 0.99], [1.92, -4.02, -0.41], [-1.95, -0.77, 12.19], [-0.23, -0.37, 2.65]], - [[21.85, 21.25, 5.27], [-12.81, -9.14, -2.63], [13.20, -18.51, 0.06], [-0.36, -1.77, -0.92], [-1.90, -1.31, 13.78], [0.21, -0.36, 0.38]], - [[8.49, 12.04, 2.41], [-14.44, -8.62, -2.68], [11.66, -19.26, -0.86], [-2.78, 1.37, -0.56], [-1.51, -1.48, 12.86], [0.47, 0.09, -1.85]], - [[-6.98, 4.11, -0.07], [-14.87, -7.05, -2.20], [7.56, -15.62, -1.03], [-4.79, 7.26, -0.08], [-0.95, -1.12, 10.03], [0.68, 0.11, -3.53]], - [[-21.21, -2.10, -2.00], [-16.58, -6.58, -1.81], [2.15, -5.14, -1.02], [-3.60, 6.99, 0.36], [-0.15, -1.23, 5.87], [0.48, 0.38, -3.79]], - [[-40.17, -8.90, -3.57], [-21.33, -7.01, -1.33], [0.89, -2.66, -0.20], [1.07, -2.03, 1.29], [-0.09, -0.22, 2.55], [-0.35, 1.65, -2.85]]]), + [[26.51, 16.41, 4.08], [-9.57, -8.90, -0.96], [4.88, -5.26, 0.16], [1.94, -3.51, 0.19], [-0.47, -0.23, 6.83], [-0.95, -0.39, 8.28]], + [[16.73, 8.32, 2.96], [-9.96, -7.26, -1.27], [6.35, -8.72, -0.01], [1.01, -3.40, -0.53], [-1.09, -0.82, 13.21], [-0.30, -0.78, 4.48]], + [[6.67, 1.90, 1.56], [-10.64, -6.01, -1.39], [6.93, -12.06, -0.88], [-0.36, -1.94, -0.43], [-1.08, -1.78, 15.91], [-0.04, -0.39, 1.12]], + [[-4.52, -3.64, 0.18], [-10.61, -4.65, -1.28], [5.60, -12.53, -0.85], [-1.88, 1.30, -0.10], [-1.18, -1.56, 15.38], [0.03, -0.00, -1.59]], + [[-14.49, -7.47, -1.01], [-8.85, -2.84, -1.10], [3.25, -9.72, -1.06], [-2.15, 3.53, 0.17], [-1.04, -1.75, 12.88], [0.25, 0.35, -3.93]], + [[-22.12, -9.45, -1.99], [-7.82, -1.62, -0.91], [1.25, -5.66, -0.61], [-1.42, 3.63, 0.34], [-0.71, -1.00, 7.89], [0.41, 0.62, -4.91]], + [[-30.11, -10.70, -2.82], [-8.26, -1.29, -0.82], [0.42, -2.47, -0.38], [-0.55, 2.36, 0.22], [-0.22, -0.51, 3.06], [0.30, 0.34, -3.06]], + [[-38.65, -12.04, -3.63], [-8.81, -1.38, -0.79], [0.17, -1.00, -0.16], [0.04, 0.58, 0.21], [-0.12, -0.33, 1.88], [-0.09, 0.02, 0.71]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -178,14 +178,48 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[26.51, 16.41, 4.08], [-9.57, -8.90, -0.96], [4.88, -5.26, 0.16], [1.94, -3.51, 0.19], [-0.47, -0.23, 6.83], [-0.95, -0.39, 8.28]], - [[16.73, 8.32, 2.96], [-9.96, -7.26, -1.27], [6.35, -8.72, -0.01], [1.01, -3.40, -0.53], [-1.09, -0.82, 13.21], [-0.30, -0.78, 4.48]], - [[6.67, 1.90, 1.56], [-10.64, -6.01, -1.39], [6.93, -12.06, -0.88], [-0.36, -1.94, -0.43], [-1.08, -1.78, 15.91], [-0.04, -0.39, 1.12]], - [[-4.52, -3.64, 0.18], [-10.61, -4.65, -1.28], [5.60, -12.53, -0.85], [-1.88, 1.30, -0.10], [-1.18, -1.56, 15.38], [0.03, -0.00, -1.59]], - [[-14.49, -7.47, -1.01], [-8.85, -2.84, -1.10], [3.25, -9.72, -1.06], [-2.15, 3.53, 0.17], [-1.04, -1.75, 12.88], [0.25, 0.35, -3.93]], - [[-22.12, -9.45, -1.99], [-7.82, -1.62, -0.91], [1.25, -5.66, -0.61], [-1.42, 3.63, 0.34], [-0.71, -1.00, 7.89], [0.41, 0.62, -4.91]], - [[-30.11, -10.70, -2.82], [-8.26, -1.29, -0.82], [0.42, -2.47, -0.38], [-0.55, 2.36, 0.22], [-0.22, -0.51, 3.06], [0.30, 0.34, -3.06]], - [[-38.65, -12.04, -3.63], [-8.81, -1.38, -0.79], [0.17, -1.00, -0.16], [0.04, 0.58, 0.21], [-0.12, -0.33, 1.88], [-0.09, 0.02, 0.71]]]), + [[54.13, 48.48, 12.30], [-7.00, -7.20, -1.74], [2.81, -2.80, 0.27], [8.05, -8.69, 0.83], [-0.56, -0.25, 3.28], [-1.03, -0.38, 5.83]], + [[45.64, 40.32, 10.27], [-9.99, -9.12, -2.31], [9.36, -10.47, 0.88], [5.04, -6.65, 0.39], [-1.44, -0.57, 8.47], [-0.71, -0.27, 4.55]], + [[34.10, 30.30, 7.68], [-11.90, -9.54, -2.50], [12.45, -15.79, 0.99], [1.92, -4.02, -0.41], [-1.95, -0.77, 12.19], [-0.23, -0.37, 2.65]], + [[21.85, 21.25, 5.27], [-12.81, -9.14, -2.63], [13.20, -18.51, 0.06], [-0.36, -1.77, -0.92], [-1.90, -1.31, 13.78], [0.21, -0.36, 0.38]], + [[8.49, 12.04, 2.41], [-14.44, -8.62, -2.68], [11.66, -19.26, -0.86], [-2.78, 1.37, -0.56], [-1.51, -1.48, 12.86], [0.47, 0.09, -1.85]], + [[-6.98, 4.11, -0.07], [-14.87, -7.05, -2.20], [7.56, -15.62, -1.03], [-4.79, 7.26, -0.08], [-0.95, -1.12, 10.03], [0.68, 0.11, -3.53]], + [[-21.21, -2.10, -2.00], [-16.58, -6.58, -1.81], [2.15, -5.14, -1.02], [-3.60, 6.99, 0.36], [-0.15, -1.23, 5.87], [0.48, 0.38, -3.79]], + [[-40.17, -8.90, -3.57], [-21.33, -7.01, -1.33], [0.89, -2.66, -0.20], [1.07, -2.03, 1.29], [-0.09, -0.22, 2.55], [-0.35, 1.65, -2.85]]]), + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_bladder_term('dome of the bladder')[0], + 'ontId': get_bladder_term('dome of the bladder')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-7', + 'name': get_bladder_term('neck of urinary bladder')[0], + 'ontId': get_bladder_term('neck of urinary bladder')[1] + }] + }), + 'Material': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 7 + }, + 'meshEdits': exnodeStringFromNodeValues( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + [[2.10, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.12, 0.00], [0.00, -0.21, -0.00], [0.00, 0.00, 0.15], [0.00, -0.01, 0.17]], + [[1.80, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.28, -0.00], [0.00, -0.11, -0.00], [0.00, -0.00, 0.28], [0.00, -0.00, 0.09]], + [[1.50, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.34, -0.01], [0.00, -0.04, 0.00], [0.00, -0.01, 0.33], [0.00, 0.00, 0.03]], + [[1.20, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.35, 0.00], [0.00, 0.02, 0.00], [0.00, 0.00, 0.35], [0.00, 0.00, -0.01]], + [[0.90, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.30, 0.00], [0.00, 0.07, 0.00], [0.00, 0.00, 0.30], [0.00, 0.00, -0.10]], + [[0.60, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.20, 0.00], [0.00, 0.11, 0.00], [0.00, 0.00, 0.16], [0.00, 0.00, -0.11]], + [[0.30, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.08, 0.00], [0.00, 0.07, -0.00], [0.00, 0.00, 0.09], [0.00, -0.00, -0.05]], + [[0.00, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.05, 0.00], [0.00, -0.02, -0.00], [0.00, 0.00, 0.05], [0.00, -0.00, -0.03]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -216,7 +250,8 @@ def getParameterSetNames(): 'Human 1', 'Mouse 1', 'Pig 1', - 'Rat 1'] + 'Rat 1', + 'Material'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): @@ -228,6 +263,8 @@ def getDefaultOptions(cls, parameterSetName='Default'): centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Pig 1'] elif 'Rat 1' in parameterSetName: centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Rat 1'] + elif 'Material' in parameterSetName: + centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Material'] else: centralPathOption = cls.centralPathDefaultScaffoldPackages_Bladder['Cat 1'] options = { @@ -263,6 +300,12 @@ def getDefaultOptions(cls, parameterSetName='Default'): if 'Rat 1' in parameterSetName: options['Wall thickness'] = 0.3 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) + if 'Material' in parameterSetName: + options['Number of elements along dome'] = 8 + options['Number of elements along neck'] = 4 + options['Number of elements around'] = 8 + options['Wall thickness'] = 0.01 + options['Ureter position around'] = 0.67 return options @staticmethod @@ -347,6 +390,7 @@ def generateBaseMesh(cls, region, options): :return: None """ centralPath = options['Central path'] + materialCentralPath = cls.centralPathDefaultScaffoldPackages_Bladder['Material'] elementsCountAlongDome = options['Number of elements along dome'] elementsCountAlongNeck = options['Number of elements along neck'] elementsCountAround = options['Number of elements around'] @@ -365,167 +409,22 @@ def generateBaseMesh(cls, region, options): firstNodeIdentifier = 1 firstElementIdentifier = 1 - # Central path - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - cx_dome, cd1_dome, cd2_dome, cd3_dome, cd12_dome, cd13_dome = \ - 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='dome of the bladder') - cx_neck, cd1_neck, cd2_neck, cd3_neck, cd12_neck, cd13_neck = \ - 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='neck of urinary bladder') - # Find arcLength - # Dome - domeLength = 0.0 - elementsCountInDome = len(cx_dome) - 1 - for e in range(elementsCountInDome): - arcLength = interp.getCubicHermiteArcLength(cx_dome[e], cd1_dome[e], - cx_dome[e + 1], cd1_dome[e + 1]) - domeLength += arcLength - domeSegmentLength = domeLength / elementsCountAlongDome - # Neck - neckLength = 0.0 - elementsCountInNeck = len(cx_neck) - 1 - for e in range(elementsCountInNeck): - arcLength = interp.getCubicHermiteArcLength(cx_neck[e], cd1_neck[e], - cx_neck[e + 1], cd1_neck[e + 1]) - neckLength += arcLength - neckSegmentLength = neckLength / elementsCountAlongNeck - bladderCentralPathLength = domeLength + neckLength - del tmpRegion + # Geometric coordinates + geometricCentralPath = BladderCentralPath(region, centralPath, elementsCountAlongDome, elementsCountAlongNeck) + xFinal, d1Final, d2Final, d3Final = findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, + elementsCountThroughWall, wallThickness, geometricCentralPath, materialCoordinates=False) - # Sample central path - # Dome - sx_dome, sd1_dome, se_dome, sxi_dome, ssf_dome = interp.sampleCubicHermiteCurves(cx_dome, cd1_dome, len(cx_dome)) - sd2_dome, sd12_dome = interp.interpolateSampleCubicHermite(cd2_dome, cd12_dome, se_dome, sxi_dome, ssf_dome) - sd3_dome, sd13_dome = interp.interpolateSampleCubicHermite(cd3_dome, cd13_dome, se_dome, sxi_dome, ssf_dome) - # Neck - sx_neck, sd1_neck, se_neck, sxi_neck, ssf_neck = interp.sampleCubicHermiteCurves(cx_neck, cd1_neck, elementsCountAlongNeck) - sd2_neck, sd12_neck = interp.interpolateSampleCubicHermite(cd2_neck, cd12_neck, se_neck, sxi_neck, ssf_neck) - sd3_neck, sd13_neck = interp.interpolateSampleCubicHermite(cd3_neck, cd13_neck, se_neck, sxi_neck, ssf_neck) - - # Find nodes of bladder dome and neck - sx_dome_group = [sx_dome, sd1_dome, sd2_dome, sd12_dome, sd3_dome, sd13_dome] - sx_neck_group = [sx_neck, sd1_neck, sd2_neck, sd12_neck, sd3_neck, sd13_neck] - - xDome, d1Dome, d2Dome = findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountAlongDome) - - xNeck, d1Neck, d2Neck, px_transit = findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, \ - neckSegmentLength, elementsCountAround, elementsCountAlongNeck) + sx_dome_group = geometricCentralPath.sx_dome_group + sx_neck_group = geometricCentralPath.sx_neck_group + bladderCentralPathLength = geometricCentralPath.bladderCentralPathLength + domeLength = geometricCentralPath.domeLength - # Replace d2 for the last layer of the dome based on the transition nodes - d2Around = [] - for n1 in range(elementsCountAround): - v1 = xDome[-1][n1] - v2 = px_transit[n1] - d2 = findDerivativeBetweenPoints(v1, v2) - # xAlong.append(v1) - d2Around.append(d2) - d2Dome = d2Dome[:-1] + [d2Around] - - xSampledAll = xDome + xNeck - d1SampledAll = d1Dome + d1Neck - d2SampledAll = d2Dome + d2Neck - - # # Smoothing d2 from apex to down the neck - # d2Raw = [] - # for n1 in range(elementsCountAround): - # xAlong = [] - # d2Along = [] - # for n2 in range(elementsCountAlongBladder + 1): - # x = xSampledAll[n2][n1] - # d2 = d2SampledAll[n2][n1] - # xAlong.append(x) - # d2Along.append(d2) - # d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along, fixAllDirections=True) - # d2Raw.append(d2Smoothed) - # - # # Rearrange d2 - # d2SampledAll = [] - # for n2 in range(elementsCountAlongBladder + 1): - # d2Around = [] - # for n1 in range(elementsCountAround): - # d2 = d2Raw[n1][n2] - # d2Around.append(d2) - # d2SampledAll.append(d2Around) - - d3UnitOuter = [] - for n2 in range(1, elementsCountAlongBladder + 1): - d3Around = [] - for n1 in range(elementsCountAround): - d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1SampledAll[n2][n1]), vector.normalise(d2SampledAll[n2][n1])))) - d3UnitOuter.append(d3Around) - - # Inner nodes - xInner = [] - d1Inner = [] - d2Inner = [] - d3Inner = [] - for n2 in range(elementsCountAlongBladder + 1): - for n1 in range(elementsCountAround): - x = xSampledAll[n2][n1] - d1 = d1SampledAll[n2][n1] - d2 = d2SampledAll[n2][n1] - d3 = d3UnitOuter[n2-1][n1] - xInner.append(x) - d1Inner.append(d1) - d2Inner.append(d2) - d3Inner.append(d3) - - # Create outer layers from the inner nodes - wallThicknessList = [wallThickness] * (elementsCountAlongBladder + 1) - relativeThicknessList = [] - transitElementList = [0] * elementsCountAround - xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xInner, d1Inner, - d2Inner, d3Inner, - wallThicknessList, - relativeThicknessList, - elementsCountAround, - elementsCountAlongBladder, - elementsCountThroughWall, - transitElementList) - - # Deal with multiple nodes at the start point for closed proximal end - xApexInner = xList[0] - # Arclength between apex point and corresponding point on next face - mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], xList[2 * elementsCountAround], - d2List[2 * elementsCountAround]) - d2ApexInner = vector.setMagnitude(sd2_dome[0], mag) - - d1ApexInner = vector.crossproduct3(sd1_dome[0], d2ApexInner) - d1ApexInner = vector.setMagnitude(d1ApexInner, mag) - d3ApexUnit = vector.normalise( - vector.crossproduct3(vector.normalise(d1ApexInner), vector.normalise(d2ApexInner))) - d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] - - # Final nodes on the bladder - xFinal = [] - d1Final = [] - d2Final = [] - d3Final = [] - for n3 in range(elementsCountThroughWall + 1): - xApex = [xApexInner[c] + - d3ApexUnit[c] * wallThickness / elementsCountThroughWall * n3 for c in range(3)] - xFinal.append(xApex) - d1Final.append(d1ApexInner) - d2Final.append(d2ApexInner) - d3Final.append(d3ApexInner) - - xFinal += xList[(elementsCountThroughWall + 1) * elementsCountAround:] - d1Final += d1List[(elementsCountThroughWall + 1) * elementsCountAround:] - d2Final += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] - d3Final += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] - - # Obtain flat nodes coordinates - urethraOpeningRadius = vector.magnitude(sd2_neck[-1]) - xFlat, d1Flat, d2Flat = obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, elementsCountThroughWall, - xFinal, d1Final, d2Final, bladderCentralPathLength, urethraOpeningRadius, wallThickness) - xOrgan = d1Organ = d2Organ = [] + # Material coordinates + tmp_region = region.createRegion() + materialCentralPath = BladderCentralPath(tmp_region, materialCentralPath, elementsCountAlongDome, elementsCountAlongNeck) + xOrgan, d1Organ, d2Organ, d3Organ = findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, + elementsCountThroughWall, wallThickness, materialCentralPath, materialCoordinates=True) + del tmp_region # Create annotation groups for bladder bodyGroup = AnnotationGroup(region, get_bladder_term("dome of the bladder")) @@ -554,9 +453,14 @@ def generateBaseMesh(cls, region, options): for i in range(elementsCountThroughWall): annotationGroupsThroughWall.append([]) + # Flat coordinates + urethraOpeningRadius = vector.magnitude(sx_neck_group[2][-1]) + xFlat, d1Flat, d2Flat = obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, elementsCountThroughWall, + xFinal, d1Final, d2Final, bladderCentralPathLength, urethraOpeningRadius, wallThickness) + # Create nodes and elements nodeIdentifier, elementIdentifier, annotationGroups = tubemesh.createNodesAndElements( - region, xFinal, d1Final, d2Final, d3Final, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, + region, xFinal, d1Final, d2Final, d3Final, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, "bladder coordinates", elementsCountAround, elementsCountAlongBladder, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, @@ -569,9 +473,9 @@ def generateBaseMesh(cls, region, options): for n2 in range(elementsCountAlongBladder + 1): for n1 in range(elementsCountAround): idx = n2 * elementsCountAround + elementsCountAround + n1 - xTrackSurface.append(xList[idx]) - d1TrackSurface.append(d1List[idx]) - d2TrackSurface.append(d2List[idx]) + xTrackSurface.append(xFinal[idx]) + d1TrackSurface.append(d1Final[idx]) + d2TrackSurface.append(d2Final[idx]) trackSurfaceBladder = TrackSurface(elementsCountAround, elementsCountAlongBladder, xTrackSurface, d1TrackSurface, d2TrackSurface, loop1=True) @@ -787,7 +691,7 @@ def findDerivativeBetweenPoints(v1, v2): def findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountAlongDome): - # Find Apex nodes d2 + # Find apex nodes d2 d2Apex = [] d2 = sx_dome_group[2][0] for n1 in range(elementsCountAround): @@ -1152,4 +1056,193 @@ def obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, eleme d1Flat.append(d1flatList[i]) d2Flat.append(d2flatList[i]) - return xFlat, d1Flat, d2Flat \ No newline at end of file + return xFlat, d1Flat, d2Flat + +class BladderCentralPath: + """ + Generates sampled central path for bladder scaffold. + """ + def __init__(self, region, centralPath, elementsCountAlongDome, elementsCountAlongNeck): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_path1 + :param elementsCountAlongDome, elementsCountAlongNeck: Nummber of elements along bladder dome and neck. + """ + + # Central path + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + cx_dome, cd1_dome, cd2_dome, cd3_dome, cd12_dome, cd13_dome = \ + 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='dome of the bladder') + cx_neck, cd1_neck, cd2_neck, cd3_neck, cd12_neck, cd13_neck = \ + 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='neck of urinary bladder') + # Find arcLength + # Dome + domeLength = 0.0 + elementsCountInDome = len(cx_dome) - 1 + for e in range(elementsCountInDome): + arcLength = interp.getCubicHermiteArcLength(cx_dome[e], cd1_dome[e], + cx_dome[e + 1], cd1_dome[e + 1]) + domeLength += arcLength + domeSegmentLength = domeLength / elementsCountAlongDome + # Neck + neckLength = 0.0 + elementsCountInNeck = len(cx_neck) - 1 + for e in range(elementsCountInNeck): + arcLength = interp.getCubicHermiteArcLength(cx_neck[e], cd1_neck[e], + cx_neck[e + 1], cd1_neck[e + 1]) + neckLength += arcLength + neckSegmentLength = neckLength / elementsCountAlongNeck + bladderCentralPathLength = domeLength + neckLength + del tmpRegion + + # Sample central path + # Dome + sx_dome, sd1_dome, se_dome, sxi_dome, ssf_dome = interp.sampleCubicHermiteCurves(cx_dome, cd1_dome, len(cx_dome)) + sd2_dome, sd12_dome = interp.interpolateSampleCubicHermite(cd2_dome, cd12_dome, se_dome, sxi_dome, ssf_dome) + sd3_dome, sd13_dome = interp.interpolateSampleCubicHermite(cd3_dome, cd13_dome, se_dome, sxi_dome, ssf_dome) + # Neck + sx_neck, sd1_neck, se_neck, sxi_neck, ssf_neck = interp.sampleCubicHermiteCurves(cx_neck, cd1_neck, elementsCountAlongNeck) + sd2_neck, sd12_neck = interp.interpolateSampleCubicHermite(cd2_neck, cd12_neck, se_neck, sxi_neck, ssf_neck) + sd3_neck, sd13_neck = interp.interpolateSampleCubicHermite(cd3_neck, cd13_neck, se_neck, sxi_neck, ssf_neck) + + # Find nodes of bladder dome and neck + sx_dome_group = [sx_dome, sd1_dome, sd2_dome, sd12_dome, sd3_dome, sd13_dome] + sx_neck_group = [sx_neck, sd1_neck, sd2_neck, sd12_neck, sd3_neck, sd13_neck] + + self.sx_dome_group = sx_dome_group + self.sx_neck_group = sx_neck_group + self.domeSegmentLength = domeSegmentLength + self.neckSegmentLength = neckSegmentLength + self.bladderCentralPathLength = bladderCentralPathLength + self.domeLength = domeLength + +def findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, elementsCountThroughWall, + wallThickness, centralPath, materialCoordinates=False): + + if materialCoordinates: + wallThickness = 0.01 + + sx_dome_group = centralPath.sx_dome_group + sx_neck_group = centralPath.sx_neck_group + domeSegmentLength = centralPath.domeSegmentLength + neckSegmentLength = centralPath.neckSegmentLength + + elementsCountAlongBladder = elementsCountAlongDome + elementsCountAlongNeck + + xDome, d1Dome, d2Dome = findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountAlongDome) + + xNeck, d1Neck, d2Neck, px_transit = findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, \ + neckSegmentLength, elementsCountAround, elementsCountAlongNeck) + + # Replace d2 for the last layer of the dome based on the transition nodes + d2Around = [] + for n1 in range(elementsCountAround): + v1 = xDome[-1][n1] + v2 = px_transit[n1] + d2 = findDerivativeBetweenPoints(v1, v2) + # xAlong.append(v1) + d2Around.append(d2) + d2Dome = d2Dome[:-1] + [d2Around] + + xSampledAll = xDome + xNeck + d1SampledAll = d1Dome + d1Neck + d2SampledAll = d2Dome + d2Neck + + # # Smoothing d2 from apex to down the neck + # d2Raw = [] + # for n1 in range(elementsCountAround): + # xAlong = [] + # d2Along = [] + # for n2 in range(elementsCountAlongBladder + 1): + # x = xSampledAll[n2][n1] + # d2 = d2SampledAll[n2][n1] + # xAlong.append(x) + # d2Along.append(d2) + # d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along, fixAllDirections=True) + # d2Raw.append(d2Smoothed) + # + # # Rearrange d2 + # d2SampledAll = [] + # for n2 in range(elementsCountAlongBladder + 1): + # d2Around = [] + # for n1 in range(elementsCountAround): + # d2 = d2Raw[n1][n2] + # d2Around.append(d2) + # d2SampledAll.append(d2Around) + + d3UnitOuter = [] + for n2 in range(1, elementsCountAlongBladder + 1): + d3Around = [] + for n1 in range(elementsCountAround): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1SampledAll[n2][n1]), vector.normalise(d2SampledAll[n2][n1])))) + d3UnitOuter.append(d3Around) + + # Inner nodes + xInner = [] + d1Inner = [] + d2Inner = [] + d3Inner = [] + for n2 in range(elementsCountAlongBladder + 1): + for n1 in range(elementsCountAround): + x = xSampledAll[n2][n1] + d1 = d1SampledAll[n2][n1] + d2 = d2SampledAll[n2][n1] + d3 = d3UnitOuter[n2 - 1][n1] + xInner.append(x) + d1Inner.append(d1) + d2Inner.append(d2) + d3Inner.append(d3) + + # Create outer layers from the inner nodes + wallThicknessList = [wallThickness] * (elementsCountAlongBladder + 1) + relativeThicknessList = [] + transitElementList = [0] * elementsCountAround + xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xInner, d1Inner, + d2Inner, d3Inner, + wallThicknessList, + relativeThicknessList, + elementsCountAround, + elementsCountAlongBladder, + elementsCountThroughWall, + transitElementList) + + # Deal with multiple nodes at the start point for closed proximal end + xApexInner = xList[0] + # Arclength between apex point and corresponding point on next face + mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], xList[2 * elementsCountAround], + d2List[2 * elementsCountAround]) + d2ApexInner = vector.setMagnitude(sx_dome_group[2][0], mag) + + d1ApexInner = vector.crossproduct3(sx_dome_group[1][0], d2ApexInner) + d1ApexInner = vector.setMagnitude(d1ApexInner, mag) + d3ApexUnit = vector.normalise( + vector.crossproduct3(vector.normalise(d1ApexInner), vector.normalise(d2ApexInner))) + d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] + + # Final nodes on the bladder + xFinal = [] + d1Final = [] + d2Final = [] + d3Final = [] + for n3 in range(elementsCountThroughWall + 1): + xApex = [xApexInner[c] + + d3ApexUnit[c] * wallThickness / elementsCountThroughWall * n3 for c in range(3)] + xFinal.append(xApex) + d1Final.append(d1ApexInner) + d2Final.append(d2ApexInner) + d3Final.append(d3ApexInner) + + xFinal += xList[(elementsCountThroughWall + 1) * elementsCountAround:] + d1Final += d1List[(elementsCountThroughWall + 1) * elementsCountAround:] + d2Final += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] + d3Final += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] + + return xFinal, d1Final, d2Final, d3Final From fb209b604c3a54e643c5196bd5a5ffb4366f2516 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 19 Jan 2023 15:41:53 +1300 Subject: [PATCH 11/26] Defined materiallWallThickness as a constant and made required changes. --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 07b63d2f..19437aea 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -390,7 +390,6 @@ def generateBaseMesh(cls, region, options): :return: None """ centralPath = options['Central path'] - materialCentralPath = cls.centralPathDefaultScaffoldPackages_Bladder['Material'] elementsCountAlongDome = options['Number of elements along dome'] elementsCountAlongNeck = options['Number of elements along neck'] elementsCountAround = options['Number of elements around'] @@ -399,6 +398,9 @@ def generateBaseMesh(cls, region, options): useCrossDerivatives = False useCubicHermiteThroughWall = not (options['Use linear through wall']) + materialCentralPath = cls.centralPathDefaultScaffoldPackages_Bladder['Material'] + materialWallThickness = 0.01 + elementsCountAlongBladder = elementsCountAlongDome + elementsCountAlongNeck fm = region.getFieldmodule() @@ -412,7 +414,7 @@ def generateBaseMesh(cls, region, options): # Geometric coordinates geometricCentralPath = BladderCentralPath(region, centralPath, elementsCountAlongDome, elementsCountAlongNeck) xFinal, d1Final, d2Final, d3Final = findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, - elementsCountThroughWall, wallThickness, geometricCentralPath, materialCoordinates=False) + elementsCountThroughWall, wallThickness, geometricCentralPath) sx_dome_group = geometricCentralPath.sx_dome_group sx_neck_group = geometricCentralPath.sx_neck_group @@ -423,7 +425,7 @@ def generateBaseMesh(cls, region, options): tmp_region = region.createRegion() materialCentralPath = BladderCentralPath(tmp_region, materialCentralPath, elementsCountAlongDome, elementsCountAlongNeck) xOrgan, d1Organ, d2Organ, d3Organ = findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, - elementsCountThroughWall, wallThickness, materialCentralPath, materialCoordinates=True) + elementsCountThroughWall, materialWallThickness, materialCentralPath) del tmp_region # Create annotation groups for bladder @@ -1124,10 +1126,7 @@ def __init__(self, region, centralPath, elementsCountAlongDome, elementsCountAlo self.domeLength = domeLength def findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, elementsCountThroughWall, - wallThickness, centralPath, materialCoordinates=False): - - if materialCoordinates: - wallThickness = 0.01 + wallThickness, centralPath): sx_dome_group = centralPath.sx_dome_group sx_neck_group = centralPath.sx_neck_group From 4c1f12c60ffac640841a62b2c50f087c985750e2 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 19 Jan 2023 15:46:41 +1300 Subject: [PATCH 12/26] Swapped left/right ureter junction labels. --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 19437aea..5e3c34ab 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -509,10 +509,10 @@ def generateBaseMesh(cls, region, options): markerList.append({"group": apexGroup, "elementId": idx1, "xi": xi1}) idx2 = elementsCountAlongDome * elementsCountAround * elementsCountThroughWall + ureterElementPositionAround + 1 xi2 = [ureter1Position.xi1, 0.0, 0.0] - markerList.append({"group": leftUreterGroup, "elementId": idx2, "xi": xi2}) + markerList.append({"group": rightUreterGroup, "elementId": idx2, "xi": xi2}) idx3 = elementsCountAlongDome * elementsCountAround * elementsCountThroughWall + elementsCountAround - ureterElementPositionAround xi3 = [1 - ureter1Position.xi1, 0.0, 0.0] - markerList.append({"group": rightUreterGroup, "elementId": idx3, "xi": xi3}) + markerList.append({"group": leftUreterGroup, "elementId": idx3, "xi": xi3}) bladderNodesetGroup = bladderGroup.getNodesetGroup(nodes) for marker in markerList: From 1fbd0e66c230501ad8f28f319828c4ad01d80558 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 19 Jan 2023 16:58:26 +1300 Subject: [PATCH 13/26] Made all the central paths in the x-y plane. --- .../meshtypes/meshtype_3d_bladder1.py | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 5e3c34ab..f290ab2b 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -42,14 +42,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[70.80, 72.30, 0.00], [-20.79, -22.78, 0.52], [18.43, -16.77, 1.98], [1.58, -5.87, -2.59], [-1.33, 1.87, 28.21], [1.21, -2.78, 20.33]], - [[49.64, 51.56, 0.11], [-21.49, -18.65, -0.31], [19.75, -22.76, 0.28], [1.06, -6.10, -0.81], [-0.59, -0.01, 41.40], [0.27, -0.96, 6.06]], - [[28.03, 34.99, -0.59], [-23.01, -16.34, -0.47], [20.57, -28.97, 0.28], [-2.00, -1.83, 0.44], [-0.75, -0.13, 40.89], [-0.26, 0.40, -4.19]], - [[3.63, 18.98, -0.82], [-26.42, -15.76, -0.50], [15.55, -26.11, 1.19], [-6.09, 5.90, -0.06], [-1.12, 0.83, 32.77], [0.03, -0.01, -9.44]], - [[-24.82, 3.62, -1.62], [-23.44, -11.53, -0.83], [8.28, -16.84, 0.05], [-4.41, 6.01, -0.02], [-0.65, -0.25, 21.87], [0.08, 0.02, -8.87]], - [[-43.01, -4.49, -2.39], [-19.63, -8.66, -0.84], [5.63, -12.84, 0.73], [-2.80, 5.02, 0.06], [-0.81, 0.45, 14.26], [0.01, 0.10, -6.72]], - [[-64.08, -13.68, -3.31], [-22.03, -8.81, -1.71], [2.65, -6.64, 0.07], [-2.12, 4.29, -0.34], [-0.60, -0.16, 8.58], [-0.01, -0.33, -3.96]], - [[-87.03, -22.04, -5.85], [-23.83, -7.91, -3.38], [1.45, -4.39, 0.06], [-0.29, 0.22, 0.33], [-0.85, -0.19, 6.45], [-0.48, 0.26, -0.30]]]), + [[157.00, -94.00, 0.00], [-16.92, 20.23, 0.00], [-13.23, -11.07, -2.66], [-9.16, -14.75, 4.76], [-3.31, -2.77, 27.98], [6.21, 5.18, 20.05]], + [[137.00, -74.00, 0.00], [-23.00, 19.67, 0.00], [-19.55, -22.86, 1.80], [-3.47, -8.84, 4.17], [1.61, 1.88, 41.33], [3.63, 4.12, 6.65]], + [[110.98, -55.04, 0.00], [-23.55, 16.45, 0.00], [-19.79, -28.33, 5.63], [1.96, -0.91, 0.03], [3.77, 5.39, 40.36], [-0.30, -0.11, -4.73]], + [[90.00, -41.00, 0.00], [-21.91, 13.75, 0.00], [-16.10, -25.66, 2.68], [4.79, 4.63, -1.52], [1.54, 2.45, 32.68], [-1.30, -1.59, -9.65]], + [[67.17, -27.59, 0.00], [-23.60, 12.63, 0.00], [-10.16, -18.98, 2.65], [5.23, 6.43, -0.78], [1.22, 2.28, 20.96], [-0.54, -0.71, -9.24]], + [[42.83, -15.79, 0.00], [-23.33, 10.32, 0.00], [-5.66, -12.80, 1.10], [3.81, 6.13, -1.26], [0.45, 1.02, 14.25], [-0.58, -1.08, -6.15]], + [[20.60, -6.87, 0.00], [-21.44, 7.87, 0.00], [-2.46, -6.71, 0.09], [2.12, 4.09, -0.46], [0.04, 0.10, 8.60], [-0.19, -0.41, -3.79]], + [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.12], [0.17, 0.47, 0.52], [0.05, 0.16, 6.50], [0.21, 0.52, -0.41]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -76,14 +76,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[139.76, 57.34, -16.27], [-48.91, -19.25, 7.52], [25.22, -60.05, 10.30], [13.84, -27.31, 3.97], [4.34, 11.87, 58.57], [0.50, 3.10, 20.20]], - [[93.16, 38.43, -9.34], [-44.30, -18.57, 6.33], [37.80, -85.02, 15.07], [11.31, -22.63, 5.57], [4.61, 16.17, 79.63], [0.05, 5.49, 21.92]], - [[51.16, 20.26, -3.58], [-42.36, -18.06, 5.86], [47.96, -105.53, 21.36], [5.99, -12.80, 6.16], [4.45, 22.74, 102.34], [-1.40, 5.62, 13.90]], - [[8.43, 2.30, 2.37], [-42.52, -17.82, 5.26], [49.71, -110.52, 27.39], [0.24, -1.20, 4.10], [1.79, 27.40, 107.31], [-2.40, 1.97, -2.17]], - [[-33.87, -15.38, 6.95], [-39.81, -16.66, 4.39], [48.45, -107.98, 29.59], [-5.06, 13.34, -1.82], [-0.35, 26.73, 98.10], [-0.90, -4.12, -19.76]], - [[-71.20, -31.01, 11.15], [-38.71, -16.87, 4.70], [40.03, -85.11, 24.22], [-15.45, 35.80, -10.05], [-0.15, 19.57, 69.02], [0.48, -8.03, -29.10]], - [[-111.26, -49.16, 16.38], [-39.85, -17.77, 5.34], [16.93, -35.23, 9.08], [-18.25, 38.75, -11.22], [0.63, 10.58, 39.89], [0.21, -8.76, -30.38]], - [[-150.90, -66.56, 21.84], [-39.43, -17.02, 5.58], [3.46, -7.44, 1.72], [-8.70, 16.83, -3.49], [0.29, 2.05, 8.29], [-0.90, -8.30, -32.83]]]), + [[290.00, -124.00, 0.00], [-44.53, 10.62, 2.07], [-14.50, -63.17, 12.12], [-24.99, -23.48, 7.76], [5.15, 10.11, 58.84], [0.77, 5.08, 20.03]], + [[245.52, -109.41, 1.05], [-44.22, 18.50, 0.02], [-35.41, -84.66, 21.54], [-16.82, -19.48, 11.08], [7.21, 17.14, 79.23], [3.37, 8.99, 20.76]], + [[202.00, -87.00, 0.00], [-43.33, 20.19, -0.51], [-47.95, -102.05, 34.35], [-4.79, -11.99, 8.62], [11.94, 28.18, 100.37], [3.03, 7.38, 12.77]], + [[159.00, -69.00, 0.00], [-42.00, 17.50, 0.00], [-45.37, -108.90, 38.98], [1.87, -1.71, 3.74], [13.36, 32.08, 105.18], [0.74, 1.97, -2.61]], + [[118.00, -52.00, 0.00], [-39.50, 16.50, 0.00], [-44.17, -105.72, 41.88], [4.75, 13.33, -2.01], [13.46, 32.21, 95.50], [-1.53, -4.24, -19.52]], + [[80.00, -36.00, 0.00], [-39.01, 16.99, 0.00], [-36.12, -82.95, 35.31], [14.15, 35.25, -13.90], [10.41, 23.92, 66.83], [-3.83, -9.68, -28.35]], + [[40.00, -18.00, 0.00], [-40.00, 18.00, 0.00], [-15.49, -34.42, 13.61], [16.42, 37.84, -16.38], [5.75, 12.77, 38.83], [-4.67, -10.77, -29.35]], + [[0.00, 0.00, 0.00], [-40.00, 18.00, 0.00], [-3.28, -7.28, 2.56], [8.01, 16.45, -5.73], [1.07, 2.38, 8.14], [-4.68, -10.01, -32.03]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -110,14 +110,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[26.51, 16.41, 4.08], [-9.57, -8.90, -0.96], [4.88, -5.26, 0.16], [1.94, -3.51, 0.19], [-0.47, -0.23, 6.83], [-0.95, -0.39, 8.28]], - [[16.73, 8.32, 2.96], [-9.96, -7.26, -1.27], [6.35, -8.72, -0.01], [1.01, -3.40, -0.53], [-1.09, -0.82, 13.21], [-0.30, -0.78, 4.48]], - [[6.67, 1.90, 1.56], [-10.64, -6.01, -1.39], [6.93, -12.06, -0.88], [-0.36, -1.94, -0.43], [-1.08, -1.78, 15.91], [-0.04, -0.39, 1.12]], - [[-4.52, -3.64, 0.18], [-10.61, -4.65, -1.28], [5.60, -12.53, -0.85], [-1.88, 1.30, -0.10], [-1.18, -1.56, 15.38], [0.03, -0.00, -1.59]], - [[-14.49, -7.47, -1.01], [-8.85, -2.84, -1.10], [3.25, -9.72, -1.06], [-2.15, 3.53, 0.17], [-1.04, -1.75, 12.88], [0.25, 0.35, -3.93]], - [[-22.12, -9.45, -1.99], [-7.82, -1.62, -0.91], [1.25, -5.66, -0.61], [-1.42, 3.63, 0.34], [-0.71, -1.00, 7.89], [0.41, 0.62, -4.91]], - [[-30.11, -10.70, -2.82], [-8.26, -1.29, -0.82], [0.42, -2.47, -0.38], [-0.55, 2.36, 0.22], [-0.22, -0.51, 3.06], [0.30, 0.34, -3.06]], - [[-38.65, -12.04, -3.63], [-8.81, -1.38, -0.79], [0.17, -1.00, -0.16], [0.04, 0.58, 0.21], [-0.12, -0.33, 1.88], [-0.09, 0.02, 0.71]]]), + [[65.00, -28.00, 0.00], [-10.45, 9.02, 0.00], [-4.60, -5.33, 1.42], [-2.54, -3.38, -1.33], [0.88, 1.02, 6.72], [-0.90, -0.72, 8.69]], + [[55.00, -20.00, 0.00], [-9.54, 6.98, 0.00], [-6.37, -8.71, -0.03], [-1.00, -3.38, -1.57], [-0.02, -0.03, 13.28], [-0.92, -1.39, 4.44]], + [[46.00, -14.00, 0.00], [-10.01, 5.57, 0.00], [-6.72, -12.09, -1.70], [0.54, -2.06, -0.66], [-0.95, -1.71, 15.93], [-0.29, -0.68, 1.17]], + [[35.00, -9.00, 0.00], [-11.02, 4.50, 0.00], [-5.18, -12.68, -1.23], [1.79, 1.21, 0.19], [-0.52, -1.28, 15.44], [0.21, 0.06, -1.51]], + [[24.00, -5.00, 0.00], [-9.03, 2.93, 0.00], [-3.15, -9.72, -1.31], [2.01, 3.63, 0.37], [-0.51, -1.58, 12.93], [0.21, 0.31, -4.05]], + [[17.00, -3.00, 0.00], [-7.52, 1.53, 0.00], [-1.16, -5.67, -0.67], [1.39, 3.65, 0.47], [-0.18, -0.90, 7.93], [0.22, 0.55, -4.93]], + [[9.00, -2.00, 0.00], [-8.52, 1.48, 0.00], [-0.43, -2.47, -0.40], [0.47, 2.41, 0.25], [-0.08, -0.49, 3.07], [0.05, 0.30, -3.15]], + [[0.00, 0.00, 0.00], [-9.47, 2.52, 0.00], [-0.26, -0.98, -0.18], [-0.13, 0.57, 0.21], [-0.08, -0.32, 1.88], [-0.05, 0.04, 0.77]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -144,14 +144,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[177.93, 203.27, -6.98], [-39.04, -53.00, 0.83], [30.11, -22.17, 0.29], [51.78, -52.34, -1.70], [0.03, 0.42, 28.30], [1.06, -1.92, 120.97]], - [[133.76, 151.30, -6.66], [-49.17, -50.77, -0.19], [66.66, -64.55, -1.68], [21.33, -32.41, -2.24], [1.30, -1.69, 116.41], [1.47, -2.29, 55.25]], - [[79.63, 102.22, -7.39], [-55.84, -46.38, -0.19], [71.68, -86.28, -4.21], [-0.40, -15.45, 2.49], [3.00, -4.17, 136.47], [-0.79, 2.99, 6.58]], - [[22.26, 58.63, -7.05], [-62.26, -42.93, 1.27], [65.94, -95.54, 3.23], [-9.21, -3.67, 4.74], [-0.25, 4.21, 129.76], [-1.86, 5.07, -12.37]], - [[-44.89, 16.76, -4.76], [-67.15, -38.10, 1.57], [52.92, -93.08, 5.01], [-16.55, 14.33, 1.48], [-0.59, 5.64, 111.17], [-0.96, 1.25, -22.72]], - [[-111.81, -17.62, -3.87], [-64.44, -31.46, 0.87], [33.03, -67.48, 6.20], [-19.80, 30.23, -1.80], [-2.14, 6.72, 84.52], [0.49, -1.71, -32.39]], - [[-173.66, -46.27, -3.03], [-63.30, -25.43, 1.60], [13.32, -33.05, 1.69], [-14.90, 28.31, -1.76], [0.19, 2.48, 46.94], [0.94, -1.85, -35.99]], - [[-238.18, -68.39, -0.67], [-65.62, -18.77, 3.11], [3.23, -10.86, 2.68], [-5.27, 16.06, 3.74], [-0.27, 3.02, 12.55], [-1.86, 2.93, -32.79]]]), + [[417.00, 272.00, 0.00], [-39.04, -53.00, 0.83], [30.11, -22.17, 0.29], [51.78, -52.34, -1.70], [0.03, 0.42, 28.30], [1.06, -1.92, 120.97]], + [[373.00, 220.00, 0.00], [-49.17, -50.77, -0.19], [66.66, -64.55, -1.68], [21.33, -32.41, -2.24], [1.30, -1.69, 116.41], [1.47, -2.29, 55.25]], + [[319.00, 171.00, 0.00], [-55.84, -46.38, -0.19], [71.68, -86.28, -4.21], [-0.40, -15.45, 2.49], [3.00, -4.17, 136.47], [-0.79, 2.99, 6.58]], + [[261.00, 127.00, 0.00], [-62.26, -42.93, 1.27], [65.94, -95.54, 3.23], [-9.21, -3.67, 4.74], [-0.25, 4.21, 129.76], [-1.86, 5.07, -12.37]], + [[195.00, 86.00, 0.00], [-67.15, -38.10, 1.57], [52.92, -93.08, 5.01], [-16.55, 14.33, 1.48], [-0.59, 5.64, 111.17], [-0.96, 1.25, -22.72]], + [[128.00, 52.00, 0.00], [-64.44, -31.46, 0.87], [33.03, -67.48, 6.20], [-19.80, 30.23, -1.80], [-2.14, 6.72, 84.52], [0.49, -1.71, -32.39]], + [[66.00, 23.00, 0.00], [-63.30, -25.43, 1.60], [13.32, -33.05, 1.69], [-14.90, 28.31, -1.76], [0.19, 2.48, 46.94], [0.94, -1.85, -35.99]], + [[0.00, 0.00, 0.00], [-65.62, -18.77, 3.11], [3.23, -10.86, 2.68], [-5.27, 16.06, 3.74], [-0.27, 3.02, 12.55], [-1.86, 2.93, -32.79]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -178,14 +178,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[54.13, 48.48, 12.30], [-7.00, -7.20, -1.74], [2.81, -2.80, 0.27], [8.05, -8.69, 0.83], [-0.56, -0.25, 3.28], [-1.03, -0.38, 5.83]], - [[45.64, 40.32, 10.27], [-9.99, -9.12, -2.31], [9.36, -10.47, 0.88], [5.04, -6.65, 0.39], [-1.44, -0.57, 8.47], [-0.71, -0.27, 4.55]], - [[34.10, 30.30, 7.68], [-11.90, -9.54, -2.50], [12.45, -15.79, 0.99], [1.92, -4.02, -0.41], [-1.95, -0.77, 12.19], [-0.23, -0.37, 2.65]], - [[21.85, 21.25, 5.27], [-12.81, -9.14, -2.63], [13.20, -18.51, 0.06], [-0.36, -1.77, -0.92], [-1.90, -1.31, 13.78], [0.21, -0.36, 0.38]], - [[8.49, 12.04, 2.41], [-14.44, -8.62, -2.68], [11.66, -19.26, -0.86], [-2.78, 1.37, -0.56], [-1.51, -1.48, 12.86], [0.47, 0.09, -1.85]], - [[-6.98, 4.11, -0.07], [-14.87, -7.05, -2.20], [7.56, -15.62, -1.03], [-4.79, 7.26, -0.08], [-0.95, -1.12, 10.03], [0.68, 0.11, -3.53]], - [[-21.21, -2.10, -2.00], [-16.58, -6.58, -1.81], [2.15, -5.14, -1.02], [-3.60, 6.99, 0.36], [-0.15, -1.23, 5.87], [0.48, 0.38, -3.79]], - [[-40.17, -8.90, -3.57], [-21.33, -7.01, -1.33], [0.89, -2.66, -0.20], [1.07, -2.03, 1.29], [-0.09, -0.22, 2.55], [-0.35, 1.65, -2.85]]]), + [[95.34, -57.99, -0.26], [-7.80, 9.56, 0.66], [-8.00, -6.50, -0.44], [-0.46, -2.11, 2.10], [0.00, -0.23, 3.33], [0.92, 0.77, 5.96]], + [[86.37, -48.34, 0.16], [-10.12, 9.72, 0.18], [-9.06, -9.45, 1.15], [-1.66, -3.81, 1.09], [0.60, 0.47, 8.58], [0.28, 0.63, 4.54]], + [[75.08, -38.67, 0.06], [-12.19, 9.74, -0.30], [-11.40, -14.21, 1.67], [-1.86, -4.70, -0.44], [0.52, 1.03, 12.31], [-0.27, -0.15, 2.74]], + [[61.99, -28.92, -0.46], [-13.08, 8.83, -0.01], [-12.72, -18.84, 0.18], [0.31, -2.64, -1.79], [0.05, 0.10, 13.97], [-0.44, -1.05, 0.29]], + [[49.00, -21.00, 0.00], [-14.49, 8.02, 0.25], [-10.90, -19.63, -1.90], [2.67, 1.37, -0.99], [-0.36, -1.06, 12.98], [-0.24, -0.53, -1.86]], + [[33.00, -13.00, 0.00], [-15.03, 6.92, 0.00], [-7.23, -15.72, -1.62], [3.94, 6.12, -0.06], [-0.39, -0.86, 10.09], [-0.08, -0.14, -3.63]], + [[19.00, -7.10, 0.00], [-16.49, 6.55, 0.00], [-3.07, -7.72, -1.96], [3.29, 6.75, 0.54], [-0.51, -1.28, 5.84], [0.12, 0.22, -3.84]], + [[0.00, 0.00, 0.00], [-21.51, 7.65, 0.00], [-0.94, -2.64, -0.25], [0.97, 3.41, 2.88], [-0.08, -0.21, 2.55], [0.74, 1.92, -2.74]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, From 5a77db4c02c99fe53b2a52d487a83a127e015697 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 19 Jan 2023 17:15:09 +1300 Subject: [PATCH 14/26] Minor changes done. --- .../meshtypes/meshtype_3d_bladder1.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index f290ab2b..bc05accf 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -278,7 +278,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Use linear through wall': True, 'Refine': False, 'Refine number of elements along': 4, - 'Refine Number of elements around': 4, + 'Refine number of elements around': 4, 'Refine number of elements through wall': 1 } if 'Human 1' in parameterSetName: @@ -320,7 +320,7 @@ def getOrderedOptionNames(): 'Ureter position around', 'Use linear through wall', 'Refine', - 'Refine Number of elements around', + 'Refine number of elements around', 'Refine number of elements along', 'Refine number of elements through wall'] return optionNames @@ -366,7 +366,7 @@ def checkOptions(cls, options): 'Number of elements around', 'Number of elements through wall', 'Refine number of elements along', - 'Refine Number of elements around', + 'Refine number of elements around', 'Refine number of elements through wall']: if options[key] < 1: options[key] = 1 @@ -535,8 +535,8 @@ def refineMesh(cls, meshrefinement, options): :param meshrefinement: MeshRefinement, which knows source and target region. :param options: Dict containing options. See getDefaultOptions(). """ - refineElementsCountAround = options['Refine number of elements along'] - refineElementsCountAlong = options['Refine Number of elements around'] + 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, @@ -1115,11 +1115,9 @@ def __init__(self, region, centralPath, elementsCountAlongDome, elementsCountAlo sd3_neck, sd13_neck = interp.interpolateSampleCubicHermite(cd3_neck, cd13_neck, se_neck, sxi_neck, ssf_neck) # Find nodes of bladder dome and neck - sx_dome_group = [sx_dome, sd1_dome, sd2_dome, sd12_dome, sd3_dome, sd13_dome] - sx_neck_group = [sx_neck, sd1_neck, sd2_neck, sd12_neck, sd3_neck, sd13_neck] + self.sx_dome_group = [sx_dome, sd1_dome, sd2_dome, sd12_dome, sd3_dome, sd13_dome] + self.sx_neck_group = [sx_neck, sd1_neck, sd2_neck, sd12_neck, sd3_neck, sd13_neck] - self.sx_dome_group = sx_dome_group - self.sx_neck_group = sx_neck_group self.domeSegmentLength = domeSegmentLength self.neckSegmentLength = neckSegmentLength self.bladderCentralPathLength = bladderCentralPathLength From 026ca05dc2f4b72ae42ffb992fd4643f94e17f35 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 2 Feb 2023 14:29:32 +1300 Subject: [PATCH 15/26] Added the start direction for finding d2 in neck and dome. --- .../meshtypes/meshtype_3d_bladder1.py | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index bc05accf..3bf923dc 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -42,14 +42,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[157.00, -94.00, 0.00], [-16.92, 20.23, 0.00], [-13.23, -11.07, -2.66], [-9.16, -14.75, 4.76], [-3.31, -2.77, 27.98], [6.21, 5.18, 20.05]], - [[137.00, -74.00, 0.00], [-23.00, 19.67, 0.00], [-19.55, -22.86, 1.80], [-3.47, -8.84, 4.17], [1.61, 1.88, 41.33], [3.63, 4.12, 6.65]], - [[110.98, -55.04, 0.00], [-23.55, 16.45, 0.00], [-19.79, -28.33, 5.63], [1.96, -0.91, 0.03], [3.77, 5.39, 40.36], [-0.30, -0.11, -4.73]], - [[90.00, -41.00, 0.00], [-21.91, 13.75, 0.00], [-16.10, -25.66, 2.68], [4.79, 4.63, -1.52], [1.54, 2.45, 32.68], [-1.30, -1.59, -9.65]], - [[67.17, -27.59, 0.00], [-23.60, 12.63, 0.00], [-10.16, -18.98, 2.65], [5.23, 6.43, -0.78], [1.22, 2.28, 20.96], [-0.54, -0.71, -9.24]], - [[42.83, -15.79, 0.00], [-23.33, 10.32, 0.00], [-5.66, -12.80, 1.10], [3.81, 6.13, -1.26], [0.45, 1.02, 14.25], [-0.58, -1.08, -6.15]], - [[20.60, -6.87, 0.00], [-21.44, 7.87, 0.00], [-2.46, -6.71, 0.09], [2.12, 4.09, -0.46], [0.04, 0.10, 8.60], [-0.19, -0.41, -3.79]], - [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.12], [0.17, 0.47, 0.52], [0.05, 0.16, 6.50], [0.21, 0.52, -0.41]]]), + [[163.52, -70.16, -3.16], [-22.69, 11.05, 1.86], [-7.88, -15.96, -1.33], [-7.07, -15.21, 1.69], [0.94, -2.81, 28.14], [0.71, 2.72, 19.85]], + [[140.19, -58.93, -1.74], [-23.95, 11.41, 0.98], [-12.94, -27.16, -0.17], [-3.05, -7.19, 0.64], [1.28, -0.86, 41.30], [-0.03, 1.18, 6.47]], + [[115.62, -47.36, -1.23], [-24.14, 11.12, 0.64], [-13.89, -30.15, -0.07], [0.27, -0.17, 0.07], [0.85, -0.49, 40.76], [-0.34, 0.28, -4.40]], + [[91.93, -36.69, -0.47], [-23.87, 10.76, 0.53], [-12.46, -27.62, -0.02], [2.72, 5.15, 0.04], [0.59, -0.29, 32.68], [-0.33, 0.20, -8.49]], + [[67.89, -25.83, -0.18], [-24.55, 10.46, 0.24], [-8.44, -19.81, -0.00], [3.63, 7.32, 0.01], [0.19, -0.08, 23.77], [-0.27, 0.14, -9.21]], + [[42.83, -15.79, 0.00], [-23.65, 9.48, 0.08], [-5.21, -12.99, -0.00], [2.97, 6.53, 0.00], [0.04, -0.02, 14.25], [-0.09, 0.04, -7.47]], + [[20.60, -6.87, 0.00], [-21.44, 7.87, 0.00], [-2.46, -6.71, 0.00], [1.91, 4.18, 0.00], [0.00, 0.00, 8.60], [-0.02, 0.01, -3.79]], + [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.00], [0.38, 0.37, -0.00], [0.00, 0.00, 6.50], [0.02, -0.01, -0.41]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -717,14 +717,18 @@ def findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountA for n1 in range(elementsCountAround): xAlong = [] d2Along = [] - for n2 in range(len(xEllipses_dome) - 1): - v1 = xEllipses_dome[n2][n1] - v2 = xEllipses_dome[n2 + 1][n1] + for n2 in range(len(xEllipses_dome)): + if n2 == 0: + v1 = sx_dome_group[0][0] + v2 = xEllipses_dome[n2][n1] + else: + v1 = xEllipses_dome[n2 - 1][n1] + v2 = xEllipses_dome[n2][n1] d2 = findDerivativeBetweenPoints(v1, v2) - xAlong.append(v1) + if n2 != 0: + xAlong.append(v1) d2Along.append(d2) xAlong.append(xEllipses_dome[-1][n1]) - d2Along.append(d2) d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) d2Raw.append(d2Smoothed) @@ -788,7 +792,7 @@ def findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountA return xSampledDome, d1SampledDome, d2SampledDome -def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, neckSegmentLength, elementsCountAround, elementsCountAlongNeck): +def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, d2SampledDome, domeSegmentLength, neckSegmentLength, elementsCountAround, elementsCountAlongNeck): # Transition transitLength = (domeSegmentLength + neckSegmentLength) / 2 @@ -820,16 +824,18 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, n for n1 in range(elementsCountAround): xAlong = [] d2Along = [] - for n2 in range(len(xEllipses_neck) - 1): - v1 = xEllipses_neck[n2][n1] - v2 = xEllipses_neck[n2 + 1][n1] - d2 = findDerivativeBetweenPoints(v1, v2) - xAlong.append(v1) + for n2 in range(len(xEllipses_neck)): + if n2 == 0: + v2 = xEllipses_neck[n2][n1] + d2 = d2SampledDome[-1][n1] + else: + v1 = xEllipses_neck[n2 - 1][n1] + v2 = xEllipses_neck[n2][n1] + d2 = findDerivativeBetweenPoints(v1, v2) + xAlong.append(v2) d2Along.append(d2) - xAlong.append(xEllipses_neck[-1][n1]) - d2Along.append(d2) d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) - d2Raw.append(d2Along) + d2Raw.append(d2Smoothed) # Rearrange d2 d2Ellipses_neck = [] @@ -1135,7 +1141,7 @@ def findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsC xDome, d1Dome, d2Dome = findNodesAlongBladderDome(sx_dome_group, elementsCountAround, elementsCountAlongDome) - xNeck, d1Neck, d2Neck, px_transit = findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, domeSegmentLength, \ + xNeck, d1Neck, d2Neck, px_transit = findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, d2Dome, domeSegmentLength, \ neckSegmentLength, elementsCountAround, elementsCountAlongNeck) # Replace d2 for the last layer of the dome based on the transition nodes From 82e49dc031b2df5a0ad6fbb75170a0e328f2b357 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Thu, 2 Feb 2023 16:49:14 +1300 Subject: [PATCH 16/26] Made the central path for cat in the xy plane. --- .../meshtypes/meshtype_3d_bladder1.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 3bf923dc..75c501b5 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -42,14 +42,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[163.52, -70.16, -3.16], [-22.69, 11.05, 1.86], [-7.88, -15.96, -1.33], [-7.07, -15.21, 1.69], [0.94, -2.81, 28.14], [0.71, 2.72, 19.85]], - [[140.19, -58.93, -1.74], [-23.95, 11.41, 0.98], [-12.94, -27.16, -0.17], [-3.05, -7.19, 0.64], [1.28, -0.86, 41.30], [-0.03, 1.18, 6.47]], - [[115.62, -47.36, -1.23], [-24.14, 11.12, 0.64], [-13.89, -30.15, -0.07], [0.27, -0.17, 0.07], [0.85, -0.49, 40.76], [-0.34, 0.28, -4.40]], - [[91.93, -36.69, -0.47], [-23.87, 10.76, 0.53], [-12.46, -27.62, -0.02], [2.72, 5.15, 0.04], [0.59, -0.29, 32.68], [-0.33, 0.20, -8.49]], - [[67.89, -25.83, -0.18], [-24.55, 10.46, 0.24], [-8.44, -19.81, -0.00], [3.63, 7.32, 0.01], [0.19, -0.08, 23.77], [-0.27, 0.14, -9.21]], - [[42.83, -15.79, 0.00], [-23.65, 9.48, 0.08], [-5.21, -12.99, -0.00], [2.97, 6.53, 0.00], [0.04, -0.02, 14.25], [-0.09, 0.04, -7.47]], - [[20.60, -6.87, 0.00], [-21.44, 7.87, 0.00], [-2.46, -6.71, 0.00], [1.91, 4.18, 0.00], [0.00, 0.00, 8.60], [-0.02, 0.01, -3.79]], - [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.00], [0.38, 0.37, -0.00], [0.00, 0.00, 6.50], [0.02, -0.01, -0.41]]]), + [[163.52, -70.16, 0.00], [-22.71, 11.06, 0.00], [-7.79, -16.00, 0.00], [-7.18, -15.15, 0.00], [0.00, 0.00, 28.30], [0.00, 0.00, 19.67]], + [[140.19, -58.93, 0.00], [-23.95, 11.40, 0.00], [-12.93, -27.16, 0.00], [-3.10, -7.17, 0.00], [0.00, 0.00, 41.33], [0.00, 0.00, 6.40]], + [[115.62, -47.36, 0.00], [-24.13, 11.12, 0.00], [-13.89, -30.15, 0.00], [0.26, -0.17, 0.00], [0.00, 0.00, 40.77], [0.00, 0.00, -4.40]], + [[91.93, -36.69, 0.00], [-23.87, 10.77, 0.00], [-12.46, -27.62, 0.00], [2.71, 5.15, 0.00], [0.00, 0.00, 32.69], [0.00, 0.00, -8.50]], + [[67.89, -25.83, 0.00], [-24.55, 10.46, 0.00], [-8.44, -19.81, 0.00], [3.63, 7.32, 0.00], [0.00, 0.00, 23.77], [0.00, 0.00, -9.21]], + [[42.83, -15.79, 0.00], [-23.65, 9.48, 0.00], [-5.21, -12.99, 0.00], [2.97, 6.53, 0.00], [0.00, 0.00, 14.25], [0.00, 0.00, -7.47]], + [[20.60, -6.87, 0.00], [-21.44, 7.87, 0.00], [-2.46, -6.71, 0.00], [1.91, 4.18, 0.00], [0.00, 0.00, 8.60], [0.00, 0.00, -3.79]], + [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.00], [0.38, 0.37, 0.00], [0.00, 0.00, 6.50], [0.00, 0.00, -0.41]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, From 58f11222cf2676cea37cfd650d88c4239ea83ade Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 13 Mar 2023 16:09:34 +1300 Subject: [PATCH 17/26] Changed the transition node coordinates. --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 75c501b5..04f8ce25 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -46,7 +46,7 @@ class MeshType_3d_bladder1(Scaffold_base): [[140.19, -58.93, 0.00], [-23.95, 11.40, 0.00], [-12.93, -27.16, 0.00], [-3.10, -7.17, 0.00], [0.00, 0.00, 41.33], [0.00, 0.00, 6.40]], [[115.62, -47.36, 0.00], [-24.13, 11.12, 0.00], [-13.89, -30.15, 0.00], [0.26, -0.17, 0.00], [0.00, 0.00, 40.77], [0.00, 0.00, -4.40]], [[91.93, -36.69, 0.00], [-23.87, 10.77, 0.00], [-12.46, -27.62, 0.00], [2.71, 5.15, 0.00], [0.00, 0.00, 32.69], [0.00, 0.00, -8.50]], - [[67.89, -25.83, 0.00], [-24.55, 10.46, 0.00], [-8.44, -19.81, 0.00], [3.63, 7.32, 0.00], [0.00, 0.00, 23.77], [0.00, 0.00, -9.21]], + [[67.89, -25.83, 0.00], [-24.55, 10.46, 0.00], [-9.10, -21.35, 0.00], [3.43, 6.83, 0.00], [0.00, 0.00, 23.77], [0.00, 0.00, -9.22]], [[42.83, -15.79, 0.00], [-23.65, 9.48, 0.00], [-5.21, -12.99, 0.00], [2.97, 6.53, 0.00], [0.00, 0.00, 14.25], [0.00, 0.00, -7.47]], [[20.60, -6.87, 0.00], [-21.44, 7.87, 0.00], [-2.46, -6.71, 0.00], [1.91, 4.18, 0.00], [0.00, 0.00, 8.60], [0.00, 0.00, -3.79]], [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.00], [0.38, 0.37, 0.00], [0.00, 0.00, 6.50], [0.00, 0.00, -0.41]]]), @@ -886,6 +886,8 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, d2SampledDome, domeS d1SampledNeck.append(d1Smoothed) d2SampledNeck.append(d2Around) + px_transit = xSampledNeck[0] + return xSampledNeck, d1SampledNeck, d2SampledNeck, px_transit def obtainBladderFlatNodes(elementsCountAlongBladder, elementsCountAround, elementsCountThroughWall, From 59e67e64eb9900bea0268147e17291e6371d7736 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 13 Mar 2023 17:20:33 +1300 Subject: [PATCH 18/26] Changed all species central paths to be on the xy plane. --- .../meshtypes/meshtype_3d_bladder1.py | 72 ++++++++++--------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 04f8ce25..c047c1fd 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -76,14 +76,22 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[290.00, -124.00, 0.00], [-44.53, 10.62, 2.07], [-14.50, -63.17, 12.12], [-24.99, -23.48, 7.76], [5.15, 10.11, 58.84], [0.77, 5.08, 20.03]], - [[245.52, -109.41, 1.05], [-44.22, 18.50, 0.02], [-35.41, -84.66, 21.54], [-16.82, -19.48, 11.08], [7.21, 17.14, 79.23], [3.37, 8.99, 20.76]], - [[202.00, -87.00, 0.00], [-43.33, 20.19, -0.51], [-47.95, -102.05, 34.35], [-4.79, -11.99, 8.62], [11.94, 28.18, 100.37], [3.03, 7.38, 12.77]], - [[159.00, -69.00, 0.00], [-42.00, 17.50, 0.00], [-45.37, -108.90, 38.98], [1.87, -1.71, 3.74], [13.36, 32.08, 105.18], [0.74, 1.97, -2.61]], - [[118.00, -52.00, 0.00], [-39.50, 16.50, 0.00], [-44.17, -105.72, 41.88], [4.75, 13.33, -2.01], [13.46, 32.21, 95.50], [-1.53, -4.24, -19.52]], - [[80.00, -36.00, 0.00], [-39.01, 16.99, 0.00], [-36.12, -82.95, 35.31], [14.15, 35.25, -13.90], [10.41, 23.92, 66.83], [-3.83, -9.68, -28.35]], - [[40.00, -18.00, 0.00], [-40.00, 18.00, 0.00], [-15.49, -34.42, 13.61], [16.42, 37.84, -16.38], [5.75, 12.77, 38.83], [-4.67, -10.77, -29.35]], - [[0.00, 0.00, 0.00], [-40.00, 18.00, 0.00], [-3.28, -7.28, 2.56], [8.01, 16.45, -5.73], [1.07, 2.38, 8.14], [-4.68, -10.01, -32.03]]]), + [[290.00, 0.00, 0.00], [-44.96, 0.00, 0.00], [0.00, -64.81, 0.00], [0.00, -29.97, 0.00], [0.00, 0.00, 59.92], [0.00, 0.00, 20.40]], + [[245.52, 0.00, 0.00], [-44.00, 0.00, 0.00], [0.00, -91.77, 0.00], [0.00, -23.94, 0.00], [0.00, 0.00, 81.38], [0.00, 0.00, 22.52]], + [[202.00, 0.00, 0.00], [-43.26, 0.00, 0.00], [0.00, -112.75, 0.00], [0.00, -13.06, 0.00], [0.00, 0.00, 104.93], [0.00, 0.00, 14.64]], + [[159.00, 0.00, 0.00], [-42.00, 0.00, 0.00], [0.00, -117.97, 0.00], [0.00, -0.81, 0.00], [0.00, 0.00, 110.77], [0.00, 0.00, -1.80]], + [[118.00, 0.00, 0.00], [-39.50, 0.00, 0.00], [0.00, -114.58, 0.00], [0.00, 14.14, 0.00], [0.00, 0.00, 101.68], [0.00, 0.00, -19.91]], + [[80.00, 0.00, 0.00], [-39.00, 0.00, 0.00], [0.00, -90.47, 0.00], [0.00, 32.32, 0.00], [0.00, 0.00, 71.74], [0.00, 0.00, -30.20]], + [[40.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -49.51, 0.00], [0.00, 41.24, 0.00], [0.00, 0.00, 41.28], [0.00, 0.00, -31.60]], + [[0.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -7.98, 0.00], [0.00, 41.80, 0.00], [0.00, 0.00, 8.55], [0.00, 0.00, -33.86]]]), + # [[290.00, -124.00, 0.00], [-44.53, 10.62, 2.07], [-14.50, -63.17, 12.12], [-24.99, -23.48, 7.76], [5.15, 10.11, 58.84], [0.77, 5.08, 20.03]], + # [[245.52, -109.41, 0.00], [-44.22, 18.50, 0.02], [-35.41, -84.66, 21.54], [-16.82, -19.48, 11.08], [7.21, 17.14, 79.23], [3.37, 8.99, 20.76]], + # [[202.00, -87.00, 0.00], [-43.33, 20.19, -0.51], [-47.95, -102.05, 34.35], [-4.79, -11.99, 8.62], [11.94, 28.18, 100.37], [3.03, 7.38, 12.77]], + # [[159.00, -69.00, 0.00], [-42.00, 17.50, 0.00], [-45.37, -108.90, 38.98], [1.87, -1.71, 3.74], [13.36, 32.08, 105.18], [0.74, 1.97, -2.61]], + # [[118.00, -52.00, 0.00], [-39.50, 16.50, 0.00], [-44.17, -105.72, 41.88], [4.75, 13.33, -2.01], [13.46, 32.21, 95.50], [-1.53, -4.24, -19.52]], + # [[80.00, -36.00, 0.00], [-39.01, 16.99, 0.00], [-36.12, -82.95, 35.31], [14.15, 35.25, -13.90], [10.41, 23.92, 66.83], [-3.83, -9.68, -28.35]], + # [[40.00, -18.00, 0.00], [-40.00, 18.00, 0.00], [-15.49, -34.42, 13.61], [16.42, 37.84, -16.38], [5.75, 12.77, 38.83], [-4.67, -10.77, -29.35]], + # [[0.00, 0.00, 0.00], [-40.00, 18.00, 0.00], [-3.28, -7.28, 2.56], [8.01, 16.45, -5.73], [1.07, 2.38, 8.14], [-4.68, -10.01, -32.03]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -110,14 +118,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[65.00, -28.00, 0.00], [-10.45, 9.02, 0.00], [-4.60, -5.33, 1.42], [-2.54, -3.38, -1.33], [0.88, 1.02, 6.72], [-0.90, -0.72, 8.69]], - [[55.00, -20.00, 0.00], [-9.54, 6.98, 0.00], [-6.37, -8.71, -0.03], [-1.00, -3.38, -1.57], [-0.02, -0.03, 13.28], [-0.92, -1.39, 4.44]], - [[46.00, -14.00, 0.00], [-10.01, 5.57, 0.00], [-6.72, -12.09, -1.70], [0.54, -2.06, -0.66], [-0.95, -1.71, 15.93], [-0.29, -0.68, 1.17]], - [[35.00, -9.00, 0.00], [-11.02, 4.50, 0.00], [-5.18, -12.68, -1.23], [1.79, 1.21, 0.19], [-0.52, -1.28, 15.44], [0.21, 0.06, -1.51]], - [[24.00, -5.00, 0.00], [-9.03, 2.93, 0.00], [-3.15, -9.72, -1.31], [2.01, 3.63, 0.37], [-0.51, -1.58, 12.93], [0.21, 0.31, -4.05]], - [[17.00, -3.00, 0.00], [-7.52, 1.53, 0.00], [-1.16, -5.67, -0.67], [1.39, 3.65, 0.47], [-0.18, -0.90, 7.93], [0.22, 0.55, -4.93]], - [[9.00, -2.00, 0.00], [-8.52, 1.48, 0.00], [-0.43, -2.47, -0.40], [0.47, 2.41, 0.25], [-0.08, -0.49, 3.07], [0.05, 0.30, -3.15]], - [[0.00, 0.00, 0.00], [-9.47, 2.52, 0.00], [-0.26, -0.98, -0.18], [-0.13, 0.57, 0.21], [-0.08, -0.32, 1.88], [-0.05, 0.04, 0.77]]]), + [[65.00, -28.00, 0.00], [-10.45, 9.02, 0.00], [-4.60, -5.33, 0.00], [-2.54, -3.38, 0.00], [0.00, 0.00, 6.72], [0.00, 0.00, 8.69]], + [[55.00, -20.00, 0.00], [-9.54, 6.98, 0.00], [-6.37, -8.71, 0.00], [-1.00, -3.38, 0.00], [0.00, 0.00, 13.28], [0.00, 0.00, 4.44]], + [[46.00, -14.00, 0.00], [-10.01, 5.57, 0.00], [-6.72, -12.09, 0.00], [0.54, -2.06, 0.00], [0.00, 0.00, 15.93], [0.00, 0.00, 1.17]], + [[35.00, -9.00, 0.00], [-11.02, 4.50, 0.00], [-5.18, -12.68, 0.00], [1.79, 1.21, 0.00], [0.00, 0.00, 15.44], [0.00, 0.00, -2.32]], + [[24.00, -5.00, 0.00], [-9.03, 2.93, 0.00], [-3.15, -9.72, 0.00], [1.91, 3.14, 0.00], [0.00, 0.00, 11.35], [0.00, 0.00, -3.68]], + [[17.00, -3.00, 0.00], [-7.52, 1.53, 0.00], [-1.32, -6.47, 0.00], [1.34, 3.34, 0.00], [0.00, 0.00, 7.93], [0.00, 0.00, -3.51]], + [[9.00, -2.00, 0.00], [-8.52, 1.48, 0.00], [-0.52, -3.02, 0.00], [0.48, 2.55, 0.00], [0.00, 0.00, 4.33], [0.00, 0.00, -3.07]], + [[0.00, 0.00, 0.00], [-9.47, 2.52, 0.00], [-0.40, -1.49, 0.00], [-0.23, 0.51, 0.00], [0.00, 0.00, 1.88], [0.00, 0.00, -1.84]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -144,14 +152,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[417.00, 272.00, 0.00], [-39.04, -53.00, 0.83], [30.11, -22.17, 0.29], [51.78, -52.34, -1.70], [0.03, 0.42, 28.30], [1.06, -1.92, 120.97]], - [[373.00, 220.00, 0.00], [-49.17, -50.77, -0.19], [66.66, -64.55, -1.68], [21.33, -32.41, -2.24], [1.30, -1.69, 116.41], [1.47, -2.29, 55.25]], - [[319.00, 171.00, 0.00], [-55.84, -46.38, -0.19], [71.68, -86.28, -4.21], [-0.40, -15.45, 2.49], [3.00, -4.17, 136.47], [-0.79, 2.99, 6.58]], - [[261.00, 127.00, 0.00], [-62.26, -42.93, 1.27], [65.94, -95.54, 3.23], [-9.21, -3.67, 4.74], [-0.25, 4.21, 129.76], [-1.86, 5.07, -12.37]], - [[195.00, 86.00, 0.00], [-67.15, -38.10, 1.57], [52.92, -93.08, 5.01], [-16.55, 14.33, 1.48], [-0.59, 5.64, 111.17], [-0.96, 1.25, -22.72]], - [[128.00, 52.00, 0.00], [-64.44, -31.46, 0.87], [33.03, -67.48, 6.20], [-19.80, 30.23, -1.80], [-2.14, 6.72, 84.52], [0.49, -1.71, -32.39]], - [[66.00, 23.00, 0.00], [-63.30, -25.43, 1.60], [13.32, -33.05, 1.69], [-14.90, 28.31, -1.76], [0.19, 2.48, 46.94], [0.94, -1.85, -35.99]], - [[0.00, 0.00, 0.00], [-65.62, -18.77, 3.11], [3.23, -10.86, 2.68], [-5.27, 16.06, 3.74], [-0.27, 3.02, 12.55], [-1.86, 2.93, -32.79]]]), + [[417.00, 272.00, 0.00], [-39.04, -53.00, 0.00], [30.11, -22.18, 0.00], [51.78, -52.35, 0.00], [0.00, 0.00, 28.30], [0.00, 0.00, 120.97]], + [[373.00, 220.00, 0.00], [-49.17, -50.77, 0.00], [66.66, -64.55, 0.00], [21.32, -32.41, 0.00], [0.00, 0.00, 116.43], [0.00, 0.00, 55.28]], + [[319.00, 171.00, 0.00], [-55.84, -46.38, 0.00], [71.67, -86.29, 0.00], [-0.38, -15.50, 0.00], [0.00, 0.00, 136.57], [0.00, 0.00, 6.69]], + [[261.00, 127.00, 0.00], [-62.26, -42.93, 0.00], [65.90, -95.57, 0.00], [-9.30, -3.61, 0.00], [0.00, 0.00, 129.83], [0.00, 0.00, -12.43]], + [[195.00, 86.00, 0.00], [-67.15, -38.10, 0.00], [52.84, -93.13, 0.00], [-16.53, 14.22, 0.00], [0.00, 0.00, 111.31], [0.00, 0.00, -22.57]], + [[128.00, 52.00, 0.00], [-64.44, -31.46, 0.00], [32.96, -67.51, 0.00], [-19.77, 30.24, 0.00], [0.00, 0.00, 84.81], [0.00, 0.00, -32.42]], + [[66.00, 23.00, 0.00], [-63.30, -25.43, 0.00], [13.28, -33.06, 0.00], [-14.97, 28.37, 0.00], [0.00, 0.00, 47.01], [0.00, 0.00, -35.97]], + [[0.00, 0.00, 0.00], [-65.62, -18.77, 0.00], [3.12, -10.89, 0.00], [-5.36, 15.97, 0.00], [0.00, 0.00, 12.91], [0.00, 0.00, -32.22]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -178,14 +186,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[95.34, -57.99, -0.26], [-7.80, 9.56, 0.66], [-8.00, -6.50, -0.44], [-0.46, -2.11, 2.10], [0.00, -0.23, 3.33], [0.92, 0.77, 5.96]], - [[86.37, -48.34, 0.16], [-10.12, 9.72, 0.18], [-9.06, -9.45, 1.15], [-1.66, -3.81, 1.09], [0.60, 0.47, 8.58], [0.28, 0.63, 4.54]], - [[75.08, -38.67, 0.06], [-12.19, 9.74, -0.30], [-11.40, -14.21, 1.67], [-1.86, -4.70, -0.44], [0.52, 1.03, 12.31], [-0.27, -0.15, 2.74]], - [[61.99, -28.92, -0.46], [-13.08, 8.83, -0.01], [-12.72, -18.84, 0.18], [0.31, -2.64, -1.79], [0.05, 0.10, 13.97], [-0.44, -1.05, 0.29]], - [[49.00, -21.00, 0.00], [-14.49, 8.02, 0.25], [-10.90, -19.63, -1.90], [2.67, 1.37, -0.99], [-0.36, -1.06, 12.98], [-0.24, -0.53, -1.86]], - [[33.00, -13.00, 0.00], [-15.03, 6.92, 0.00], [-7.23, -15.72, -1.62], [3.94, 6.12, -0.06], [-0.39, -0.86, 10.09], [-0.08, -0.14, -3.63]], - [[19.00, -7.10, 0.00], [-16.49, 6.55, 0.00], [-3.07, -7.72, -1.96], [3.29, 6.75, 0.54], [-0.51, -1.28, 5.84], [0.12, 0.22, -3.84]], - [[0.00, 0.00, 0.00], [-21.51, 7.65, 0.00], [-0.94, -2.64, -0.25], [0.97, 3.41, 2.88], [-0.08, -0.21, 2.55], [0.74, 1.92, -2.74]]]), + [[96.01, -55.94, 0.00], [-8.06, 8.25, 0.00], [-4.81, -4.69, 0.00], [-7.40, -7.96, 0.001], [0.00, 0.00, 2.34], [0.00, 0.00, 7.40]], + [[86.69, -47.04, 0.00], [-10.56, 9.55, 0.00], [-10.53, -11.65, 0.00], [-4.05, -5.96, 0.00], [0.00, 0.00, 8.59], [0.00, 0.00, 5.12]], + [[74.85, -36.92, 0.00], [-13.81, 10.54, 0.00], [-12.55, -16.40, 0.00], [-0.83, -3.94, 0.00], [0.00, 0.00, 12.34], [0.00, 0.00, 2.79]], + [[59.01, -26.15, 0.00], [-15.77, 9.72, 0.00], [-11.93, -19.35, 0.00], [1.31, -1.82, 0.00], [0.00, 0.00, 13.96], [0.00, 0.00, 0.30]], + [[43.39, -17.45, 0.00], [-15.66, 7.77, 0.00], [-9.98, -20.11, 0.00], [2.59, 1.78, 0.00], [0.00, 0.00, 13.03], [0.00, 0.00, -1.94]], + [[27.76, -10.60, 0.00], [-14.32, 6.11, 0.00], [-6.79, -15.92, 0.00], [3.53, 6.37, 0.00], [0.00, 0.00, 10.13], [0.00, 0.00, -3.58]], + [[14.77, -5.22, 0.00], [-13.89, 5.33, 0.00], [-2.98, -7.76, 0.00], [3.01, 6.71, 0.00], [0.00, 0.00, 5.99], [0.00, 0.00, -3.81]], + [[0.00, 0.00, 0.00], [-15.64, 5.10, 0.00], [-0.87, -2.66, 0.00], [1.21, 3.47, 0.00], [0.00, 0.00, 2.55], [0.00, 0.00, -3.08]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, From fbe846e1e4ef15f04dc6c0984f932e49b5e1eee5 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Wed, 15 Mar 2023 10:44:37 +1300 Subject: [PATCH 19/26] Changed d2 for the end of neck and fixed the end direction. --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index c047c1fd..59466499 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -836,13 +836,20 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, d2SampledDome, domeS if n2 == 0: v2 = xEllipses_neck[n2][n1] d2 = d2SampledDome[-1][n1] + elif (n2 == len(xEllipses_neck) - 1): + v1 = xEllipses_neck[n2 - 1][n1] + v2 = xEllipses_neck[n2][n1] + d2vec = findDerivativeBetweenPoints(v1, v2) + d2mag = vector.magnitude(d2vec) + d2dir = vector.normalise(sx_neck_group[1][-1]) + d2 = vector.setMagnitude(d2dir, d2mag) else: v1 = xEllipses_neck[n2 - 1][n1] v2 = xEllipses_neck[n2][n1] d2 = findDerivativeBetweenPoints(v1, v2) xAlong.append(v2) d2Along.append(d2) - d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along) + d2Smoothed = interp.smoothCubicHermiteDerivativesLine(xAlong, d2Along, fixEndDirection=True) d2Raw.append(d2Smoothed) # Rearrange d2 From 8b1e9fdbdfcaff6aa4480a7bf568038880f710b4 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Wed, 15 Mar 2023 10:57:15 +1300 Subject: [PATCH 20/26] Edited the human central path. --- .../meshtypes/meshtype_3d_bladder1.py | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 59466499..4be4be1e 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -76,22 +76,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[290.00, 0.00, 0.00], [-44.96, 0.00, 0.00], [0.00, -64.81, 0.00], [0.00, -29.97, 0.00], [0.00, 0.00, 59.92], [0.00, 0.00, 20.40]], - [[245.52, 0.00, 0.00], [-44.00, 0.00, 0.00], [0.00, -91.77, 0.00], [0.00, -23.94, 0.00], [0.00, 0.00, 81.38], [0.00, 0.00, 22.52]], - [[202.00, 0.00, 0.00], [-43.26, 0.00, 0.00], [0.00, -112.75, 0.00], [0.00, -13.06, 0.00], [0.00, 0.00, 104.93], [0.00, 0.00, 14.64]], - [[159.00, 0.00, 0.00], [-42.00, 0.00, 0.00], [0.00, -117.97, 0.00], [0.00, -0.81, 0.00], [0.00, 0.00, 110.77], [0.00, 0.00, -1.80]], - [[118.00, 0.00, 0.00], [-39.50, 0.00, 0.00], [0.00, -114.58, 0.00], [0.00, 14.14, 0.00], [0.00, 0.00, 101.68], [0.00, 0.00, -19.91]], - [[80.00, 0.00, 0.00], [-39.00, 0.00, 0.00], [0.00, -90.47, 0.00], [0.00, 32.32, 0.00], [0.00, 0.00, 71.74], [0.00, 0.00, -30.20]], - [[40.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -49.51, 0.00], [0.00, 41.24, 0.00], [0.00, 0.00, 41.28], [0.00, 0.00, -31.60]], - [[0.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -7.98, 0.00], [0.00, 41.80, 0.00], [0.00, 0.00, 8.55], [0.00, 0.00, -33.86]]]), - # [[290.00, -124.00, 0.00], [-44.53, 10.62, 2.07], [-14.50, -63.17, 12.12], [-24.99, -23.48, 7.76], [5.15, 10.11, 58.84], [0.77, 5.08, 20.03]], - # [[245.52, -109.41, 0.00], [-44.22, 18.50, 0.02], [-35.41, -84.66, 21.54], [-16.82, -19.48, 11.08], [7.21, 17.14, 79.23], [3.37, 8.99, 20.76]], - # [[202.00, -87.00, 0.00], [-43.33, 20.19, -0.51], [-47.95, -102.05, 34.35], [-4.79, -11.99, 8.62], [11.94, 28.18, 100.37], [3.03, 7.38, 12.77]], - # [[159.00, -69.00, 0.00], [-42.00, 17.50, 0.00], [-45.37, -108.90, 38.98], [1.87, -1.71, 3.74], [13.36, 32.08, 105.18], [0.74, 1.97, -2.61]], - # [[118.00, -52.00, 0.00], [-39.50, 16.50, 0.00], [-44.17, -105.72, 41.88], [4.75, 13.33, -2.01], [13.46, 32.21, 95.50], [-1.53, -4.24, -19.52]], - # [[80.00, -36.00, 0.00], [-39.01, 16.99, 0.00], [-36.12, -82.95, 35.31], [14.15, 35.25, -13.90], [10.41, 23.92, 66.83], [-3.83, -9.68, -28.35]], - # [[40.00, -18.00, 0.00], [-40.00, 18.00, 0.00], [-15.49, -34.42, 13.61], [16.42, 37.84, -16.38], [5.75, 12.77, 38.83], [-4.67, -10.77, -29.35]], - # [[0.00, 0.00, 0.00], [-40.00, 18.00, 0.00], [-3.28, -7.28, 2.56], [8.01, 16.45, -5.73], [1.07, 2.38, 8.14], [-4.68, -10.01, -32.03]]]), + [[327.63, 0.00, 0.00], [-47.88, 0.00, 0.00], [0.00, -88.67, 0.00], [0.00, -27.39, 0.00], [0.00, 0.00, 55.11], [0.00, 0.00, 75.02]], + [[278.67, 0.00, 0.00], [-50.03, 0.00, 0.00], [0.00, -115.01, 0.00], [0.00, -25.29, 0.00], [0.00, 0.00, 110.57], [0.00, 0.00, 35.90]], + [[227.59, 0.00, 0.00], [-51.46, 0.00, 0.00], [0.00, -139.20, 0.00], [0.00, -15.31, 0.00], [0.00, 0.00, 126.06], [0.00, 0.00, 9.86]], + [[175.76, 0.00, 0.00], [-50.07, 0.00, 0.00], [0.00, -145.49, 0.00], [0.00, 0.61, 0.00], [0.00, 0.00, 130.21], [0.00, 0.00, -0.34]], + [[127.45, 0.00, 0.00], [-47.88, 0.00, 0.00], [0.00, -138.44, 0.00], [0.00, 15.55, 0.00], [0.00, 0.00, 125.68], [0.00, 0.00, -12.32]], + [[80.00, 0.00, 0.00], [-43.73, 0.00, 0.00], [0.00, -114.54, 0.00], [0.00, 29.79, 0.00], [0.00, 0.00, 105.71], [0.00, 0.00, -24.64]], + [[40.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -79.78, 0.00], [0.00, 51.57, 0.00], [0.00, 0.00, 77.13], [0.00, 0.00, -48.60]], + [[0.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -11.40, 0.00], [0.00, 85.18, 0.00], [0.00, 0.00, 8.51], [0.00, 0.00, -88.64]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, From 65f99d3a9302eac5df1f415a2ea62751220639cf Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Wed, 15 Mar 2023 11:10:10 +1300 Subject: [PATCH 21/26] Made some changes to human central path. --- .../meshtypes/meshtype_3d_bladder1.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 4be4be1e..8c1b5007 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -76,14 +76,14 @@ class MeshType_3d_bladder1(Scaffold_base): }, 'meshEdits': exnodeStringFromNodeValues( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - [[327.63, 0.00, 0.00], [-47.88, 0.00, 0.00], [0.00, -88.67, 0.00], [0.00, -27.39, 0.00], [0.00, 0.00, 55.11], [0.00, 0.00, 75.02]], - [[278.67, 0.00, 0.00], [-50.03, 0.00, 0.00], [0.00, -115.01, 0.00], [0.00, -25.29, 0.00], [0.00, 0.00, 110.57], [0.00, 0.00, 35.90]], - [[227.59, 0.00, 0.00], [-51.46, 0.00, 0.00], [0.00, -139.20, 0.00], [0.00, -15.31, 0.00], [0.00, 0.00, 126.06], [0.00, 0.00, 9.86]], - [[175.76, 0.00, 0.00], [-50.07, 0.00, 0.00], [0.00, -145.49, 0.00], [0.00, 0.61, 0.00], [0.00, 0.00, 130.21], [0.00, 0.00, -0.34]], - [[127.45, 0.00, 0.00], [-47.88, 0.00, 0.00], [0.00, -138.44, 0.00], [0.00, 15.55, 0.00], [0.00, 0.00, 125.68], [0.00, 0.00, -12.32]], - [[80.00, 0.00, 0.00], [-43.73, 0.00, 0.00], [0.00, -114.54, 0.00], [0.00, 29.79, 0.00], [0.00, 0.00, 105.71], [0.00, 0.00, -24.64]], - [[40.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -79.78, 0.00], [0.00, 51.57, 0.00], [0.00, 0.00, 77.13], [0.00, 0.00, -48.60]], - [[0.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -11.40, 0.00], [0.00, 85.18, 0.00], [0.00, 0.00, 8.51], [0.00, 0.00, -88.64]]]), + [[327.63, 0.00, 0.00], [-47.88, 0.00, 0.00], [0.00, -83.19, 0.00], [0.00, -57.84, 0.00], [0.00, 0.00, 47.36], [0.00, 0.00, 91.53]], + [[278.67, 0.00, 0.00], [-50.03, 0.00, 0.00], [0.00, -132.92, 0.00], [0.00, -41.62, 0.00], [0.00, 0.00, 114.86], [0.00, 0.00, 43.47]], + [[227.59, 0.00, 0.00], [-51.46, 0.00, 0.00], [0.00, -166.08, 0.00], [0.00, -21.12, 0.00], [0.00, 0.00, 133.26], [0.00, 0.00, 14.47]], + [[175.76, 0.00, 0.00], [-50.07, 0.00, 0.00], [0.00, -174.99, 0.00], [0.00, 0.12, 0.00], [0.00, 0.00, 143.75], [0.00, 0.00, 0.19]], + [[127.45, 0.00, 0.00], [-47.88, 0.00, 0.00], [0.00, -166.45, 0.00], [0.00, 19.22, 0.00], [0.00, 0.00, 134.33], [0.00, 0.00, -16.37]], + [[80.00, 0.00, 0.00], [-43.73, 0.00, 0.00], [0.00, -136.75, 0.00], [0.00, 35.76, 0.00], [0.00, 0.00, 111.14], [0.00, 0.00, -30.61]], + [[40.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -95.89, 0.00], [0.00, 62.54, 0.00], [0.00, 0.00, 74.28], [0.00, 0.00, -51.30]], + [[0.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -11.68, 0.00], [0.00, 105.89, 0.00], [0.00, 0.00, 8.54], [0.00, 0.00, -80.18]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, From 0db7b8772b5c24ffa55f732d4a03e2427558d8bb Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 26 Jun 2023 09:21:10 +1200 Subject: [PATCH 22/26] Removed sampling the central path. --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 8c1b5007..43c11bcf 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -1130,8 +1130,10 @@ def __init__(self, region, centralPath, elementsCountAlongDome, elementsCountAlo sd3_neck, sd13_neck = interp.interpolateSampleCubicHermite(cd3_neck, cd13_neck, se_neck, sxi_neck, ssf_neck) # Find nodes of bladder dome and neck - self.sx_dome_group = [sx_dome, sd1_dome, sd2_dome, sd12_dome, sd3_dome, sd13_dome] - self.sx_neck_group = [sx_neck, sd1_neck, sd2_neck, sd12_neck, sd3_neck, sd13_neck] + # self.sx_dome_group = [sx_dome, sd1_dome, sd2_dome, sd12_dome, sd3_dome, sd13_dome] + # self.sx_neck_group = [sx_neck, sd1_neck, sd2_neck, sd12_neck, sd3_neck, sd13_neck] + self.sx_dome_group = [cx_dome, cd1_dome, cd2_dome, cd12_dome, cd3_dome, cd13_dome] + self.sx_neck_group = [cx_neck, cd1_neck, cd2_neck, cd12_neck, cd3_neck, cd13_neck] self.domeSegmentLength = domeSegmentLength self.neckSegmentLength = neckSegmentLength From 4f7b073fc467fea3fdb6458cd443a8788a3f33b2 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 26 Jun 2023 09:23:05 +1200 Subject: [PATCH 23/26] Only using "addingLength" for transition. --- .../meshtypes/meshtype_3d_bladder1.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 43c11bcf..261114c2 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -797,18 +797,18 @@ def findNodesAlongBladderNeck(sx_dome_group, sx_neck_group, d2SampledDome, domeS # Transition transitLength = (domeSegmentLength + neckSegmentLength) / 2 addingLength = transitLength - neckSegmentLength - if transitLength <= neckSegmentLength: - e = 1 - xi = transitLength / neckSegmentLength - else: - e = int(transitLength / neckSegmentLength) + 1 - xi = transitLength / (e * neckSegmentLength) - xTransition = interp.interpolateCubicHermite(sx_dome_group[0][-1], sx_dome_group[1][-1], sx_neck_group[0][e], sx_neck_group[1][e], xi) - # d1Transition = interp.interpolateCubicHermiteDerivative(sx_dome_group[0][-1], sx_dome_group[1][-1], sx_neck_group[0][e], sx_neck_group[1][e], xi) - d2Transition = interp.interpolateCubicHermite(sx_dome_group[2][-1], sx_dome_group[3][-1], sx_neck_group[2][e], sx_neck_group[3][e], xi) - d3Transition = interp.interpolateCubicHermite(sx_dome_group[4][-1], sx_dome_group[5][-1], sx_neck_group[4][e], sx_neck_group[5][e], xi) - px_transit, pd1_transit = createEllipsePoints(xTransition, 2 * math.pi, d2Transition, d3Transition, elementsCountAround, - startRadians=0.0) + # if transitLength <= neckSegmentLength: + # e = 1 + # xi = transitLength / neckSegmentLength + # else: + # e = int(transitLength / neckSegmentLength) + 1 + # xi = transitLength / (e * neckSegmentLength) + # xTransition = interp.interpolateCubicHermite(sx_dome_group[0][-1], sx_dome_group[1][-1], sx_neck_group[0][e], sx_neck_group[1][e], xi) + # # d1Transition = interp.interpolateCubicHermiteDerivative(sx_dome_group[0][-1], sx_dome_group[1][-1], sx_neck_group[0][e], sx_neck_group[1][e], xi) + # d2Transition = interp.interpolateCubicHermite(sx_dome_group[2][-1], sx_dome_group[3][-1], sx_neck_group[2][e], sx_neck_group[3][e], xi) + # d3Transition = interp.interpolateCubicHermite(sx_dome_group[4][-1], sx_dome_group[5][-1], sx_neck_group[4][e], sx_neck_group[5][e], xi) + # px_transit, pd1_transit = createEllipsePoints(xTransition, 2 * math.pi, d2Transition, d3Transition, elementsCountAround, + # startRadians=0.0) # Create ellipses along neck around the central path xEllipses_neck = [] From 685769e0112119df7451d487514445166695507e Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 26 Jun 2023 09:25:40 +1200 Subject: [PATCH 24/26] Set d12 and d13 to be zero at the urethra junction for all species. --- src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 261114c2..eab045af 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -49,7 +49,7 @@ class MeshType_3d_bladder1(Scaffold_base): [[67.89, -25.83, 0.00], [-24.55, 10.46, 0.00], [-9.10, -21.35, 0.00], [3.43, 6.83, 0.00], [0.00, 0.00, 23.77], [0.00, 0.00, -9.22]], [[42.83, -15.79, 0.00], [-23.65, 9.48, 0.00], [-5.21, -12.99, 0.00], [2.97, 6.53, 0.00], [0.00, 0.00, 14.25], [0.00, 0.00, -7.47]], [[20.60, -6.87, 0.00], [-21.44, 7.87, 0.00], [-2.46, -6.71, 0.00], [1.91, 4.18, 0.00], [0.00, 0.00, 8.60], [0.00, 0.00, -3.79]], - [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.00], [0.38, 0.37, 0.00], [0.00, 0.00, 6.50], [0.00, 0.00, -0.41]]]), + [[0.00, 0.00, 0.00], [-19.75, 5.87, 0.00], [-1.32, -4.43, 0.00], [0.00, 0.00, 0.00], [0.00, 0.00, 6.50], [0.00, 0.00, 0.00]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -83,7 +83,7 @@ class MeshType_3d_bladder1(Scaffold_base): [[127.45, 0.00, 0.00], [-47.88, 0.00, 0.00], [0.00, -166.45, 0.00], [0.00, 19.22, 0.00], [0.00, 0.00, 134.33], [0.00, 0.00, -16.37]], [[80.00, 0.00, 0.00], [-43.73, 0.00, 0.00], [0.00, -136.75, 0.00], [0.00, 35.76, 0.00], [0.00, 0.00, 111.14], [0.00, 0.00, -30.61]], [[40.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -95.89, 0.00], [0.00, 62.54, 0.00], [0.00, 0.00, 74.28], [0.00, 0.00, -51.30]], - [[0.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -11.68, 0.00], [0.00, 105.89, 0.00], [0.00, 0.00, 8.54], [0.00, 0.00, -80.18]]]), + [[0.00, 0.00, 0.00], [-40.00, 0.00, 0.00], [0.00, -11.68, 0.00], [0.00, 0.00, 0.00], [0.00, 0.00, 8.54], [0.00, 0.00, 0.00]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -117,7 +117,7 @@ class MeshType_3d_bladder1(Scaffold_base): [[24.00, -5.00, 0.00], [-9.03, 2.93, 0.00], [-3.15, -9.72, 0.00], [1.91, 3.14, 0.00], [0.00, 0.00, 11.35], [0.00, 0.00, -3.68]], [[17.00, -3.00, 0.00], [-7.52, 1.53, 0.00], [-1.32, -6.47, 0.00], [1.34, 3.34, 0.00], [0.00, 0.00, 7.93], [0.00, 0.00, -3.51]], [[9.00, -2.00, 0.00], [-8.52, 1.48, 0.00], [-0.52, -3.02, 0.00], [0.48, 2.55, 0.00], [0.00, 0.00, 4.33], [0.00, 0.00, -3.07]], - [[0.00, 0.00, 0.00], [-9.47, 2.52, 0.00], [-0.40, -1.49, 0.00], [-0.23, 0.51, 0.00], [0.00, 0.00, 1.88], [0.00, 0.00, -1.84]]]), + [[0.00, 0.00, 0.00], [-9.47, 2.52, 0.00], [-0.40, -1.49, 0.00], [0.00, 0.00, 0.00], [0.00, 0.00, 1.88], [0.00, 0.00, 0.00]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -151,7 +151,7 @@ class MeshType_3d_bladder1(Scaffold_base): [[195.00, 86.00, 0.00], [-67.15, -38.10, 0.00], [52.84, -93.13, 0.00], [-16.53, 14.22, 0.00], [0.00, 0.00, 111.31], [0.00, 0.00, -22.57]], [[128.00, 52.00, 0.00], [-64.44, -31.46, 0.00], [32.96, -67.51, 0.00], [-19.77, 30.24, 0.00], [0.00, 0.00, 84.81], [0.00, 0.00, -32.42]], [[66.00, 23.00, 0.00], [-63.30, -25.43, 0.00], [13.28, -33.06, 0.00], [-14.97, 28.37, 0.00], [0.00, 0.00, 47.01], [0.00, 0.00, -35.97]], - [[0.00, 0.00, 0.00], [-65.62, -18.77, 0.00], [3.12, -10.89, 0.00], [-5.36, 15.97, 0.00], [0.00, 0.00, 12.91], [0.00, 0.00, -32.22]]]), + [[0.00, 0.00, 0.00], [-65.62, -18.77, 0.00], [3.12, -10.89, 0.00], [0.00, 0.00, 0.00], [0.00, 0.00, 12.91], [0.00, 0.00, 0.00]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -185,7 +185,7 @@ class MeshType_3d_bladder1(Scaffold_base): [[43.39, -17.45, 0.00], [-15.66, 7.77, 0.00], [-9.98, -20.11, 0.00], [2.59, 1.78, 0.00], [0.00, 0.00, 13.03], [0.00, 0.00, -1.94]], [[27.76, -10.60, 0.00], [-14.32, 6.11, 0.00], [-6.79, -15.92, 0.00], [3.53, 6.37, 0.00], [0.00, 0.00, 10.13], [0.00, 0.00, -3.58]], [[14.77, -5.22, 0.00], [-13.89, 5.33, 0.00], [-2.98, -7.76, 0.00], [3.01, 6.71, 0.00], [0.00, 0.00, 5.99], [0.00, 0.00, -3.81]], - [[0.00, 0.00, 0.00], [-15.64, 5.10, 0.00], [-0.87, -2.66, 0.00], [1.21, 3.47, 0.00], [0.00, 0.00, 2.55], [0.00, 0.00, -3.08]]]), + [[0.00, 0.00, 0.00], [-15.64, 5.10, 0.00], [-0.87, -2.66, 0.00], [0.00, 0.00, 0.00], [0.00, 0.00, 2.55], [0.00, 0.00, 0.00]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -219,7 +219,7 @@ class MeshType_3d_bladder1(Scaffold_base): [[0.90, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.30, 0.00], [0.00, 0.07, 0.00], [0.00, 0.00, 0.30], [0.00, 0.00, -0.10]], [[0.60, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.20, 0.00], [0.00, 0.11, 0.00], [0.00, 0.00, 0.16], [0.00, 0.00, -0.11]], [[0.30, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.08, 0.00], [0.00, 0.07, -0.00], [0.00, 0.00, 0.09], [0.00, -0.00, -0.05]], - [[0.00, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.05, 0.00], [0.00, -0.02, -0.00], [0.00, 0.00, 0.05], [0.00, -0.00, -0.03]]]), + [[0.00, 0.00, 0.00], [-0.30, 0.00, 0.00], [0.00, -0.05, 0.00], [0.00, 0.00, 0.00], [0.00, 0.00, 0.05], [0.00, 0.00, 0.00]]]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, From 27be1a28d823a2f0849adc7b2c36a89a1d29e716 Mon Sep 17 00:00:00 2001 From: Zohreh Ekhlasi Date: Mon, 26 Jun 2023 09:27:28 +1200 Subject: [PATCH 25/26] Use the same number of elements for all species. --- .../meshtypes/meshtype_3d_bladder1.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index eab045af..551e5762 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -282,19 +282,19 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Human 1' in parameterSetName: - options['Number of elements along dome'] = 10 - options['Number of elements along neck'] = 6 - options['Number of elements around'] = 12 + # options['Number of elements along dome'] = 10 + # options['Number of elements along neck'] = 6 + # options['Number of elements around'] = 12 options['Wall thickness'] = 3.0 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) if 'Mouse 1' in parameterSetName: - options['Number of elements along neck'] = 6 + # options['Number of elements along neck'] = 6 options['Wall thickness'] = 0.5 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) if 'Pig 1' in parameterSetName: - options['Number of elements along dome'] = 10 - options['Number of elements along neck'] = 5 - options['Number of elements around'] = 12 + # options['Number of elements along dome'] = 10 + # options['Number of elements along neck'] = 5 + # options['Number of elements around'] = 12 options['Wall thickness'] = 2.5 options['Ureter position around'] = 0.67 # should be on the dorsal part (> 0.5) if 'Rat 1' in parameterSetName: From c13ddbd6e458e30c6d7e2691499319b5f2a25516 Mon Sep 17 00:00:00 2001 From: Richard Christie Date: Mon, 3 Jul 2023 14:39:50 +1200 Subject: [PATCH 26/26] Create marker points using new style --- .../meshtypes/meshtype_3d_bladder1.py | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 1ccca3fe..63b6d051 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -407,7 +407,6 @@ def generateBaseMesh(cls, region, options): fm = region.getFieldmodule() fm.beginChange() - cache = fm.createFieldcache() mesh = fm.findMeshByDimension(3) firstNodeIdentifier = 1 @@ -415,7 +414,7 @@ def generateBaseMesh(cls, region, options): # Geometric coordinates geometricCentralPath = BladderCentralPath(region, centralPath, elementsCountAlongDome, elementsCountAlongNeck) - xFinal, d1Final, d2Final, d3Final = findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, + xFinal, d1Final, d2Final, d3Final = getBladderCoordinates(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, elementsCountThroughWall, wallThickness, geometricCentralPath) sx_dome_group = geometricCentralPath.sx_dome_group @@ -426,7 +425,7 @@ def generateBaseMesh(cls, region, options): # Material coordinates tmp_region = region.createRegion() materialCentralPath = BladderCentralPath(tmp_region, materialCentralPath, elementsCountAlongDome, elementsCountAlongNeck) - xOrgan, d1Organ, d2Organ, d3Organ = findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, + xOrgan, d1Organ, d2Organ, d3Organ = getBladderCoordinates(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, elementsCountThroughWall, materialWallThickness, materialCentralPath) del tmp_region @@ -463,13 +462,16 @@ def generateBaseMesh(cls, region, options): xFinal, d1Final, d2Final, bladderCentralPathLength, urethraOpeningRadius, wallThickness) # Create nodes and elements + bladderCoordinatesFieldName = "bladder coordinates" nodeIdentifier, elementIdentifier, annotationGroups = tubemesh.createNodesAndElements( - region, xFinal, d1Final, d2Final, d3Final, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, "bladder coordinates", - elementsCountAround, elementsCountAlongBladder, elementsCountThroughWall, + region, xFinal, d1Final, d2Final, d3Final, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, + bladderCoordinatesFieldName, elementsCountAround, elementsCountAlongBladder, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=True) + bladderCoordinates = fm.findFieldByName(bladderCoordinatesFieldName) + # Define trackSurface to put the ureter markers on xTrackSurface = [] d1TrackSurface = [] @@ -489,16 +491,9 @@ def generateBaseMesh(cls, region, options): ureter1Position = trackSurfaceBladder.createPositionProportion(ureterPositionAroundFactor, neckStartPositionAlongFactor) ureterElementPositionAround = ureter1Position.e1 - # Annotation fiducial point - markerGroup = findOrCreateFieldGroup(fm, "marker") - markerName = findOrCreateFieldStoredString(fm, name="marker_name") - markerLocation = findOrCreateFieldStoredMeshLocation(fm, mesh, name="marker_location") + # Annotation fiducial points nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - markerPoints = markerGroup.getOrCreateNodesetGroup(nodes) - markerTemplateInternal = nodes.createNodetemplate() - markerTemplateInternal.defineField(markerName) - markerTemplateInternal.defineField(markerLocation) # Define markers for apex and ureter junctions with bladder apexGroup = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_bladder_term("apex of urinary bladder")) @@ -519,12 +514,12 @@ def generateBaseMesh(cls, region, options): bladderNodesetGroup = bladderGroup.getNodesetGroup(nodes) for marker in markerList: annotationGroup = marker["group"] - markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) - cache.setNode(markerPoint) - markerLocation.assignMeshLocation(cache, mesh.findElementByIdentifier(marker["elementId"]), marker["xi"]) - markerName.assignString(cache, annotationGroup.getName()) - annotationGroup.getNodesetGroup(nodes).addNode(markerPoint) - bladderNodesetGroup.addNode(markerPoint) + element = mesh.findElementByIdentifier(marker["elementId"]) + # create marker points with element locations + markerNode = annotationGroup.createMarkerNode(nodeIdentifier, element=element, xi=marker["xi"]) + # calculate bladder coordinates automatically from element:xi + annotationGroup.setMarkerMaterialCoordinates(bladderCoordinates) + bladderNodesetGroup.addNode(markerNode) nodeIdentifier += 1 fm.endChange() @@ -1149,8 +1144,8 @@ def __init__(self, region, centralPath, elementsCountAlongDome, elementsCountAlo self.bladderCentralPathLength = bladderCentralPathLength self.domeLength = domeLength -def findBladderNodes3D(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, elementsCountThroughWall, - wallThickness, centralPath): +def getBladderCoordinates(elementsCountAlongDome, elementsCountAlongNeck, elementsCountAround, elementsCountThroughWall, + wallThickness, centralPath): sx_dome_group = centralPath.sx_dome_group sx_neck_group = centralPath.sx_neck_group