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

Adjust range of elements according to updated number of elements. #179

Merged
merged 6 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 37 additions & 7 deletions src/scaffoldmaker/meshtypes/meshtype_3d_solidcylinder1.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ def getDefaultOptions(cls, parameterSetName='Default'):
'Number of elements across transition': 1,
'Number of elements along': 1,
'Shell element thickness proportion': 1.0,
'Lower half': False,
'Crop number of elements across major': [0, 0],
'Crop number of elements across minor': [0, 0],
'Crop number of elements along': [0, 0],
'Use cross derivatives': False,
'Refine': False,
'Refine number of elements across major': 1,
Expand All @@ -75,7 +77,9 @@ def getOrderedOptionNames():
'Number of elements across transition',
'Number of elements along',
'Shell element thickness proportion',
'Lower half',
'Crop number of elements across major',
'Crop number of elements across minor',
'Crop number of elements along',
'Refine',
'Refine number of elements across major',
'Refine number of elements along'
Expand Down Expand Up @@ -140,6 +144,24 @@ def checkOptions(cls, options):
if options['Shell element thickness proportion'] < 0.15:
options['Shell element thickness proportion'] = 1.0

maxelems = [options['Number of elements across major'],
options['Number of elements across minor'],
options['Number of elements along']]

cropElements = [
options['Crop number of elements across major'],
options['Crop number of elements across minor'],
options['Crop number of elements along'],
]

for j in [0, 1]:
if not (1 + options['Number of elements across shell'] < cropElements[0][j] < maxelems[0]):
options['Crop number of elements across major'][j] = 0
if not (1 + options['Number of elements across shell'] < cropElements[1][j] < maxelems[1] - 1):
options['Crop number of elements across minor'][j] = 0
if not (0 <= options['Crop number of elements along'][j] < options['Number of elements along']):
options['Crop number of elements along'][j] = 0

return dependentChanges

@staticmethod
Expand All @@ -152,31 +174,39 @@ def generateBaseMesh(region, options):
"""

centralPath = options['Central path']
full = not options['Lower half']
elementsCountAcrossMajor = options['Number of elements across major']
if not full:
elementsCountAcrossMajor //= 2
elementsCountAcrossMinor = options['Number of elements across minor']
elementsCountAcrossShell = options['Number of elements across shell']
elementsCountAcrossTransition = options['Number of elements across transition']
elementsCountAlong = options['Number of elements along']
shellProportion = options['Shell element thickness proportion']
useCrossDerivatives = options['Use cross derivatives']

cropElements = [
options['Crop number of elements across major'],
options['Crop number of elements across minor'],
options['Crop number of elements along'],
]
rangeOfRequiredElements = [
[cropElements[0][0], elementsCountAcrossMajor - cropElements[0][1]],
[cropElements[1][0], elementsCountAcrossMinor - cropElements[1][1]],
[cropElements[2][0], elementsCountAlong - cropElements[2][1]],
]

fm = region.getFieldmodule()
coordinates = findOrCreateFieldCoordinates(fm)

cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong)

cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if full else CylinderShape.CYLINDER_SHAPE_LOWER_HALF
cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL

base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell,
elementsCountAcrossTransition,
shellProportion,
[0.0, 0.0, 0.0], cylinderCentralPath.alongAxis[0], cylinderCentralPath.majorAxis[0],
cylinderCentralPath.minorRadii[0])
cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base,
cylinderShape=cylinderShape,
cylinderShape=cylinderShape, rangeOfRequiredElements=rangeOfRequiredElements,
cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False)

annotationGroup = []
Expand Down
63 changes: 27 additions & 36 deletions src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ def getDefaultOptions(cls, parameterSetName='Default'):
'Radius1': 1.0,
'Radius2': 1.0,
'Radius3': 1.0,
'Range of elements required in direction 1': [0, 4],
'Range of elements required in direction 2': [0, 4],
'Range of elements required in direction 3': [0, 4],
'Crop number of elements in direction 1': [0, 0],
'Crop number of elements in direction 2': [0, 0],
'Crop number of elements in direction 3': [0, 0],
'Box derivatives': [1, 2, 3],
'Use cross derivatives': False,
'Refine': False,
Expand All @@ -57,9 +57,9 @@ def getOrderedOptionNames():
'Radius1',
'Radius2',
'Radius3',
'Range of elements required in direction 1',
'Range of elements required in direction 2',
'Range of elements required in direction 3',
'Crop number of elements in direction 1',
'Crop number of elements in direction 2',
'Crop number of elements in direction 3',
'Box derivatives',
'Refine',
'Refine number of elements'
Expand Down Expand Up @@ -95,37 +95,20 @@ def checkOptions(cls, options):
if len(options['Box derivatives']) > len(set(options['Box derivatives'])):
options['Box derivatives'] = [1, 2, 3]

for i in range(1, 4):
if options['Range of elements required in direction {}'.format(i)][1] >= \
options['Number of elements across axis {}'.format(i)] - 1\
- options['Number of elements across shell']:
options['Range of elements required in direction {}'.format(i)][1] = \
options['Number of elements across axis {}'.format(i)]

nm = 4
for i in range(1, nm):
if options['Range of elements required in direction {}'.format(i)][0] <= 1 + \
options['Number of elements across shell']:
options['Range of elements required in direction {}'.format(i)][0] = 0

maxelems = [options['Number of elements across axis 1'],
options['Number of elements across axis 2'],
options['Number of elements across axis 3']]
ranges = [options['Range of elements required in direction 1'],
options['Range of elements required in direction 2'],
options['Range of elements required in direction 3']]
for i in range(3):
if ranges[i][1] > maxelems[i] or ranges[i][1] <= max(1, ranges[i][0]):
dependentChanges = True
ranges[i][1] = maxelems[i]
for i in range(3):
if ranges[i][0] >= min(maxelems[i] - 1, ranges[i][1]) or ranges[i][0] < 1:
dependentChanges = True
ranges[i][0] = 0

options['Range of elements required in direction 1'] = ranges[0]
options['Range of elements required in direction 2'] = ranges[1]
options['Range of elements required in direction 3'] = ranges[2]
cropElements = [
options['Crop number of elements in direction 1'],
options['Crop number of elements in direction 2'],
options['Crop number of elements in direction 3'],
]

for i in range(3):
for j in [0, 1]:
if not (1 + options['Number of elements across shell'] < cropElements[i][j] < maxelems[i]):
options['Crop number of elements in direction {}'.format(i + 1)][j] = 0

elementsCount_min = min(options['Number of elements across axis 1'],
options['Number of elements across axis 2'],
Expand Down Expand Up @@ -160,9 +143,17 @@ def generateBaseMesh(region, options):
shellProportion = options['Shell element thickness proportion']
radius = [options['Radius1'], options['Radius2'], options['Radius3']]
useCrossDerivatives = options['Use cross derivatives']
rangeOfRequiredElements = [options['Range of elements required in direction 1'],
options['Range of elements required in direction 2'],
options['Range of elements required in direction 3']]

cropElements = [
options['Crop number of elements in direction 1'],
options['Crop number of elements in direction 2'],
options['Crop number of elements in direction 3'],
]
rangeOfRequiredElements = [
[cropElements[0][0], elementsCountAcrossAxis1 - cropElements[0][1]],
[cropElements[1][0], elementsCountAcrossAxis2 - cropElements[1][1]],
[cropElements[2][0], elementsCountAcrossAxis3 - cropElements[2][1]],
]
sphereBoxDerivatives = [-options['Box derivatives'][0], options['Box derivatives'][1],
options['Box derivatives'][2]] # To make the values more intuitive for the user but
# consistent with [back, right, up]
Expand Down
17 changes: 15 additions & 2 deletions src/scaffoldmaker/utils/cylindermesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class CylinderMesh:
"""

def __init__(self, fieldModule, coordinates, elementsCountAlong, base=None, end=None,
cylinderShape=CylinderShape.CYLINDER_SHAPE_FULL,
cylinderShape=CylinderShape.CYLINDER_SHAPE_FULL, rangeOfRequiredElements=None,
tapered=None, cylinderCentralPath=None, useCrossDerivatives=False , meshGroupsElementsAlong=[], meshGroups=[]):
"""
:param fieldModule: Zinc fieldModule to create elements in.
Expand All @@ -144,6 +144,8 @@ def __init__(self, fieldModule, coordinates, elementsCountAlong, base=None, end=
:param end: Cylinder end ellipse. It is an instance of class CylinderEnds.
:param elementsCountAlong: Number of elements along the cylinder axis.
:param cylinderShape: A value from enum CylinderMode specifying.
:param rangeOfRequiredElements: Specifies the range of elements required to be created. It can be used to
create the part of cylinder required. If None or same as elementsCountAcross the whole part will be created.
"""

self._centres = None
Expand Down Expand Up @@ -177,6 +179,15 @@ def __init__(self, fieldModule, coordinates, elementsCountAlong, base=None, end=
self._cylinderType = CylinderType.CYLINDER_TAPERED
self._tapered = tapered
self._useCrossDerivatives = useCrossDerivatives
if rangeOfRequiredElements:
self._rangeOfRequiredElements = rangeOfRequiredElements
else:
self._rangeOfRequiredElements = [
[0, self._elementsCountAcrossMajor],
[0, self._elementsCountAcrossMinor],
[0, self._elementsCountAlong],
]

self._meshGroups = meshGroups
self._meshGroupsElementsAlong = meshGroupsElementsAlong
self._cylinderCentralPath = cylinderCentralPath
Expand Down Expand Up @@ -380,7 +391,8 @@ def generateNodes(self, nodes, fieldModule, coordinates):
"""
nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1)
self._startNodeIdentifier = nodeIdentifier
nodeIdentifier = self._shield.generateNodes(fieldModule, coordinates, nodeIdentifier)
nodeIdentifier = self._shield.generateNodes(fieldModule, coordinates, nodeIdentifier,
self._rangeOfRequiredElements)
self._endNodeIdentifier = nodeIdentifier

def generateElements(self, mesh, fieldModule, coordinates):
Expand All @@ -393,6 +405,7 @@ def generateElements(self, mesh, fieldModule, coordinates):
elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1)
self._startElementIdentifier = elementIdentifier
elementIdentifier = self._shield.generateElements(fieldModule, coordinates, elementIdentifier,
self._rangeOfRequiredElements,
self._meshGroupsElementsAlong, self._meshGroups)
self._endElementIdentifier = elementIdentifier

Expand Down
15 changes: 13 additions & 2 deletions src/scaffoldmaker/utils/shieldmesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,13 @@ def generateNodesForOtherHalf(self, mirrorPlane):
self.pd2[n3][2*self.elementsCountUp-n2][n1] = mirror.mirrorVector(self.pd2[n3][n2][n1])
self.pd3[n3][2*self.elementsCountUp-n2][n1] = mirror.mirrorVector(self.pd3[n3][n2][n1])

def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, mirrorPlane=None):
def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, rangeOfRequiredElements, mirrorPlane=None):
"""
Create shield nodes from coordinates.
:param fieldmodule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES.
:param coordinates: Coordinate field to define.
:param startNodeIdentifier: First node identifier to use.
:param rangeOfRequiredElements: Only the elements and nodes for the given range is generated.
:param mirrorPlane: mirror plane ax+by+cz=d in form of [a,b,c,d]
:return: next nodeIdentifier.
"""
Expand All @@ -465,6 +466,10 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, mirrorPla
for n2 in range(self.elementsCountUpFull + 1):
for n3 in range(self.elementsCountAlong+1):
for n1 in range(self.elementsCountAcross + 1):
if n3 > rangeOfRequiredElements[2][1] or n3 < rangeOfRequiredElements[2][0]\
or n2 > rangeOfRequiredElements[0][1] or n2 < rangeOfRequiredElements[0][0]\
or n1 > rangeOfRequiredElements[1][1] or n1 < rangeOfRequiredElements[1][0]:
continue
if self.px[n3][n2][n1]:
node = nodes.createNode(nodeIdentifier, nodetemplate)
self.nodeId[n3][n2][n1] = nodeIdentifier
Expand All @@ -477,12 +482,14 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, mirrorPla

return nodeIdentifier

def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroupsElementsAlong=[], meshGroups=[]):
def generateElements(self, fieldmodule, coordinates, startElementIdentifier, rangeOfRequiredElements,
meshGroupsElementsAlong=[], meshGroups=[]):
"""
Create shield elements from nodes.
:param fieldmodule: Zinc fieldmodule to create elements in.
:param coordinates: Coordinate field to define.
:param startElementIdentifier: First element identifier to use.
:param rangeOfRequiredElements: Only the elements and nodes for the given range is generated.
:param meshGroups, meshGroupsElementsAlong: Zinc mesh groups to add elements to. meshGroupsElementsAlong is a
list that specifies number of elements along the cylinder to be added to the same meshGroup.
:return: next elementIdentifier.
Expand Down Expand Up @@ -522,6 +529,10 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes
for e3 in range(self.elementsCountAlong):
for e2 in range(self.elementsCountUpFull):
for e1 in range(self.elementsCountAcross):
if e3 >= rangeOfRequiredElements[2][1] or e3 < rangeOfRequiredElements[2][0] or\
e2 >= rangeOfRequiredElements[0][1] or e2 < rangeOfRequiredElements[0][0]\
or e1 >= rangeOfRequiredElements[1][1] or e1 < rangeOfRequiredElements[1][0]:
continue
eft1 = eft
scalefactors = None
if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_cylinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_cylinder1(self):
parameterSetNames = scaffold.getParameterSetNames()
self.assertEqual(parameterSetNames, ["Default"])
options = scaffold.getDefaultOptions("Default")
self.assertEqual(12, len(options))
self.assertEqual(14, len(options))
self.assertEqual(4, options.get("Number of elements across major"))
self.assertEqual(4, options.get("Number of elements across minor"))
self.assertEqual(0, options.get("Number of elements across shell"))
Expand Down
12 changes: 6 additions & 6 deletions tests/test_sphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def test_sphere1(self):
self.assertEqual(1.0, options.get("Radius2"))
self.assertEqual(1.0, options.get("Radius3"))
self.assertEqual(1.0, options.get("Shell element thickness proportion"))
self.assertEqual([0, 4], options.get("Range of elements required in direction 1"))
self.assertEqual([0, 4], options.get("Range of elements required in direction 2"))
self.assertEqual([0, 4], options.get("Range of elements required in direction 3"))
self.assertEqual([0, 0], options.get("Crop number of elements in direction 1"))
self.assertEqual([0, 0], options.get("Crop number of elements in direction 2"))
self.assertEqual([0, 0], options.get("Crop number of elements in direction 3"))
self.assertEqual([1, 2, 3], options.get("Box derivatives"))

context = Context("Test")
Expand Down Expand Up @@ -140,9 +140,9 @@ def test_sphere1(self):
options['Number of elements across axis 1'] = 4
options['Number of elements across axis 2'] = 6
options['Number of elements across axis 3'] = 8
options['Range of elements required in direction 1'] = [0, 4]
options['Range of elements required in direction 2'] = [0, 6]
options['Range of elements required in direction 3'] = [0, 8]
options['Crop number of elements in direction 1'] = [0, 0]
options['Crop number of elements in direction 2'] = [0, 0]
options['Crop number of elements in direction 3'] = [0, 0]

options['Radius1'] = 0.5
options['Radius2'] = 0.8
Expand Down