Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stomach #132

Merged
merged 40 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
94eaf10
Initial commit for stomach scaffold
mlin865 Mar 4, 2021
efd7386
Space out elements at triple point
mlin865 Apr 1, 2021
a782aab
Create parameter sets for rat and human
mlin865 Apr 2, 2021
db65d6f
Spread out elements along more evenly
mlin865 Apr 7, 2021
861e3c6
Update parameters for rat and human
mlin865 Apr 8, 2021
cdbd95e
Add annotation groups
mlin865 Apr 13, 2021
1ec8235
Create annotation groups
mlin865 Apr 15, 2021
c2945a5
Remove redundant code
mlin865 Apr 16, 2021
849119e
Allow for linear through wall
mlin865 Apr 16, 2021
84b7e7f
Add unit test for stomach and update tests for colon and small intestine
mlin865 Apr 16, 2021
3a79f61
Add markers
mlin865 Apr 16, 2021
e2103d8
Calculate position of 6 point junction using triple points function
mlin865 Apr 21, 2021
59e3875
Add annotation groups for limiting ridge
mlin865 Apr 21, 2021
7081afb
Add third marker on duodenum end on greater curvature
mlin865 Apr 21, 2021
7ecffce
Update unit tests
mlin865 Apr 21, 2021
a9adadf
Merge remote-tracking branch 'abi/master' into stomach
mlin865 Apr 21, 2021
cd703d5
Remove redundant lines and edit comments to improve clarity
mlin865 Apr 21, 2021
70bc33c
Add scale factor for wedges
mlin865 Apr 22, 2021
8c4aa1e
Annotate part of esophagus as stomach
mlin865 Apr 23, 2021
a850565
Update central path for rat stomach to show duodenum group
mlin865 Apr 23, 2021
5ee25ac
Make None into string for colon annotation terms without termIDs
mlin865 May 3, 2021
e9364b9
Update description of functions for creating wedges with collapse nodes
mlin865 May 3, 2021
d776722
Merge createEftWedgeCollapseXi2 with createEFTWedgeCollapseXi2Quadrant
mlin865 May 3, 2021
9a2b482
Replace eft.validate assert with print calls
mlin865 May 3, 2021
17d0ab0
Add description for argument collapseNodes
mlin865 May 3, 2021
7c7f869
Merge parameters to Refine number of elements surface
mlin865 May 3, 2021
92f089f
Add marker for pylorus on greater curvature
mlin865 May 3, 2021
795f073
Create annotation groups for markers
mlin865 May 4, 2021
8bd8bd6
Apply smoothing tools to central path for human stomach
mlin865 May 4, 2021
90deefc
Apply smoothing tools to central path of rat stomach
mlin865 May 4, 2021
b2c3714
Update refine number of elements surface to 4
mlin865 May 4, 2021
ff89dea
Remove number of elements through wall option until support for multi…
mlin865 May 4, 2021
2aa5557
Replace option names with annulus with cardia
mlin865 May 4, 2021
6d96760
Add esophagus to stomach annotation group
mlin865 May 4, 2021
81b54f2
Add markers to stomach group
mlin865 May 4, 2021
5e7809e
Vary cardia derivative factor to smooth transition around annulus fro…
mlin865 May 5, 2021
5914a70
Remove redundant steps
mlin865 May 5, 2021
89b9714
Correct error to improve greater curvature near fundus end
mlin865 May 5, 2021
a28f7dc
Merge remote-tracking branch 'abi/master' into stomach
mlin865 May 6, 2021
07cfc79
Update unit test for stomach
mlin865 May 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/scaffoldmaker/annotation/colon_terms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
( "colon", "UBERON:0001155", "FMA:14543", "ILX:0736005"),
( "colonic mucosa", "UBERON:0000317", "FMA:14984", "ILX:0731046"),
( "distal colon", "UBERON:0008971", "ILX:0727523"),
( "mesenteric zone", None),
( "non-mesenteric zone", None),
( "mesenteric zone", "None"),
( "non-mesenteric zone", "None"),
( "proximal colon", "UBERON:0008972", "ILX:0733240"),
( "serosa of colon", "UBERON:0003335", "FMA:14990", "ILX:0736932"),
( "spiral colon", "UBERON:0010239", "ILX:0735018"),
Expand Down
35 changes: 35 additions & 0 deletions src/scaffoldmaker/annotation/stomach_terms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Common resource for stomach annotation terms.
"""

# convention: preferred name, preferred id, followed by any other ids and alternative names
stomach_terms = [
( "body of stomach", "UBERON:0001161", " FMA:14560", "ILX:0724929"),
( "cardia of stomach", "UBERON:0001162", " FMA:14561", "ILX:0729096"),
( "duodenum", "UBERON:0002114", " FMA:7206", "ILX:0726125"),
( "duodenum on greater curvature", "None"),
( "esophagus", "UBERON:0001043", "FMA: 7131", "ILX:0735017"),
( "esophagogastric junction", "UBERON:0007650", "FMA: 9434", "ILX:0733910"),
( "forestomach-glandular stomach junction", "UBERON:0012270", "ILX:0729974"),
( "forestomach-glandular stomach junction on inner wall", "None"),
( "forestomach-glandular stomach junction on outer wall", "None"),
( "fundus of stomach", "UBERON:0001160", " FMA:14559", "ILX:0724443"),
( "gastro-esophagal junction on lesser curvature", "None"),
( "junction between fundus and body on greater curvature", "None"),
( "limiting ridge on greater curvature", "None"),
( "pylorus", "UBERON:0001166", " FMA:14581", "ILX:0734150"),
( "pyloric antrum", "UBERON:0001165", " FMA:14579", "ILX:0728672"),
( "pylorus on greater curvature", "None"),
( "stomach", "UBERON:0000945", "FMA:7148", "ILX:0736697")
]

def get_stomach_term(name : str):
"""
Find term by matching name to any identifier held for a term.
Raise exception if name not found.
:return ( preferred name, preferred id )
"""
for term in stomach_terms:
if name in term:
return ( term[0], term[1] )
raise NameError("Stomach annotation term '" + name + "' not found.")
2,528 changes: 2,528 additions & 0 deletions src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/scaffoldmaker/scaffolds.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from scaffoldmaker.meshtypes.meshtype_3d_sphereshell1 import MeshType_3d_sphereshell1
from scaffoldmaker.meshtypes.meshtype_3d_sphereshellseptum1 import MeshType_3d_sphereshellseptum1
from scaffoldmaker.meshtypes.meshtype_3d_stellate1 import MeshType_3d_stellate1
from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1
from scaffoldmaker.meshtypes.meshtype_3d_stomachhuman1 import MeshType_3d_stomachhuman1
from scaffoldmaker.meshtypes.meshtype_3d_tube1 import MeshType_3d_tube1
from scaffoldmaker.meshtypes.meshtype_3d_tubeseptum1 import MeshType_3d_tubeseptum1
Expand Down Expand Up @@ -84,6 +85,7 @@ def __init__(self):
MeshType_3d_sphereshell1,
MeshType_3d_sphereshellseptum1,
MeshType_3d_stellate1,
MeshType_3d_stomach1,
MeshType_3d_stomachhuman1,
MeshType_3d_tube1,
MeshType_3d_tubeseptum1,
Expand Down
118 changes: 118 additions & 0 deletions src/scaffoldmaker/utils/eftfactory_bicubichermitelinear.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,124 @@ def createEftWedgeXi1Zero(self):
assert eft.validate(), 'eftfactory_tricubichermite.createEftWedgeXi1Zero: Failed to validate eft'
return eft

def createEftWedgeCollapseXi1Quadrant(self, collapseNodes):
'''
Create a bicubic hermite linear element field for a wedge element collapsed in xi1.
:param collapseNodes: As the element can be collapsed in xi1 at either ends of xi2 or xi3, collapseNodes
are the local indices of nodes whose d2 (for elements collapse at either ends of xi2) or
d3 (for elements collapse at either ends of xi3) are remapped with d1 before collapsing the nodes.
:return: Element field template
'''
eft = self.createEftBasic()
setEftScaleFactorIds(eft, [1], [])

valid = True
if collapseNodes in [[1, 3], [2, 4]]: # xi3 = 0
nodes = [1, 2, 3, 4]
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, [])
ln_map = [1, 1, 2, 2, 3, 4, 5, 6]
elif collapseNodes in [[5, 7], [6, 8]]: # xi3 = 1
nodes = [5, 6, 7, 8]
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, [])
ln_map = [1, 2, 3, 4, 5, 5, 6, 6]
elif collapseNodes in [[1, 5], [2, 6]]:
nodes = [1, 2, 5, 6]
# remap parameters on xi2 = 0 before collapsing nodes
if collapseNodes == [1, 5]:
setEftScaleFactorIds(eft, [1], [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])])
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, [])
elif collapseNodes == [2, 6]:
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])])
else:
valid = False
ln_map = [1, 1, 2, 3, 4, 4, 5, 6]
elif collapseNodes in [[3, 7], [4, 8]]:
nodes = [3, 4, 7, 8]
# remap parameters on xi2 = 1 before collapsing nodes
if collapseNodes == [3, 7]:
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])])
elif collapseNodes == [4, 8]:
setEftScaleFactorIds(eft, [1], [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])])
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS1, [])
else:
valid = False
ln_map = [1, 2, 3, 3, 4, 5, 6, 6]
else:
valid = False

if not valid:
assert False, "createEftWedgeCollapseXi1Quadrant. Not implemented for collapse nodes " + str(collapseNodes)

# zero cross derivative parameters
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, [])

remapEftLocalNodes(eft, 6, ln_map)
if not eft.validate():
print('eftfactory_bicubichermitelinear.createEftWedgeCollapseXi1Quadrant: Failed to validate eft for collapseNodes', collapseNodes)
return eft

def createEftWedgeCollapseXi2Quadrant(self, collapseNodes):
'''
Create a bicubic hermite linear element field for a wedge element collapsed in xi2.
:param collapseNodes: As the element can be collapsed in xi2 at either ends of xi1 or xi3, collapseNodes
are the local indices of nodes whose d1 (for elements collapse at either ends of xi1) or
d3 (for elements collapse at either ends of xi3) are remapped with d2 before collapsing the nodes.
:return: Element field template
'''
eft = self.createEftBasic()

valid = True
if collapseNodes in [[1, 2], [3, 4]]: # xi3 = 0
nodes = [1, 2, 3, 4]
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
ln_map = [1, 2, 1, 2, 3, 4, 5, 6]
elif collapseNodes in [[5, 6], [7, 8]]: # xi3 = 1
nodes = [5, 6, 7, 8]
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
ln_map = [1, 2, 3, 4, 5, 6, 5, 6]

elif collapseNodes in [[3, 7]]:
nodes = [1, 3, 5, 7]
# remap parameters on xi1 = 0 before collapsing nodes
if collapseNodes == [3, 7]:
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])])
else:
valid = False
ln_map = [1, 2, 1, 3, 4, 5, 4, 6]

elif collapseNodes in [[2, 6], [4, 8]]:
nodes = [2, 4, 6, 8]
# remap parameters on xi1 = 1 before collapsing nodes
if collapseNodes == [2, 6]:
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])])
elif collapseNodes == [4, 8]:
setEftScaleFactorIds(eft, [1], [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])])
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
else:
valid = False
ln_map = [1, 2, 3, 2, 4, 5, 6, 5]

else:
valid = False

if not valid:
assert False, "createEftWedgeCollapseXi2Quadrant. Not implemented for collapse nodes " + str(collapseNodes)

# zero cross derivative parameters
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D2_DS1DS2, [])

remapEftLocalNodes(eft, 6, ln_map)
if not eft.validate():
print('eftfactory_bicubichermitelinear.createEftWedgeCollapseXi2Quadrant: Failed to validate eft for collapseNodes', collapseNodes)
return eft

def createEftWedgeXi1ZeroOpenTube(self):
'''
Create a basic bicubic hermite linear element template for elements
Expand Down
36 changes: 31 additions & 5 deletions src/scaffoldmaker/utils/eftfactory_tricubichermite.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,10 @@ def createEftWedgeXi1Zero(self):

def createEftWedgeCollapseXi1Quadrant(self, collapseNodes):
'''
Create a tricubic hermite element field for a wedge element, where xi1 collapsed on xi3 = 0 or xi3 = 1.
Create a tricubic hermite element field for a wedge element collapsed in xi1.
:param collapseNodes: As the element can be collapsed in xi1 at either ends of xi2 or xi3, collapseNodes
are the local indices of nodes whose d2 (for elements collapse at either ends of xi2) or
d3 (for elements collapse at either ends of xi3) are remapped with d1 before collapsing the nodes.
:return: Element field template
'''
eft = self.createEftBasic()
Expand Down Expand Up @@ -897,7 +900,10 @@ def createEftWedgeCollapseXi1Quadrant(self, collapseNodes):

def createEftWedgeCollapseXi2Quadrant(self, collapseNodes):
'''
Create a tricubic hermite element field for a wedge element, where xi2 collapsed on xi3 = 0 or Xi3 = 1.
Create a tricubic hermite element field for a wedge element collapsed in xi2.
:param collapseNodes: As the element can be collapsed in xi2 at either ends of xi1 or xi3, collapseNodes
are the local indices of nodes whose d1 (for elements collapse at either ends of xi1) or
d3 (for elements collapse at either ends of xi3) are remapped with d2 before collapsing the nodes.
:return: Element field template
'''
eft = self.createEftBasic()
Expand Down Expand Up @@ -929,11 +935,31 @@ def createEftWedgeCollapseXi2Quadrant(self, collapseNodes):
else:
valid = False
ln_map = [1, 2, 3, 4, 5, 6, 5, 6]
elif collapseNodes in [[4, 8]]:

elif collapseNodes in [[3, 7]]:
nodes = [1, 3, 5, 7]
# remap parameters on xi1 = 0 before collapsing nodes
if collapseNodes == [3, 7]:
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])])
else:
valid = False
ln_map = [1, 2, 1, 3, 4, 5, 4, 6]

elif collapseNodes in [[2, 6], [4, 8]]:
nodes = [2, 4, 6, 8]
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
remapEftNodeValueLabel(eft, [2, 6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])])
# remap parameters on xi1 = 1 before collapsing nodes
if collapseNodes == [2, 6]:
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])])
elif collapseNodes == [4, 8]:
setEftScaleFactorIds(eft, [1], [])
remapEftNodeValueLabel(eft, collapseNodes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])])
remapEftNodeValueLabel(eft, nodes, Node.VALUE_LABEL_D_DS2, [])
else:
valid = False
ln_map = [1, 2, 3, 2, 4, 5, 6, 5]

else:
valid = False

Expand Down
10 changes: 5 additions & 5 deletions tests/test_colon.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,14 @@ def test_colon1(self):
coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement()
self.assertTrue(coordinates.isValid())
minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes)
assertAlmostEqualList(self, minimums, [ 108.03959866945482, -36.876103983560014, -25.93217903595996 ], 1.0E-6)
assertAlmostEqualList(self, maximums, [ 185.43446761757468, 48.07433517752282, 34.995316052158934 ], 1.0E-6)
assertAlmostEqualList(self, minimums, [ 108.02506479907721, -36.876103983560014, -25.89741158484918 ], 1.0E-6)
assertAlmostEqualList(self, maximums, [ 185.46457506076914, 48.1011574894518, 34.995316052158934 ], 1.0E-6)

flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement()
self.assertTrue(flatCoordinates.isValid())
minimums, maximums = evaluateFieldNodesetRange(flatCoordinates, nodes)
assertAlmostEqualList(self, minimums, [ 0.0, 0.0, 0.0 ], 1.0E-6)
assertAlmostEqualList(self, maximums, [ 186.72988844629867, 75.79769125771575, 3.2000000000000006 ], 1.0E-6)
assertAlmostEqualList(self, maximums, [ 186.72988844629867, 77.41781871321301, 3.2000000000000006 ], 1.0E-6)

textureCoordinates = fieldmodule.findFieldByName("texture coordinates").castFiniteElement()
minimums, maximums = evaluateFieldNodesetRange(textureCoordinates, nodes)
Expand All @@ -136,10 +136,10 @@ def test_colon1(self):
fieldcache = fieldmodule.createFieldcache()
result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1)
self.assertEqual(result, RESULT_OK)
self.assertAlmostEqual(surfaceArea, 14623.340352853866, delta=1.0E-6)
self.assertAlmostEqual(surfaceArea, 14612.416789097502, delta=1.0E-6)
result, volume = volumeField.evaluateReal(fieldcache, 1)
self.assertEqual(result, RESULT_OK)
self.assertAlmostEqual(volume, 26869.74823158621, delta=1.0E-6)
self.assertAlmostEqual(volume, 26826.06954301569, delta=1.0E-6)

def test_mousecolon1(self):
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/test_smallintestine.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_smallintestine1(self):
Test creation of small intestine scaffold.
"""
parameterSetNames = MeshType_3d_smallintestine1.getParameterSetNames()
self.assertEqual(parameterSetNames, ["Default", "Mouse 1"])
self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Mouse 1"])
centralPathDefaultScaffoldPackages = {
'Test line': ScaffoldPackage(MeshType_1d_path1, {
'scaffoldSettings': {
Expand Down
Loading