From ff29f1bcd26cd7539a54b6599e52615c9a06d7e5 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Mon, 9 Aug 2021 16:20:58 +1200 Subject: [PATCH 01/37] Add another script for generating spheroid --- .../meshtypes/meshtype_3d_heartventricles3.py | 6 +- .../meshtypes/meshtype_3d_solidsphere2.py | 200 +++++ src/scaffoldmaker/scaffolds.py | 2 + src/scaffoldmaker/utils/cylindermesh.py | 14 +- src/scaffoldmaker/utils/shieldmesh.py | 55 +- src/scaffoldmaker/utils/spheremesh.py | 799 ++++++++++++++++++ 6 files changed, 1061 insertions(+), 15 deletions(-) create mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py create mode 100644 src/scaffoldmaker/utils/spheremesh.py diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_heartventricles3.py b/src/scaffoldmaker/meshtypes/meshtype_3d_heartventricles3.py index bcf83d9f..fbc0a71d 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_heartventricles3.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_heartventricles3.py @@ -21,7 +21,7 @@ sampleCubicHermiteCurves, sampleCubicHermiteCurvesSmooth, smoothCubicHermiteDerivativesLine from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite from scaffoldmaker.utils.meshrefinement import MeshRefinement -from scaffoldmaker.utils.shieldmesh import ShieldMesh +from scaffoldmaker.utils.shieldmesh import ShieldMesh2D from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition, calculate_surface_axes @@ -490,7 +490,7 @@ def generateBaseMesh(cls, region, options): lad1 = [ [-s for s in d ] for d in lad1 ] lad3 = [ vector.setMagnitude(d, lvFreeWallThickness) for d in lad3 ] - rvShield = ShieldMesh(elementsCountAroundRVFreeWall, elementsCountUpRVFreeWall, 0) + rvShield = ShieldMesh2D(elementsCountAroundRVFreeWall, elementsCountUpRVFreeWall, 0) rvx = rvShield.px rvd1 = rvShield.pd1 rvd2 = rvShield.pd2 @@ -601,7 +601,7 @@ def generateBaseMesh(cls, region, options): # LV free wall elementsCountUpLV = elementsCountUpLVFreeWall + elementsCountUpLVApex - lvShield = ShieldMesh(elementsCountAroundLVFreeWall, elementsCountUpLV, elementsCountUpLVApex, lvTrackSurface) + lvShield = ShieldMesh2D(elementsCountAroundLVFreeWall, elementsCountUpLV, elementsCountUpLVApex, lvTrackSurface) lvx = lvShield.px lvd1 = lvShield.pd1 lvd2 = lvShield.pd2 diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py new file mode 100644 index 00000000..e1dfd562 --- /dev/null +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -0,0 +1,200 @@ +""" +Generates a solid sphere using a ShieldMesh of all cube elements, + with variable numbers of elements across axes and shell directions. +""" + +from __future__ import division +import math +import copy +from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates +from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base +from scaffoldmaker.utils.meshrefinement import MeshRefinement +# from scaffoldmaker.utils.cylindermesh import CylinderMesh, CylinderShape, CylinderEnds, CylinderCentralPath +from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues +from scaffoldmaker.scaffoldpackage import ScaffoldPackage +from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from opencmiss.zinc.node import Node + + +class MeshType_3d_solidsphere2(Scaffold_base): + """ +Generates a solid sphere using a ShieldMesh of all cube elements, +with variable numbers of elements across axes and shell directions. + """ + # centralPathDefaultScaffoldPackages = { + # 'Cylinder 1': ScaffoldPackage(MeshType_1d_path1, { + # 'scaffoldSettings': { + # 'Coordinate dimensions': 3, + # 'D2 derivatives': True, + # 'D3 derivatives': True, + # 'Length': 3.0, + # 'Number of elements': 3 + # }, + # 'meshEdits': exnodeStringFromNodeValues( + # [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + # Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + # [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], + # [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], + # [[0.0, 0.0, 2.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], + # [[0.0, 0.0, 3.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]] + # ]) + # }) + # } + + @staticmethod + def getName(): + return '3D Solid Sphere 2' + + @classmethod + def getDefaultOptions(cls, parameterSetName='Default'): + # centralPathOption = cls.centralPathDefaultScaffoldPackages['Cylinder 1'] + options = { + # 'Central path': copy.deepcopy(centralPathOption), + 'Number of elements across axis 1': 2, + 'Number of elements across axis 2': 2, + 'Number of elements across axis 3': 2, + 'Number of elements across shell': 0, + 'Number of elements across transition': 1, + # 'Number of elements along': 1, + 'Shell element thickness proportion': 1.0, + # 'Lower half': False, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements across major': 1, + 'Refine number of elements along': 1 + } + return options + + @staticmethod + def getOrderedOptionNames(): + return [ + # 'Central path', + 'Number of elements across axis 1', + 'Number of elements across axis 2', + 'Number of elements across axis 3', + 'Number of elements across shell', + 'Number of elements across transition', + # 'Number of elements along', + 'Shell element thickness proportion', + # 'Lower half', + 'Refine', + 'Refine number of elements across major', + 'Refine number of elements along' + ] + + @classmethod + def getOptionValidScaffoldTypes(cls, optionName): + if optionName == 'Central path': + return [MeshType_1d_path1] + return [] + + @classmethod + def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): + if optionName == 'Central path': + return list(cls.centralPathDefaultScaffoldPackages.keys()) + assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ + cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ + 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() + return scaffoldType.getParameterSetNames() + + @classmethod + def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): + ''' + :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. + :return: ScaffoldPackage. + ''' + if parameterSetName: + assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ + 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() + if optionName == 'Central path': + if not parameterSetName: + parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] + return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' + + @classmethod + def checkOptions(cls, options): + if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + dependentChanges = False + + # if options['Number of elements across major'] < 4: + # options['Number of elements across major'] = 4 + # if options['Number of elements across major'] % 2: + # options['Number of elements across major'] += 1 + # + # if options['Number of elements across minor'] < 4: + # options['Number of elements across minor'] = 4 + # if options['Number of elements across minor'] % 2: + # options['Number of elements across minor'] += 1 + # if options['Number of elements along'] < 1: + # options['Number of elements along'] = 1 + # if options['Number of elements across transition'] < 1: + # options['Number of elements across transition'] = 1 + # Rcrit = min(options['Number of elements across major']-4, options['Number of elements across minor']-4)//2 + # if options['Number of elements across shell'] + options['Number of elements across transition'] - 1 > Rcrit: + # dependentChanges = True + # options['Number of elements across shell'] = Rcrit + # options['Number of elements across transition'] = 1 + # + # if options['Shell element thickness proportion'] < 0.15: + # options['Shell element thickness proportion'] = 1.0 + + return dependentChanges + + @staticmethod + def generateBaseMesh(region, options): + """ + Generate the base tricubic Hermite mesh. See also generateMesh(). + :param region: Zinc region to define model in. Must be empty. + :param options: Dict containing options. See getDefaultOptions(). + :return: None + """ + + # centralPath = options['Central path'] + # full = not options['Lower half'] + elementsCountAcrossAxis1 = options['Number of elements across axis 1'] + elementsCountAcrossAxis2 = options['Number of elements across axis 2'] + elementsCountAcrossAxis3 = options['Number of elements across axis 3'] + # if not full: + # elementsCountAcrossMajor //= 2 + # elementsCountAcrossMinor = options['Number of elements across minor'] + elementsCountAcrossShell = options['Number of elements across shell'] + elementsCountAcrossTransition = options['Number of elements across transition'] + # elementsCountAlong = options['Number of elements along'] + shellProportion = options['Shell element thickness proportion'] + useCrossDerivatives = options['Use cross derivatives'] + + fm = region.getFieldmodule() + coordinates = findOrCreateFieldCoordinates(fm) + + # cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong) + + # cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if full else CylinderShape.CYLINDER_SHAPE_LOWER_HALF + + # base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, + # elementsCountAcrossTransition, + # shellProportion, + # [0.0, 0.0, 0.0], cylinderCentralPath.alongAxis[0], cylinderCentralPath.majorAxis[0], + # cylinderCentralPath.minorRadii[0]) + # cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base, + # cylinderShape=cylinderShape, + # cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) + + annotationGroup = [] + return annotationGroup + + @classmethod + def refineMesh(cls, meshRefinement, options): + """ + Refine source mesh into separate region, with change of basis. + :param meshRefinement: MeshRefinement, which knows source and target region. + :param options: Dict containing options. See getDefaultOptions(). + """ + assert isinstance(meshRefinement, MeshRefinement) + refineElementsCountAcrossAxis1 = options['Refine number of elements across axis1'] + refineElementsCountAcrossAxis2 = options['Refine number of elements across axis2'] + refineElementsCountAcrossAxis3 = options['Refine number of elements across axis3'] + # refineElementsCountAlong = options['Refine number of elements along'] + meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcrossAxis1, refineElementsCountAcrossAxis2, refineElementsCountAcrossAxis3) diff --git a/src/scaffoldmaker/scaffolds.py b/src/scaffoldmaker/scaffolds.py index 87a34088..9a159714 100644 --- a/src/scaffoldmaker/scaffolds.py +++ b/src/scaffoldmaker/scaffolds.py @@ -35,6 +35,7 @@ from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1 from scaffoldmaker.meshtypes.meshtype_3d_smallintestine1 import MeshType_3d_smallintestine1 from scaffoldmaker.meshtypes.meshtype_3d_solidsphere1 import MeshType_3d_solidsphere1 +from scaffoldmaker.meshtypes.meshtype_3d_solidsphere2 import MeshType_3d_solidsphere2 from scaffoldmaker.meshtypes.meshtype_3d_solidcylinder1 import MeshType_3d_solidcylinder1 from scaffoldmaker.meshtypes.meshtype_3d_sphereshell1 import MeshType_3d_sphereshell1 from scaffoldmaker.meshtypes.meshtype_3d_sphereshellseptum1 import MeshType_3d_sphereshellseptum1 @@ -83,6 +84,7 @@ def __init__(self): MeshType_3d_ostium1, MeshType_3d_smallintestine1, MeshType_3d_solidsphere1, + MeshType_3d_solidsphere2, MeshType_3d_solidcylinder1, MeshType_3d_sphereshell1, MeshType_3d_sphereshellseptum1, diff --git a/src/scaffoldmaker/utils/cylindermesh.py b/src/scaffoldmaker/utils/cylindermesh.py index 5652cbf4..8c015a2a 100644 --- a/src/scaffoldmaker/utils/cylindermesh.py +++ b/src/scaffoldmaker/utils/cylindermesh.py @@ -9,7 +9,7 @@ import math from opencmiss.zinc.field import Field from opencmiss.utils.zinc.finiteelement import getMaximumNodeIdentifier, getMaximumElementIdentifier -from scaffoldmaker.utils.shieldmesh import ShieldMesh, ShieldShape, ShieldRimDerivativeMode +from scaffoldmaker.utils.shieldmesh import ShieldMesh2D, ShieldShape2D, ShieldRimDerivativeMode from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, interpolateSampleCubicHermite, \ smoothCubicHermiteDerivativesLine, interpolateSampleLinear from opencmiss.zinc.node import Node @@ -213,11 +213,11 @@ def createCylinderMesh3d(self, fieldModule, coordinates): elementsCountRim = self._elementsCountAcrossRim - shieldMode = ShieldShape.SHIELD_SHAPE_FULL if self._cylinderShape is self._cylinderShape.CYLINDER_SHAPE_FULL \ - else ShieldShape.SHIELD_SHAPE_LOWER_HALF + shieldMode = ShieldShape2D.SHIELD_SHAPE_FULL if self._cylinderShape is self._cylinderShape.CYLINDER_SHAPE_FULL \ + else ShieldShape2D.SHIELD_SHAPE_LOWER_HALF ellipseShape = EllipseShape.Ellipse_SHAPE_FULL \ if self._cylinderShape is self._cylinderShape.CYLINDER_SHAPE_FULL else EllipseShape.Ellipse_SHAPE_LOWER_HALF - self._shield = ShieldMesh(self._elementsCountAcrossMinor, self._elementsCountAcrossMajor, elementsCountRim, + self._shield = ShieldMesh2D(self._elementsCountAcrossMinor, self._elementsCountAcrossMajor, elementsCountRim, None, self._elementsCountAlong, shieldMode, shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND) @@ -424,9 +424,9 @@ def __init__(self, centre, majorAxis, minorAxis, self.coreMajorRadius = coreMajorRadius self.coreMinorRadius = coreMinorRadius elementsCountRim = elementsCountAcrossShell + elementsCountAcrossTransition - 1 - shieldMode = ShieldShape.SHIELD_SHAPE_FULL if ellipseShape is EllipseShape.Ellipse_SHAPE_FULL\ - else ShieldShape.SHIELD_SHAPE_LOWER_HALF - shield = ShieldMesh(elementsCountAcrossMinor, elementsCountAcrossMajor, elementsCountRim, + shieldMode = ShieldShape2D.SHIELD_SHAPE_FULL if ellipseShape is EllipseShape.Ellipse_SHAPE_FULL\ + else ShieldShape2D.SHIELD_SHAPE_LOWER_HALF + shield = ShieldMesh2D(elementsCountAcrossMinor, elementsCountAcrossMajor, elementsCountRim, None, 1, shieldMode, shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND) self.elementsCountAcrossMajor = elementsCountAcrossMajor diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 4822a09a..2188fafd 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -18,21 +18,66 @@ from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition, calculate_surface_axes from enum import Enum -class ShieldShape(Enum): +class ShieldShape2D(Enum): SHIELD_SHAPE_FULL = 1 SHIELD_SHAPE_LOWER_HALF = 2 +class ShieldShape3D(Enum): + SHIELD_SHAPE_FULL = 1 + SHIELD_SHAPE_HALF_NNP = 2 # NNP is a3>=3 + SHIELD_SHAPE_OCTANT_PPP = 3 # in a right hand coordinate system (a1,a2,a3), PPP means a1>=0, a2>=0 and a3>=0 + class ShieldRimDerivativeMode(Enum): SHIELD_RIM_DERIVATIVE_MODE_AROUND = 1 # rim derivatives are d1 anticlockwise around shield, d3 outward SHIELD_RIM_DERIVATIVE_MODE_REGULAR = 2 # rim derivatives d1, d2 match interior nodes for regular elements -class ShieldMesh: +class ShieldMesh3D: + ''' + Generates a 3D shield mesh. + ''' + + def __init__(self, elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3, elementsCountRim, + shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP): + ''' + Parameters + ''' + assert elementsCountRim >= 0 + # assert elementsCountAlong >= 1 + # assert elementsCountAcross >= (elementsCountRim + 4) + # assert elementsCountUpFull >= (elementsCountRim + 2) + self.elementsCountAcrossAcrossAxis1 = elementsCountAcrossAxis1 + self.elementsCountAcrossAcrossAxis2 = elementsCountAcrossAxis2 + self.elementsCountAcrossAcrossAxis3 = elementsCountAcrossAxis3 + # self.elementsCountUpFull = elementsCountUpFull + # elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL else elementsCountUpFull + # self.elementsCountUp = elementsCountUp + self.elementsCountRim = elementsCountRim + # self.elementsCountAlong = elementsCountAlong + # self.elementsCountUpRegular = elementsCountUp - 2 - elementsCountRim + # elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim + # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim + self._mode = shieldMode + + # self.px = [ [] for _ in range(elementsCountAlong+1) ] + # self.pd1 = [ [] for _ in range(elementsCountAlong+1) ] + # self.pd2 = [ [] for _ in range(elementsCountAlong+1) ] + # self.pd3 = [ [] for _ in range(elementsCountAlong+1) ] + # self.nodeId = [ [] for _ in range(elementsCountAlong+1) ] + # for n3 in range(elementsCountAlong+1): + # for n2 in range(elementsCountUpFull + 1): + # for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: + # p.append([ None ]*(elementsCountAcross + 1)) + # + # self.elementId = [ [[ None ]*elementsCountAcross for n2 in range(elementsCountUpFull)] for e3 in range(elementsCountAlong) ] + + +class ShieldMesh2D: ''' Shield mesh generator. ''' def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, trackSurface : TrackSurface=None, - elementsCountAlong=1, shieldMode=ShieldShape.SHIELD_SHAPE_LOWER_HALF, shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR): + elementsCountAlong=1, shieldMode=ShieldShape2D.SHIELD_SHAPE_LOWER_HALF, shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR): ''' Data structure for defining a shield-shaped mesh which is flat on the top and rounded around the bottom and/or the same mirror mirrored on top. @@ -68,7 +113,7 @@ def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, t assert elementsCountUpFull >= (elementsCountRim + 2) self.elementsCountAcross = elementsCountAcross self.elementsCountUpFull = elementsCountUpFull - elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape.SHIELD_SHAPE_FULL else elementsCountUpFull + elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL else elementsCountUpFull self.elementsCountUp = elementsCountUp self.elementsCountRim = elementsCountRim self.elementsCountAlong = elementsCountAlong @@ -362,7 +407,7 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan # s += str(n1) if self.px[1][n2][n1] else " " # print(n2, s, n2 - self.elementsCountUp - 1) - if self._mode == ShieldShape.SHIELD_SHAPE_FULL and mirrorPlane: + if self._mode == ShieldShape2D.SHIELD_SHAPE_FULL and mirrorPlane: self.generateNodesForOtherHalf(mirrorPlane) for n2 in range(self.elementsCountUpFull + 1): diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py new file mode 100644 index 00000000..1a19a12e --- /dev/null +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -0,0 +1,799 @@ +""" +Utility functions for generating a 3-D solid spheroid. It can be used to generate +a solid sphere. +""" + +from enum import Enum +from scaffoldmaker.utils import vector, geometry +import math +from opencmiss.zinc.field import Field +from opencmiss.utils.zinc.finiteelement import getMaximumNodeIdentifier, getMaximumElementIdentifier +from scaffoldmaker.utils.shieldmesh import ShieldMesh2D, ShieldShape2D, ShieldRimDerivativeMode +from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, interpolateSampleCubicHermite, \ + smoothCubicHermiteDerivativesLine, interpolateSampleLinear +from opencmiss.zinc.node import Node +from scaffoldmaker.utils.mirror import Mirror +from scaffoldmaker.meshtypes.meshtype_1d_path1 import extractPathParametersFromRegion + + +class SphereShape(Enum): + SPHERE_SHAPE_FULL = 1 # full sphere is created + SPHERE_SHAPE_LOWER_HALF = 2 # lower half sphere + + +# class EllipseShape(Enum): +# Ellipse_SHAPE_FULL = 1 # full ellipse is created +# Ellipse_SHAPE_LOWER_HALF = 2 # lower half ellipse + + +class CylinderEnds: + """ + Stores base ellipse parameters. + """ + + def __init__(self, elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell=0, + elementsCountAcrossTransition=1, shellProportion=1.0, + centre=None, alongAxis=None, majorAxis=None, minorRadius=None): + """ + :param elementsCountAcrossMajor: Number of elements across major axis. Must be at least 2 + elementsCountRim for + half and 4 + elementsCountRim for full cylinder. + :param elementsCountAcrossMinor: Number of elements across minor axis. + :param elementsCountAcrossShell: Number of elements across shell. + :param elementsCountAcrossTransition: Number of elements between core boundary and inner square. + :param shellProportion: Ratio of thickness of each layer in shell wrt thickness of each layer in core. + :param centre: Centre of the ellipse. + :param alongAxis: The cylinder axis that the base is extruded along. + :param majorAxis: The major axis of the base. Should be perpendicular to alongAxis + :param minorRadius: The minor radius of the ellipse. + """ + self._centre = centre + self._alongAxis = alongAxis + self._majorAxis = majorAxis + self._minorRadius = minorRadius + if alongAxis: + self._minorAxis = vector.setMagnitude(vector.crossproduct3(alongAxis, majorAxis), minorRadius) + self._elementsCountAcrossMinor = elementsCountAcrossMinor + self._elementsCountAcrossMajor = elementsCountAcrossMajor + self._elementsCountAcrossShell = elementsCountAcrossShell + self._elementsCountAcrossTransition = elementsCountAcrossTransition + self._shellProportion = shellProportion + self._majorRadius = vector.magnitude(majorAxis) + self.px = None + self.pd1 = None + self.pd2 = None + self.pd3 = None + + +# class CylinderCentralPath: +# """ +# Stores ellipses parameters a long the central path. +# """ +# +# def __init__(self, region, centralPath, elementsCount): +# """ +# :param region: Zinc region to define model in. +# :param centralPath: Central path subscaffold comes from meshtype_1d_path1 and used to calculate ellipse radii. +# :param elementsCount: Number of elements needs to be sampled along the central path. +# """ +# tmpRegion = region.createRegion() +# centralPath.generate(tmpRegion) +# cx, cd1, cd2, cd3, cd12, cd13 = extractPathParametersFromRegion(tmpRegion, +# [Node.VALUE_LABEL_VALUE, +# Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, +# Node.VALUE_LABEL_D_DS3, +# Node.VALUE_LABEL_D2_DS1DS2, +# Node.VALUE_LABEL_D2_DS1DS3]) +# del tmpRegion +# # for i in range(len(cx)): +# # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') +# +# sx, sd1, se, sxi, ssf = sampleCubicHermiteCurves(cx, cd1, elementsCount) +# sd2, sd12 = interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) +# sd3, sd13 = interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) +# +# self.centres = sx +# self.majorRadii = [vector.magnitude(a) for a in sd2] +# self.majorAxis = sd2 +# self.minorRadii = [vector.magnitude(a) for a in sd3] +# self.minorAxis = sd3 +# self.alongAxis = sd1 + + +class SphereMesh: + """ + Cylinder mesh generator. Extrudes an ellipse/circle. + """ + + def __init__(self, fieldModule, coordinates, elementsCountAlong, base=None, end=None, + cylinderShape=SphereShape.SPHERE_SHAPE_FULL, + tapered=None, cylinderCentralPath=None, useCrossDerivatives=False): + """ + :param fieldModule: Zinc fieldModule to create elements in. + :param coordinates: Coordinate field to define. + :param base: Cylinder base ellipse. It is an instance of class CylinderEnds. + :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. + """ + + self._centres = None + self._majorAxis = None + self._minorAxis = None + self._majorRadii = None + self._minorRadii = None + self._coreMajorRadii = [] + self._coreMinorRadii = [] + self._base = base + self._end = end + self._shield = None + self._elementsCountAcrossMinor = base._elementsCountAcrossMinor + self._elementsCountAcrossMajor = base._elementsCountAcrossMajor + self._elementsCountUp = base._elementsCountAcrossMajor // 2 \ + if cylinderShape == SphereShape.Sphere_SHAPE_FULL else base._elementsCountAcrossMajor + self._elementsCountAcrossShell = base._elementsCountAcrossShell + self._elementsCountAcrossTransition = base._elementsCountAcrossTransition + self._elementsCountAcrossRim = self._elementsCountAcrossShell + self._elementsCountAcrossTransition - 1 + self._shellProportion = base._shellProportion + self._elementsCountAlong = elementsCountAlong + self._elementsCountAround = 2 * (self._elementsCountAcrossMajor+self._elementsCountAcrossMinor - + 4*(self._elementsCountAcrossRim + 1)) + self._startNodeIdentifier = 1 + self._startElementIdentifier = 1 + self._endNodeIdentifier = 1 + self._endElementIdentifier = 1 + self._cylinderShape = cylinderShape + # self._cylinderType = CylinderType.CYLINDER_STRAIGHT + if (tapered is not None) or cylinderCentralPath: + self._cylinderType = CylinderType.CYLINDER_TAPERED + self._tapered = tapered + self._useCrossDerivatives = useCrossDerivatives + self._cylinderCentralPath = cylinderCentralPath + if cylinderCentralPath: + self.calculateEllipseParams(cylinderCentralPath=self._cylinderCentralPath) + self._base = CylinderEnds(base._elementsCountAcrossMajor, base._elementsCountAcrossMinor, + base._elementsCountAcrossShell, base._elementsCountAcrossTransition, + base._shellProportion, self._centres[0], + None, self._majorAxis[0], self._minorRadii[0]) + else: + self._length = vector.magnitude(base._alongAxis) + arcLengthAlong = self._length / elementsCountAlong + self.calculateEllipseParams(arcLengthAlong, cylinderCentralPath=self._cylinderCentralPath) + + # generate the mesh + self.createCylinderMesh3d(fieldModule, coordinates) + + def createCylinderMesh3d(self, fieldModule, coordinates): + """ + Create an extruded shape (ellipse/circle) mesh. Currently limited to ellipse or circle base with the alongAxis + perpendicular to the base. + :param fieldModule: Zinc fieldModule to create elements in. + :param coordinates: Coordinate field to define. + :return: Final values of nextNodeIdentifier, nextElementIdentifier. + """ + assert (self._elementsCountAlong > 0), 'createCylinderMesh3d: Invalid number of along elements' + assert (self._elementsCountAcrossMinor > 3), 'createCylinderMesh3d: Invalid number of across elements' + assert (self._elementsCountAcrossMinor % 2 == 0), 'createCylinderMesh3d: number of across elements' \ + ' is not an even number' + assert (self._elementsCountAcrossMajor > 1), 'createCylinderMesh3d: Invalid number of up elements' + assert (self._cylinderShape in [self._cylinderShape.CYLINDER_SHAPE_FULL, + self._cylinderShape.CYLINDER_SHAPE_LOWER_HALF]), \ + 'createCylinderMesh3d: Invalid cylinder mode.' + + nodes = fieldModule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + mesh = fieldModule.findMeshByDimension(3) + + elementsCountRim = self._elementsCountAcrossRim + + shieldMode = ShieldShape2D.SHIELD_SHAPE_FULL if self._cylinderShape is self._cylinderShape.CYLINDER_SHAPE_FULL \ + else ShieldShape2D.SHIELD_SHAPE_LOWER_HALF + ellipseShape = EllipseShape.Ellipse_SHAPE_FULL \ + if self._cylinderShape is self._cylinderShape.CYLINDER_SHAPE_FULL else EllipseShape.Ellipse_SHAPE_LOWER_HALF + self._shield = ShieldMesh2D(self._elementsCountAcrossMinor, self._elementsCountAcrossMajor, elementsCountRim, + None, self._elementsCountAlong, shieldMode, + shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND) + + # generate ellipses mesh along cylinder axis + n3Count = 0 if self._cylinderType == CylinderType.CYLINDER_STRAIGHT else self._elementsCountAlong + self._ellipses = [] + for n3 in range(n3Count + 1): + ellipse = Ellipse2D(self._centres[n3], self._majorAxis[n3], self._minorAxis[n3], + self._elementsCountAcrossMajor, self._elementsCountAcrossMinor, self._elementsCountAcrossShell, + self._elementsCountAcrossTransition, + self._shellProportion, self._coreMajorRadii[n3], self._coreMinorRadii[n3], + ellipseShape=ellipseShape) + self._ellipses.append(ellipse) + self.copyEllipsesNodesToShieldNodes(n3) + + for n3 in range(n3Count + 1): + self.calculateD2Derivatives(n3, n3Count) + + if self._cylinderType == CylinderType.CYLINDER_TAPERED: + self.smoothd2Derivatives() + + # The other ellipses for a straight cylinder. + if self._cylinderType == CylinderType.CYLINDER_STRAIGHT: + arcLengthAlong = vector.magnitude(self._base._alongAxis) / self._elementsCountAlong + for n2 in range(self._elementsCountUp + 1): + for n3 in range(self._elementsCountAlong + 1): + for n1 in range(self._elementsCountAcrossMinor + 1): + if self._shield.px[0][n2][n1]: + temx = [self._shield.px[0][n2][n1][c] + n3 * arcLengthAlong * + vector.normalise(self._base._alongAxis)[c] for c in range(3)] + self._shield.px[n3][n2][n1] = temx + self._shield.pd1[n3][n2][n1] = self._shield.pd1[0][n2][n1] + self._shield.pd2[n3][n2][n1] = self._shield.pd2[0][n2][n1] + self._shield.pd3[n3][n2][n1] = self._shield.pd3[0][n2][n1] + + self.generateNodes(nodes, fieldModule, coordinates) + self.generateElements(mesh, fieldModule, coordinates) + + if self._end is None: + self._end = CylinderEnds(self._elementsCountAcrossMajor, self._elementsCountAcrossMinor, + self._elementsCountAcrossShell, self._elementsCountAcrossTransition, + self._shellProportion, + self._centres[-1], self._shield.pd2[-1][0][1], + vector.setMagnitude(self._base._majorAxis, self._majorRadii[-1]), + self._minorRadii[-1]) + self.setEndsNodes() + + def calculateD2Derivatives(self, n3, n3Count): + """ + calculate d2 derivatives. + :param n3: Index of along cylinder axis coordinates to use + :param n3Count: number of bases to create coordinates for. + """ + btx = self._shield.px + btd1 = self._shield.pd1 + btd2 = self._shield.pd2 + btd3 = self._shield.pd3 + # get ellipse d2 and next ellipse x, d2 + for n2 in range(self._elementsCountAcrossMajor + 1): + for n1 in range(self._elementsCountAcrossMinor + 1): + if btd1[n3][n2][n1]: + n3n = n3 if (n3 < n3Count) else n3 - 1 + btd2[n3][n2][n1] = [(btx[n3n + 1][n2][n1][c] - btx[n3n][n2][n1][c]) for c in range(3)] + + def smoothd2Derivatives(self): + """ + smooth d2 derivatives using initial values calculated by calculateD2Derivatives + """ + btx = self._shield.px + btd1 = self._shield.pd1 + btd2 = self._shield.pd2 + btd3 = self._shield.pd3 + for n2 in range(self._elementsCountAcrossMajor + 1): + for n1 in range(self._elementsCountAcrossMinor + 1): + td2 = [] + tx = [] + if btx[0][n2][n1]: + for n3 in range(self._elementsCountAlong + 1): + tx.append(btx[n3][n2][n1]) + td2.append(btd2[n3][n2][n1]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True) + for n3 in range(self._elementsCountAlong + 1): + btd2[n3][n2][n1] = td2[n3] + + def setEndsNodes(self): + """ + sets ellipse coordinates, derivatives and node ids. + """ + self._base.px = self._shield.px[0] + self._base.pd1 = self._shield.pd1[0] + self._base.pd2 = self._shield.pd2[0] + self._base.pd3 = self._shield.pd3[0] + self._end.px = self._shield.px[-1] + self._end.pd1 = self._shield.pd1[-1] + self._end.pd2 = self._shield.pd2[-1] + self._end.pd3 = self._shield.pd3[-1] + + def calculateEllipseParams(self, arcLengthAlong=None, cylinderCentralPath=None): + """ + Calculate the ellipses major and minor radii, major and minor axis and ellipses centres. + :param arcLengthAlong: arc length along the cylinder axis. Only if cylinderCentralPath is false. + :param cylinderCentralPath: Stores radii and centres of the ellipses along the cylinder length + """ + if not cylinderCentralPath: + self._centres = [self._base._centre for _ in range(self._elementsCountAlong+1)] + self._majorAxis = [self._base._majorAxis for _ in range(self._elementsCountAlong+1)] + self._minorAxis = [self._base._minorAxis for _ in range(self._elementsCountAlong+1)] + self._majorRadii = [self._base._majorRadius for _ in range(self._elementsCountAlong+1)] + self._minorRadii = [self._base._minorRadius for _ in range(self._elementsCountAlong+1)] + if cylinderCentralPath: + self._centres = cylinderCentralPath.centres + self._majorAxis = cylinderCentralPath.majorAxis + self._minorAxis = cylinderCentralPath.minorAxis + self._majorRadii = cylinderCentralPath.majorRadii + self._minorRadii = cylinderCentralPath.minorRadii + + elementsMinor = self._elementsCountAcrossMinor//2 - self._elementsCountAcrossShell*(1-self._shellProportion) + elementsMajor = self._elementsCountUp - self._elementsCountAcrossShell*(1-self._shellProportion) + for n3 in range(self._elementsCountAlong + 1): + self._coreMinorRadii.append((1-self._shellProportion*self._elementsCountAcrossShell/elementsMinor)*self._minorRadii[n3]) + self._coreMajorRadii.append((1-self._shellProportion*self._elementsCountAcrossShell/elementsMajor)*self._majorRadii[n3]) + + if self._cylinderType == CylinderType.CYLINDER_TAPERED and not cylinderCentralPath: + centre = self._base._centre + majorRadius = self._base._majorRadius + minorRadius = self._base._minorRadius + for n3 in range(1, self._elementsCountAlong+1): + majorRadius, majorAxis = computeNextRadius(majorRadius, self._base._majorAxis, + self._tapered.majorRatio, + self._tapered.majorProgressionMode) + minorRadius, minorAxis = computeNextRadius(minorRadius, self._base._minorAxis, + self._tapered.minorRatio, + self._tapered.minorProgressionMode) + centre = computeNextCentre(centre, arcLengthAlong, self._base._alongAxis) + self._centres[n3] = centre + self._majorAxis[n3] = majorAxis + self._minorAxis[n3] = minorAxis + self._majorRadii[n3] = majorRadius + self._minorRadii[n3] = minorRadius + + def copyEllipsesNodesToShieldNodes(self, n3): + """ + Copy coordinates and derivatives of ellipses to shield. + :param n3: the index number of ellipse along the central path. + """ + self._shield.px[n3] = self._ellipses[n3].px + self._shield.pd1[n3] = self._ellipses[n3].pd1 + self._shield.pd2[n3] = self._ellipses[n3].pd2 + self._shield.pd3[n3] = self._ellipses[n3].pd3 + + def generateNodes(self, nodes, fieldModule, coordinates): + """ + Create cylinder nodes from coordinates. + :param nodes: nodes from coordinates. + :param fieldModule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. + :param coordinates: Coordinate field to define. + """ + nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) + self._startNodeIdentifier = nodeIdentifier + nodeIdentifier = self._shield.generateNodes(fieldModule, coordinates, nodeIdentifier) + self._endNodeIdentifier = nodeIdentifier + + def generateElements(self, mesh, fieldModule, coordinates): + """ + Create cylinder elements from nodes. + :param mesh: + :param fieldModule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. + :param coordinates: Coordinate field to define. + """ + elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1) + self._startElementIdentifier = elementIdentifier + elementIdentifier = self._shield.generateElements(fieldModule, coordinates, elementIdentifier, []) + self._endElementIdentifier = elementIdentifier + + def getElementsCountAround(self): + return self._elementsCountAround + + def getElementIdentifiers(self): + return self._shield.elementId + + +class Ellipse2D: + """ + Generate a 2D ellipse. + """ + + def __init__(self, centre, majorAxis, minorAxis, + elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, + elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, + ellipseShape=EllipseShape.Ellipse_SHAPE_FULL): + """ + :param centre: Ellipse centre. + :param majorAxis: A vector for ellipse major axis. + :param minorAxis: Ellipse minor axis. + :param elementsCountAcrossMajor: + :param elementsCountAcrossMinor: + :param ellipseShape: The shape of the ellipse which can be full or lower half. + """ + self.centre = centre + self.majorAxis = majorAxis + self.minorAxis = minorAxis + self.majorRadius = vector.magnitude(majorAxis) + self.minorRadius = vector.magnitude(minorAxis) + self.coreMajorRadius = coreMajorRadius + self.coreMinorRadius = coreMinorRadius + elementsCountRim = elementsCountAcrossShell + elementsCountAcrossTransition - 1 + shieldMode = ShieldShape2D.SHIELD_SHAPE_FULL if ellipseShape is EllipseShape.Ellipse_SHAPE_FULL\ + else ShieldShape2D.SHIELD_SHAPE_LOWER_HALF + shield = ShieldMesh2D(elementsCountAcrossMinor, elementsCountAcrossMajor, elementsCountRim, + None, 1, shieldMode, + shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND) + self.elementsCountAcrossMajor = elementsCountAcrossMajor + self.elementsCountAround = shield.elementsCountAroundFull + self.elementsCountUp = shield.elementsCountUp + self.elementsCountAcrossMinor = elementsCountAcrossMinor + self.elementsCountAcrossShell = elementsCountAcrossShell + self.elementsCountAcrossTransition = elementsCountAcrossTransition + self.elementsCountAcrossRim = elementsCountRim + self.shellProportion = shellProportion + self.nodeId = shield.nodeId + self.px = shield.px[0] + self.pd1 = shield.pd1[0] + self.pd2 = shield.pd2[0] + self.pd3 = shield.pd3[0] + self.__shield = shield + self.ellipseShape = ellipseShape + # generate the ellipse + self.generate2DEllipseMesh() + + def generate2DEllipseMesh(self): + """ + Generates a 2d ellipse using shield structure in shieldmesh. + """ + self.generateBase1DMesh(0) + if self.elementsCountAcrossShell > 0: + self.generateBase1DMesh(self.elementsCountAcrossShell) + self.setRimNodes() + rscx, rscd1, rscd2, rscd3 = self.createMirrorCurve() + self.createRegularRowCurves(rscx, rscd1, rscd3) + self.createRegularColumnCurves() + self.__shield.getTriplePoints(0) + self.smoothTriplePointsCurves() + self.smoothTransitionRims() + if self.ellipseShape == EllipseShape.Ellipse_SHAPE_FULL: + self.generateNodesForUpperHalf() + + def generateBase1DMesh(self, rx): + """ + Generate nodes around the perimeter of the ellipse. + """ + btx = self.px + btd1 = self.pd1 + btd2 = self.pd2 + btd3 = self.pd3 + + ratio = rx/self.elementsCountAcrossShell if self.elementsCountAcrossShell > 0 else 0 + majorAxis = [d*(1 - ratio*(1-self.coreMajorRadius/self.majorRadius)) for d in self.majorAxis] + minorAxis = [d*(1 - ratio*(1-self.coreMinorRadius/self.minorRadius)) for d in self.minorAxis] + majorRadius = vector.magnitude(majorAxis) + + nx, nd1 = createEllipsePerimeter( + self.centre, majorAxis, minorAxis, self.elementsCountAround, majorRadius) + nte = normalToEllipse(self.majorAxis, self.minorAxis) + + tbx, tbd1, tbd2, tbd3 = [], [], [], [] + for n in range(self.elementsCountAround + 1): + tbx.append(nx[n]) + tbd1.append(nd1[n]) + tbd2.append(nte) + tbd3.append(vector.normalise(vector.crossproduct3(tbd1[n], nte))) + + for n in range(self.elementsCountAround + 1): + n1, n2 = self.__shield.convertRimIndex(n, rx) + btx[n2][n1] = tbx[n] + btd1[n2][n1] = tbd1[n] + btd2[n2][n1] = tbd2[n] + btd3[n2][n1] = tbd3[n] + + def setRimNodes(self): + """ + Set nodes around the shell outer layer and core boundary in order needed for creating a shield mesh. + """ + btx = self.px + btd1 = self.pd1 + btd2 = self.pd2 + btd3 = self.pd3 + # + elementsCountShell = self.elementsCountAcrossShell + for n in range(self.elementsCountAround + 1): + if self.elementsCountAcrossShell > 1: + n1, n2 = self.__shield.convertRimIndex(n) + n1c, n2c = self.__shield.convertRimIndex(n, self.elementsCountAcrossShell) + tx, td3, pe, pxi, psf = sampleCubicHermiteCurves([btx[n2c][n1c], btx[n2][n1]], + [btd3[n2c][n1c], btd3[n2][n1]], elementsCountShell, + arcLengthDerivatives=True) + + for rx in range(1, self.elementsCountAcrossShell): + n1rx, n2rx = self.__shield.convertRimIndex(n, rx) + btx[n2rx][n1rx] = tx[-rx + elementsCountShell] + btd1[n2rx][n1rx] = btd1[n2][n1] + btd2[n2rx][n1rx] = btd2[n2][n1] + btd3[n2rx][n1rx] = btd3[n2][n1] + + for rx in range(1, self.elementsCountAcrossShell): + self.__shield.smoothDerivativesAroundRim(0, n3d=None, rx=rx) + + def createMirrorCurve(self): + """ + generate coordinates and derivatives for the mirror curve + :return: Coordinates and derivatives for the mirror curve + """ + btx = self.px + btd1 = self.pd1 + btd2 = self.pd2 + btd3 = self.pd3 + + n2a = self.elementsCountAcrossShell + rcx = [] + tmdx = btx[n2a][self.elementsCountAcrossMinor // 2] + tmdd3 = btd3[n2a][self.elementsCountAcrossMinor // 2] + tmux = [ + 0.5 * (btx[self.elementsCountUp][0][c] + btx[self.elementsCountUp][self.elementsCountAcrossMinor] + [c]) for c in range(3)] + rcx.append(tmdx) + rcx.append(tmux) + rcd3 = [vector.setMagnitude(tmdd3, -1), vector.setMagnitude(tmdd3, -1)] + rscx, rscd1 = sampleCubicHermiteCurves(rcx, rcd3, self.elementsCountUp - n2a, arcLengthDerivatives=True)[0:2] + + # get d2, d3 + rscd2 = [] + rscd3 = [] + for n in range(len(rscx)): + d3 = vector.normalise( + [btx[self.elementsCountUp][self.elementsCountAcrossMinor][c] - btx[self.elementsCountUp][0] + [c] for c in range(3)]) + d2 = vector.normalise(vector.crossproduct3(d3, rscd1[n])) + rscd2.append(d2) + rscd3.append(d3) + + return rscx, rscd1, rscd2, rscd3 + + def createRegularRowCurves(self, rscx, rscd1, rscd3): + """ + generate curves along regular rows using the mirror curve obtained from createMirrorCurve. + :param rscx: Coordinates of the nodes on the middle curve. + :param rscd1: d1 derivatives of the nodes on the middle curve. + :param rscd3: d3 derivatives of the nodes on the middle curve. + """ + btx = self.px + btd1 = self.pd1 + btd2 = self.pd2 + btd3 = self.pd3 + + elementsCountRim = self.elementsCountAcrossRim + n2a = self.elementsCountAcrossShell + n2b = elementsCountRim + n2d = n2b + 2 + n2m = self.elementsCountUp + n1a = self.elementsCountAcrossShell + n1b = elementsCountRim + n1z = self.elementsCountAcrossMinor - self.elementsCountAcrossShell + for n2 in range(n2d, n2m + 1): + txm, td3m, pe, pxi, psf = sampleCubicHermiteCurves( + [btx[n2][n1a], rscx[n2 - n2a], btx[n2][n1z]], + [vector.setMagnitude(btd3[n2][n1a], -1.0), rscd3[n2 - n2a], btd3[n2][n1z]], + self.elementsCountAcrossMinor-2*self.elementsCountAcrossShell, arcLengthDerivatives=True) + td1m = interpolateSampleCubicHermite([[-btd1[n2][n1a][c] for c in range(3)], rscd1[n2 - n2a], + btd1[n2][n1z]], [[0.0, 0.0, 0.0]] * 3, pe, pxi, psf)[0] + + tx = [] + td3 = [] + for n1 in range(self.elementsCountAcrossMinor + 1): + if n1 <= n1a: + tx.append(btx[n2][n1]) + td3.append([-btd3[n2][n1][c] for c in range(3)]) + elif (n1 > n1a) and (n1 < n1z): + tx.append(txm[n1 - n1a]) + td3.append(td3m[n1 - n1a]) + else: + tx.append(btx[n2][n1]) + td3.append((btd3[n2][n1])) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + + for n1 in range(self.elementsCountAcrossMinor + 1): + if n1 <= n1a: + btd3[n2][n1] = [-td3[n1][c] for c in range(3)] + elif (n1 > n1a) and (n1 < n1z): + btx[n2][n1] = tx[n1] + if n2 == n2m: + if n1 <= n1b: + btd1[n2][n1] = vector.setMagnitude(btd1[n2m][-1], -1.0) + else: + btd1[n2][n1] = vector.setMagnitude(btd1[n2m][-1], 1.0) + else: + if n1 <= n1b: + btd1[n2][n1] = [-d for d in td1m[n1 - n1a]] + else: + btd1[n2][n1] = td1m[n1 - n1a] + if n1 <= n1b: + btd3[n2][n1] = [-d for d in td3[n1]] + else: + btd3[n2][n1] = td3[n1] + else: + btd3[n2][n1] = td3[n1] + + def createRegularColumnCurves(self): + """ + up regular columns of shield: get d1, initial d3 below regular rows + """ + btx = self.px + btd1 = self.pd1 + btd2 = self.pd2 + btd3 = self.pd3 + + elementsCountRim = self.elementsCountAcrossRim + n1d = elementsCountRim + 2 + n1x = self.elementsCountAcrossMinor - elementsCountRim - 1 + n2a = self.elementsCountAcrossShell + n2b = elementsCountRim + n2d = 2 + n2b + n2m = self.elementsCountUp + for n1 in range(n1d, n1x): + txm, td1m, pe, pxi, psf = sampleCubicHermiteCurves( + [btx[n2a][n1], btx[n2d][n1]], [[-btd3[n2a][n1][c] for c in range(3)], btd1[n2d][n1]], + 2 + self.elementsCountAcrossTransition - 1, arcLengthDerivatives=True) + td3m = interpolateSampleCubicHermite([btd1[n2a][n1], btd3[n2d][n1]], [[0.0, 0.0, 0.0]] * 2, pe, pxi, psf)[0] + + tx = [] + td1 = [] + for n2 in range(n2m + 1): + if n2 <= n2a: + tx.append(btx[n2][n1]) + td1.append([-btd3[n2][n1][c] for c in range(3)]) + elif (n2 > n2a) and (n2 < n2d): + tx.append(txm[n2 - n2a]) + td1.append(td1m[n2 - n2a]) + else: + tx.append(btx[n2][n1]) + td1.append(btd1[n2][n1]) + + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) + + for n2 in range(n2m + 1): + if n2 <= n2a: + btd3[n2][n1] = [-td1[n2][c] for c in range(3)] + elif (n2 > n2a) and (n2 < n2d): + btx[n2][n1] = tx[n2] + if n2 <= n2b: + btd1[n2][n1] = td3m[n2 - n2a] + btd3[n2][n1] = [-d for d in td1[n2]] + else: + btd1[n2][n1] = td1[n2] + btd3[n2][n1] = td3m[n2 - n2a] + else: + btd1[n2][n1] = td1[n2] + + def smoothTriplePointsCurves(self): + """ + Smooth row and column curves passing triple points (i.e., row 1 and columns 1 and -2). + """ + btx = self.px + btd1 = self.pd1 + btd2 = self.pd2 + btd3 = self.pd3 + + n1c = 1 + self.elementsCountAcrossRim + n1y = self.elementsCountAcrossMinor - self.elementsCountAcrossRim + n1x = n1y - 1 + n2a = self.elementsCountAcrossShell + n2c = 1 + self.elementsCountAcrossRim + n2m = self.elementsCountUp + + # smooth shield row n2c + btd3[n2c][n1c:n1y] = smoothCubicHermiteDerivativesLine(btx[n2c][n1c:n1y], btd3[n2c][n1c:n1y]) + + # smooth Shield columns n1c, n1x + for n1 in [n1c, n1x]: + tx = [] + td1 = [] + for n2 in range(n2c, n2m + 1): + tx.append(btx[n2][n1]) + td1.append(btd1[n2][n1]) + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True, fixStartDerivative=True) + for n in range(n2m-n2c+1): + btd1[n + n2c][n1] = td1[n] + + # sample nodes to triple points + for n1 in [n1c, n1x]: + c1 = 1 if n1 == n1c else -1 + txm, td3m, pe, pxi, psf = sampleCubicHermiteCurves( + [btx[n2a][n1], btx[n2c][n1]], [[-btd3[n2a][n1][c] for c in range(3)], + [btd1[n2c][n1][c] + c1 * btd3[n2c][n1][c] for c in range(3)]], + 1 + self.elementsCountAcrossTransition - 1, arcLengthDerivatives=True) + td1m = interpolateSampleCubicHermite([btd1[n2a][n1], [-c1*d for d in btd1[n2c][n1]]], [[0.0, 0.0, 0.0]] * 2, pe, pxi, psf)[0] + + for n2 in range(n2a + 1, n2c): + btx[n2][n1] = txm[n2 - n2a] + btd1[n2][n1] = td1m[n2 - n2a] + btd3[n2][n1] = [-d for d in td3m[n2 - n2a]] + + # smooth + self.__shield.smoothDerivativesToTriplePoints(0, fixAllDirections=True) + + def smoothTransitionRims(self): + """ + smooth rims in the transition zone + """ + n2a = self.elementsCountAcrossShell + n2b = self.elementsCountAcrossRim + for rx in range(n2a + 1, n2b + 1): + self.__shield.smoothDerivativesAroundRim(0, n3d=None, rx=rx) + + def generateNodesForUpperHalf(self): + """ + Generates coordinates and derivatives for the upper half by mirroring the lower half nodes and derivatives. + It keeps the d1 direction. + It uses mirrorPlane: plane ax+by+cz=d in form of [a,b,c,d] + """ + mirrorPlane = [-d for d in self.majorAxis] + [-vector.dotproduct(self.majorAxis, self.centre)] + mirror = Mirror(mirrorPlane) + for n2 in range(self.elementsCountUp): + for n1 in range(self.elementsCountAcrossMinor + 1): + if self.px[n2][n1]: + self.px[2 * self.elementsCountUp - n2][n1] = mirror.mirrorImageOfPoint( + self.px[n2][n1]) + self.pd1[2 * self.elementsCountUp - n2][n1] = mirror.reverseMirrorVector( + self.pd1[n2][n1]) + self.pd3[2 * self.elementsCountUp - n2][n1] = mirror.mirrorVector( + self.pd3[n2][n1]) + + +def createEllipsePerimeter(centre, majorAxis, minorAxis, elementsCountAround, height): + """ + Generate a set of points and derivatives for an ellipse + starting at pole majorAxis from centre. + :param elementsCountAround: Number of elements around. + :param centre: Centre of full ellipse. + :param majorAxis: Vector in direction of starting major radius, magnitude is ellipse major radius. + :param minorAxis: Vector normal to major axis, magnitude is ellipse minor axis length. + :param height: Height of arc of ellipsoid from starting point along majorAxis. + :return: Lists nx, nd1. Ordered fastest around, starting at major radius. + """ + nx = [] + nd1 = [] + magMajorAxis = vector.magnitude(majorAxis) + magMinorAxis = vector.magnitude(minorAxis) + unitMajorAxis = vector.normalise(majorAxis) + unitMinorAxis = vector.normalise(minorAxis) + useHeight = min(max(0.0, height), 2.0 * magMajorAxis) + totalRadians = geometry.getEllipseRadiansToX(magMajorAxis, 0.0, magMajorAxis - useHeight, + initialTheta=0.5 * math.pi * useHeight / magMajorAxis) + radians = 0.0 + arcLengthUp = geometry.getEllipseArcLength(magMajorAxis, magMinorAxis, radians, totalRadians) + elementsCountUp = elementsCountAround // 2 + elementArcLength = arcLengthUp / elementsCountUp + radians = geometry.updateEllipseAngleByArcLength(magMajorAxis, magMinorAxis, radians, -arcLengthUp) + for n1 in range(2 * elementsCountUp + 1): + cosRadians = math.cos(radians) + sinRadians = math.sin(radians) + nx.append( + [(centre[c] + cosRadians * majorAxis[c] + sinRadians * minorAxis[c]) for c in range(3)]) + + ndab = vector.setMagnitude([-sinRadians * magMajorAxis, cosRadians * magMinorAxis], elementArcLength) + nd1.append( + [(ndab[0] * unitMajorAxis[c] + ndab[1] * unitMinorAxis[c]) for c in range(3)]) + radians = geometry.updateEllipseAngleByArcLength(magMajorAxis, magMinorAxis, radians, elementArcLength) + return nx, nd1 + + +def normalToEllipse(v1, v2): + """ + Find unit normal vector of an ellipse using two vectors in the ellipse. The direction is v1xv2 + :param v1: vector 1. + :param v2: vector 2. + :return: + """ + nte = vector.normalise(vector.crossproduct3(v1, v2)) + return nte + + +def computeNextRadius(radius, axis, ratio, progression): + """ + calculate next radius based on the progression method. r_n+1=r_n*ratio for geometric. r_n+1=r_ratio for arithmetic. + :param radius: radius (major or minor) along the central path. + :param axis: major or minor axis along the central path. + :param ratio: common ratio (common difference) for changing the next radius. + :param progression: arithmetic or geometric. + :return: next radius and axis. + """ + if progression == ConeBaseProgression.GEOMETRIC_PROGRESSION: + radius = radius * ratio + elif progression == ConeBaseProgression.ARITHMETIC_PROGRESSION: + radius += ratio + axis = vector.setMagnitude(axis, radius) + return radius, axis + + +def computeNextCentre(centre, arcLength, axis): + """ + compute next centre coordinate + :param axis: + :param arcLength: the length to go forward. + :param centre: the start centre. + :return: next centre coordinates. + """ + centre = [centre[c]+arcLength * vector.normalise(axis)[c] for c in range(3)] + return centre From d26e115cceb334685bf9f807b4a3eabed04877ab Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Mon, 23 Aug 2021 09:56:35 +1200 Subject: [PATCH 02/37] Create a 2X2X2 octant. Everything is hard coded and there is an issue to be fixed. --- .../meshtypes/meshtype_3d_solidsphere2.py | 29 +- src/scaffoldmaker/utils/cylindermesh.py | 3 + src/scaffoldmaker/utils/shieldmesh.py | 210 +++- src/scaffoldmaker/utils/spheremesh.py | 919 ++++-------------- 4 files changed, 407 insertions(+), 754 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index e1dfd562..7a0921ff 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -14,6 +14,11 @@ from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 from opencmiss.zinc.node import Node +from opencmiss.zinc.field import Field +from scaffoldmaker.utils.spheremesh import SphereMesh, SphereShape +from scaffoldmaker.utils.cylindermesh import Ellipse2D, EllipseShape +from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D + class MeshType_3d_solidsphere2(Scaffold_base): @@ -115,8 +120,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + # if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): + # options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) dependentChanges = False # if options['Number of elements across major'] < 4: @@ -169,18 +174,16 @@ def generateBaseMesh(region, options): fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) - # cylinderCentralPath = CylinderCentralPath(region, centralPath, elementsCountAlong) - - # cylinderShape = CylinderShape.CYLINDER_SHAPE_FULL if full else CylinderShape.CYLINDER_SHAPE_LOWER_HALF + centre = [0.0, 0.0, 0.0] + axis1 = [1.0, 0.0, 0.0] + axis2 = [0.0, 1.0, 0.0] + axis3 = [0.0, 0.0, 1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - # base = CylinderEnds(elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, - # elementsCountAcrossTransition, - # shellProportion, - # [0.0, 0.0, 0.0], cylinderCentralPath.alongAxis[0], cylinderCentralPath.majorAxis[0], - # cylinderCentralPath.minorRadii[0]) - # cylinder1 = CylinderMesh(fm, coordinates, elementsCountAlong, base, - # cylinderShape=cylinderShape, - # cylinderCentralPath=cylinderCentralPath, useCrossDerivatives=False) + sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) annotationGroup = [] return annotationGroup diff --git a/src/scaffoldmaker/utils/cylindermesh.py b/src/scaffoldmaker/utils/cylindermesh.py index 8c015a2a..676a5170 100644 --- a/src/scaffoldmaker/utils/cylindermesh.py +++ b/src/scaffoldmaker/utils/cylindermesh.py @@ -749,6 +749,9 @@ def generateNodesForUpperHalf(self): self.pd3[2 * self.elementsCountUp - n2][n1] = mirror.mirrorVector( self.pd3[n2][n1]) + def getShield(self): + return self.__shield + def createEllipsePerimeter(centre, majorAxis, minorAxis, elementsCountAround, height): """ diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 2188fafd..b960510f 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -36,7 +36,7 @@ class ShieldMesh3D: Generates a 3D shield mesh. ''' - def __init__(self, elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3, elementsCountRim, + def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP): ''' Parameters @@ -45,9 +45,8 @@ def __init__(self, elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsC # assert elementsCountAlong >= 1 # assert elementsCountAcross >= (elementsCountRim + 4) # assert elementsCountUpFull >= (elementsCountRim + 2) - self.elementsCountAcrossAcrossAxis1 = elementsCountAcrossAxis1 - self.elementsCountAcrossAcrossAxis2 = elementsCountAcrossAxis2 - self.elementsCountAcrossAcrossAxis3 = elementsCountAcrossAxis3 + self.elementsCountAcross = elementsCountAcross + # self.elementsCountUpFull = elementsCountUpFull # elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL else elementsCountUpFull # self.elementsCountUp = elementsCountUp @@ -58,17 +57,198 @@ def __init__(self, elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsC # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim self._mode = shieldMode - # self.px = [ [] for _ in range(elementsCountAlong+1) ] - # self.pd1 = [ [] for _ in range(elementsCountAlong+1) ] - # self.pd2 = [ [] for _ in range(elementsCountAlong+1) ] - # self.pd3 = [ [] for _ in range(elementsCountAlong+1) ] - # self.nodeId = [ [] for _ in range(elementsCountAlong+1) ] - # for n3 in range(elementsCountAlong+1): - # for n2 in range(elementsCountUpFull + 1): - # for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: - # p.append([ None ]*(elementsCountAcross + 1)) - # - # self.elementId = [ [[ None ]*elementsCountAcross for n2 in range(elementsCountUpFull)] for e3 in range(elementsCountAlong) ] + self.px = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.pd1 = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.pd2 = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.pd3 = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.nodeId = [ [] for _ in range(elementsCountAcross[2] + 1) ] + for n3 in range(elementsCountAcross[2] + 1): + for n2 in range(elementsCountAcross[0] + 1): + for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: + p.append([ None ]*(elementsCountAcross[1] + 1)) + + self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] + + def getQudaruplePoint(self): + """ + + :return: + """ + n1a = 1 + n2a = 1 + n3a = 1 + n2b = self.elementsCountAcross[0] + x = [self.px[0][n2a][n1a][0],self.px[n3a][n2b][n1a][1],self.px[n3a][n2a][0][2]] + self.px[n3a][n2a][n1a] = [c for c in x] + self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2b][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + + def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,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 mirrorPlane: mirror plane ax+by+cz=d in form of [a,b,c,d] + :return: next nodeIdentifier. + """ + nodeIdentifier = startNodeIdentifier + nodes = fieldmodule.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) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + cache = fieldmodule.createFieldcache() + + #for n2 in range(self.elementsCountUp, -1, -1): + # s = "" + # for n1 in range(self.elementsCountAcross + 1): + # s += str(n1) if self.px[1][n2][n1] else " " + # print(n2, s, n2 - self.elementsCountUp - 1) + + # if self._mode == ShieldShape2D.SHIELD_SHAPE_FULL and mirrorPlane: + # self.generateNodesForOtherHalf(mirrorPlane) + + for n2 in range(self.elementsCountAcross[0] + 1): + for n3 in range(self.elementsCountAcross[2] + 1): + for n1 in range(self.elementsCountAcross[1] + 1): + if self.px[n3][n2][n1]: + node = nodes.createNode(nodeIdentifier, nodetemplate) + self.nodeId[n3][n2][n1] = nodeIdentifier + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, self.px [n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, self.pd1[n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, self.pd2[n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, self.pd3[n3][n2][n1]) + nodeIdentifier += 1 + + return nodeIdentifier + + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, 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 meshGroups: Zinc mesh groups to add elements to. + :return: next elementIdentifier. + """ + elementIdentifier = startElementIdentifier + useCrossDerivatives = False + mesh = fieldmodule.findMeshByDimension(3) + + tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) + eft = tricubichermite.createEftNoCrossDerivatives() + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) + elementtemplate.defineField(coordinates, -1, eft) + + elementtemplate1 = mesh.createElementtemplate() + elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + # isEven = (self.elementsCountAcross % 2) == 0 + e1a = self.elementsCountRim + for e3 in range(self.elementsCountAcross[2]): + for e2 in range(self.elementsCountAcross[0]): + for e1 in range(self.elementsCountAcross[1]): + eft1 = eft + scalefactors = None + if e3==0 and e2==1 and e1==0: + nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], + self.nodeId[e3][e2][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+1][e2][e1+1],self.nodeId[e3+1][e2+1][e1+1]] + elif e3==0 and e2==1 and e1==1: + nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], + self.nodeId[e3][e2-1][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2-1][e1+1],self.nodeId[e3+2][e2+1][e1+1]] + + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1,[8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + + elif e3==0 and e2==0 and e1==0: + nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], + self.nodeId[e3][e2][e1+2],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2][e1+2],self.nodeId[e3+1][e2+1][e1+1]] + + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) + + elif e3 == 1 and e2 == 1 and e1 == 0: + nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3][e2-1][e1], self.nodeId[e3+1][e2+1][e1], + self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2-1][e1+2], self.nodeId[e3+1][e2+1][e1+2]] + + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + + + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + + + + else: + continue + + + if eft1 is not eft: + elementtemplate1.defineField(coordinates, -1, eft1) + element = mesh.createElement(elementIdentifier, elementtemplate1) + else: + element = mesh.createElement(elementIdentifier, elementtemplate) + result2 = element.setNodesByIdentifier(eft1, nids) + if scalefactors: + result3 = element.setScaleFactors(eft1, scalefactors) + else: + result3 = 7 + + self.elementId[e3][e2][e1] = elementIdentifier + + elementIdentifier += 1 + + return elementIdentifier class ShieldMesh2D: diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 1a19a12e..4ffdd722 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -1,6 +1,5 @@ """ -Utility functions for generating a 3-D solid spheroid. It can be used to generate -a solid sphere. +Utility functions for generating a solid spheroid. """ from enum import Enum @@ -8,336 +7,239 @@ import math from opencmiss.zinc.field import Field from opencmiss.utils.zinc.finiteelement import getMaximumNodeIdentifier, getMaximumElementIdentifier -from scaffoldmaker.utils.shieldmesh import ShieldMesh2D, ShieldShape2D, ShieldRimDerivativeMode +from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D, ShieldRimDerivativeMode from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, interpolateSampleCubicHermite, \ smoothCubicHermiteDerivativesLine, interpolateSampleLinear from opencmiss.zinc.node import Node from scaffoldmaker.utils.mirror import Mirror from scaffoldmaker.meshtypes.meshtype_1d_path1 import extractPathParametersFromRegion +from scaffoldmaker.utils.cylindermesh import Ellipse2D, EllipseShape class SphereShape(Enum): - SPHERE_SHAPE_FULL = 1 # full sphere is created - SPHERE_SHAPE_LOWER_HALF = 2 # lower half sphere - - -# class EllipseShape(Enum): -# Ellipse_SHAPE_FULL = 1 # full ellipse is created -# Ellipse_SHAPE_LOWER_HALF = 2 # lower half ellipse - - -class CylinderEnds: - """ - Stores base ellipse parameters. - """ - - def __init__(self, elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell=0, - elementsCountAcrossTransition=1, shellProportion=1.0, - centre=None, alongAxis=None, majorAxis=None, minorRadius=None): - """ - :param elementsCountAcrossMajor: Number of elements across major axis. Must be at least 2 + elementsCountRim for - half and 4 + elementsCountRim for full cylinder. - :param elementsCountAcrossMinor: Number of elements across minor axis. - :param elementsCountAcrossShell: Number of elements across shell. - :param elementsCountAcrossTransition: Number of elements between core boundary and inner square. - :param shellProportion: Ratio of thickness of each layer in shell wrt thickness of each layer in core. - :param centre: Centre of the ellipse. - :param alongAxis: The cylinder axis that the base is extruded along. - :param majorAxis: The major axis of the base. Should be perpendicular to alongAxis - :param minorRadius: The minor radius of the ellipse. - """ - self._centre = centre - self._alongAxis = alongAxis - self._majorAxis = majorAxis - self._minorRadius = minorRadius - if alongAxis: - self._minorAxis = vector.setMagnitude(vector.crossproduct3(alongAxis, majorAxis), minorRadius) - self._elementsCountAcrossMinor = elementsCountAcrossMinor - self._elementsCountAcrossMajor = elementsCountAcrossMajor - self._elementsCountAcrossShell = elementsCountAcrossShell - self._elementsCountAcrossTransition = elementsCountAcrossTransition - self._shellProportion = shellProportion - self._majorRadius = vector.magnitude(majorAxis) - self.px = None - self.pd1 = None - self.pd2 = None - self.pd3 = None - - -# class CylinderCentralPath: -# """ -# Stores ellipses parameters a long the central path. -# """ -# -# def __init__(self, region, centralPath, elementsCount): -# """ -# :param region: Zinc region to define model in. -# :param centralPath: Central path subscaffold comes from meshtype_1d_path1 and used to calculate ellipse radii. -# :param elementsCount: Number of elements needs to be sampled along the central path. -# """ -# tmpRegion = region.createRegion() -# centralPath.generate(tmpRegion) -# cx, cd1, cd2, cd3, cd12, cd13 = extractPathParametersFromRegion(tmpRegion, -# [Node.VALUE_LABEL_VALUE, -# Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, -# Node.VALUE_LABEL_D_DS3, -# Node.VALUE_LABEL_D2_DS1DS2, -# Node.VALUE_LABEL_D2_DS1DS3]) -# del tmpRegion -# # for i in range(len(cx)): -# # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], ',', cd3[i], ',', cd13[i], '],') -# -# sx, sd1, se, sxi, ssf = sampleCubicHermiteCurves(cx, cd1, elementsCount) -# sd2, sd12 = interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) -# sd3, sd13 = interpolateSampleCubicHermite(cd3, cd13, se, sxi, ssf) -# -# self.centres = sx -# self.majorRadii = [vector.magnitude(a) for a in sd2] -# self.majorAxis = sd2 -# self.minorRadii = [vector.magnitude(a) for a in sd3] -# self.minorAxis = sd3 -# self.alongAxis = sd1 - + SPHERE_SHAPE_FULL = 1 + SPHERE_SHAPE_HALF_NNP = 2 # NNP is a3>=3 + SPHERESHIELD_SHAPE_OCTANT_PPP = 3 class SphereMesh: """ - Cylinder mesh generator. Extrudes an ellipse/circle. + Sphere mesh generator. """ - def __init__(self, fieldModule, coordinates, elementsCountAlong, base=None, end=None, - cylinderShape=SphereShape.SPHERE_SHAPE_FULL, - tapered=None, cylinderCentralPath=None, useCrossDerivatives=False): + def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. - :param base: Cylinder base ellipse. It is an instance of class CylinderEnds. - :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. - """ - - self._centres = None - self._majorAxis = None - self._minorAxis = None - self._majorRadii = None - self._minorRadii = None - self._coreMajorRadii = [] - self._coreMinorRadii = [] - self._base = base - self._end = end + :param centre, axes: centre and axes of the sphere. + :param elementsCountAcross: [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] Total number of elements + across the sphere axes. + :param elementsCountAcrossShell, elementsCountAcrossTransition: Total number of elements across each axis + consists of regular elements in the middle cube, transition elements from cube to a sphere (core boundary) + and shell elements around it. Shell nodes and derivatives are similar to the core boundary and don't need + remapping. The topology of the shield structure is extended to 3D with a quadruple points. + :param sphereShape: A value from enum sphereMode specifying. Octant_PPP for example, is the octant in axis1>=0 + axis2>=0 and axis3>=0 + """ + + self._axes = axes + self._radius = [vector.magnitude(axis) for axis in axes] + self._coreRadius = [] self._shield = None - self._elementsCountAcrossMinor = base._elementsCountAcrossMinor - self._elementsCountAcrossMajor = base._elementsCountAcrossMajor - self._elementsCountUp = base._elementsCountAcrossMajor // 2 \ - if cylinderShape == SphereShape.Sphere_SHAPE_FULL else base._elementsCountAcrossMajor - self._elementsCountAcrossShell = base._elementsCountAcrossShell - self._elementsCountAcrossTransition = base._elementsCountAcrossTransition + self._elementsCount = elementsCountAcross + self._elementsCountAcrossShell = elementsCountAcrossShell + self._elementsCountAcrossTransition = elementsCountAcrossTransition self._elementsCountAcrossRim = self._elementsCountAcrossShell + self._elementsCountAcrossTransition - 1 - self._shellProportion = base._shellProportion - self._elementsCountAlong = elementsCountAlong - self._elementsCountAround = 2 * (self._elementsCountAcrossMajor+self._elementsCountAcrossMinor - + self._shellProportion = shellProportion + self._elementsCountAround12 = 2 * (self._elementsCount[0] + self._elementsCount[1] - 4*(self._elementsCountAcrossRim + 1)) self._startNodeIdentifier = 1 self._startElementIdentifier = 1 self._endNodeIdentifier = 1 self._endElementIdentifier = 1 - self._cylinderShape = cylinderShape - # self._cylinderType = CylinderType.CYLINDER_STRAIGHT - if (tapered is not None) or cylinderCentralPath: - self._cylinderType = CylinderType.CYLINDER_TAPERED - self._tapered = tapered + self._sphereShape = sphereShape + self._useCrossDerivatives = useCrossDerivatives - self._cylinderCentralPath = cylinderCentralPath - if cylinderCentralPath: - self.calculateEllipseParams(cylinderCentralPath=self._cylinderCentralPath) - self._base = CylinderEnds(base._elementsCountAcrossMajor, base._elementsCountAcrossMinor, - base._elementsCountAcrossShell, base._elementsCountAcrossTransition, - base._shellProportion, self._centres[0], - None, self._majorAxis[0], self._minorRadii[0]) - else: - self._length = vector.magnitude(base._alongAxis) - arcLengthAlong = self._length / elementsCountAlong - self.calculateEllipseParams(arcLengthAlong, cylinderCentralPath=self._cylinderCentralPath) + + self._centre = centre + + for i in range(3): + elementsAxis = elementsCountAcross[i] - elementsCountAcrossShell * (1 - shellProportion) + self._coreRadius.append( + (1 - shellProportion * elementsCountAcrossShell / elementsAxis) * self._radius[i]) # generate the mesh - self.createCylinderMesh3d(fieldModule, coordinates) + self.createSphereMesh3d(fieldModule, coordinates) - def createCylinderMesh3d(self, fieldModule, coordinates): + def createSphereMesh3d(self, fieldModule, coordinates): """ - Create an extruded shape (ellipse/circle) mesh. Currently limited to ellipse or circle base with the alongAxis - perpendicular to the base. + Create a sphere mesh based on the shield topology. :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. :return: Final values of nextNodeIdentifier, nextElementIdentifier. """ - assert (self._elementsCountAlong > 0), 'createCylinderMesh3d: Invalid number of along elements' - assert (self._elementsCountAcrossMinor > 3), 'createCylinderMesh3d: Invalid number of across elements' - assert (self._elementsCountAcrossMinor % 2 == 0), 'createCylinderMesh3d: number of across elements' \ + for i in range(3): + assert (self._elementsCount[i] > 1), 'createSphereMesh3d: Invalid number of elements' + assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ ' is not an even number' - assert (self._elementsCountAcrossMajor > 1), 'createCylinderMesh3d: Invalid number of up elements' - assert (self._cylinderShape in [self._cylinderShape.CYLINDER_SHAPE_FULL, - self._cylinderShape.CYLINDER_SHAPE_LOWER_HALF]), \ - 'createCylinderMesh3d: Invalid cylinder mode.' + + assert (self._sphereShape in [self._sphereShape.SPHERE_SHAPE_FULL, + self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ + 'createSphereMesh3d: Invalid sphere mode.' nodes = fieldModule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) mesh = fieldModule.findMeshByDimension(3) elementsCountRim = self._elementsCountAcrossRim - shieldMode = ShieldShape2D.SHIELD_SHAPE_FULL if self._cylinderShape is self._cylinderShape.CYLINDER_SHAPE_FULL \ - else ShieldShape2D.SHIELD_SHAPE_LOWER_HALF - ellipseShape = EllipseShape.Ellipse_SHAPE_FULL \ - if self._cylinderShape is self._cylinderShape.CYLINDER_SHAPE_FULL else EllipseShape.Ellipse_SHAPE_LOWER_HALF - self._shield = ShieldMesh2D(self._elementsCountAcrossMinor, self._elementsCountAcrossMajor, elementsCountRim, - None, self._elementsCountAlong, shieldMode, - shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND) - - # generate ellipses mesh along cylinder axis - n3Count = 0 if self._cylinderType == CylinderType.CYLINDER_STRAIGHT else self._elementsCountAlong - self._ellipses = [] - for n3 in range(n3Count + 1): - ellipse = Ellipse2D(self._centres[n3], self._majorAxis[n3], self._minorAxis[n3], - self._elementsCountAcrossMajor, self._elementsCountAcrossMinor, self._elementsCountAcrossShell, - self._elementsCountAcrossTransition, - self._shellProportion, self._coreMajorRadii[n3], self._coreMinorRadii[n3], - ellipseShape=ellipseShape) - self._ellipses.append(ellipse) - self.copyEllipsesNodesToShieldNodes(n3) - - for n3 in range(n3Count + 1): - self.calculateD2Derivatives(n3, n3Count) - - if self._cylinderType == CylinderType.CYLINDER_TAPERED: - self.smoothd2Derivatives() - - # The other ellipses for a straight cylinder. - if self._cylinderType == CylinderType.CYLINDER_STRAIGHT: - arcLengthAlong = vector.magnitude(self._base._alongAxis) / self._elementsCountAlong - for n2 in range(self._elementsCountUp + 1): - for n3 in range(self._elementsCountAlong + 1): - for n1 in range(self._elementsCountAcrossMinor + 1): - if self._shield.px[0][n2][n1]: - temx = [self._shield.px[0][n2][n1][c] + n3 * arcLengthAlong * - vector.normalise(self._base._alongAxis)[c] for c in range(3)] - self._shield.px[n3][n2][n1] = temx - self._shield.pd1[n3][n2][n1] = self._shield.pd1[0][n2][n1] - self._shield.pd2[n3][n2][n1] = self._shield.pd2[0][n2][n1] - self._shield.pd3[n3][n2][n1] = self._shield.pd3[0][n2][n1] - - self.generateNodes(nodes, fieldModule, coordinates) - self.generateElements(mesh, fieldModule, coordinates) - - if self._end is None: - self._end = CylinderEnds(self._elementsCountAcrossMajor, self._elementsCountAcrossMinor, - self._elementsCountAcrossShell, self._elementsCountAcrossTransition, - self._shellProportion, - self._centres[-1], self._shield.pd2[-1][0][1], - vector.setMagnitude(self._base._majorAxis, self._majorRadii[-1]), - self._minorRadii[-1]) - self.setEndsNodes() - - def calculateD2Derivatives(self, n3, n3Count): - """ - calculate d2 derivatives. - :param n3: Index of along cylinder axis coordinates to use - :param n3Count: number of bases to create coordinates for. - """ - btx = self._shield.px - btd1 = self._shield.pd1 - btd2 = self._shield.pd2 - btd3 = self._shield.pd3 - # get ellipse d2 and next ellipse x, d2 - for n2 in range(self._elementsCountAcrossMajor + 1): - for n1 in range(self._elementsCountAcrossMinor + 1): - if btd1[n3][n2][n1]: - n3n = n3 if (n3 < n3Count) else n3 - 1 - btd2[n3][n2][n1] = [(btx[n3n + 1][n2][n1][c] - btx[n3n][n2][n1][c]) for c in range(3)] - - def smoothd2Derivatives(self): - """ - smooth d2 derivatives using initial values calculated by calculateD2Derivatives - """ - btx = self._shield.px - btd1 = self._shield.pd1 - btd2 = self._shield.pd2 - btd3 = self._shield.pd3 - for n2 in range(self._elementsCountAcrossMajor + 1): - for n1 in range(self._elementsCountAcrossMinor + 1): - td2 = [] - tx = [] - if btx[0][n2][n1]: - for n3 in range(self._elementsCountAlong + 1): - tx.append(btx[n3][n2][n1]) - td2.append(btd2[n3][n2][n1]) - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True) - for n3 in range(self._elementsCountAlong + 1): - btd2[n3][n2][n1] = td2[n3] - - def setEndsNodes(self): - """ - sets ellipse coordinates, derivatives and node ids. - """ - self._base.px = self._shield.px[0] - self._base.pd1 = self._shield.pd1[0] - self._base.pd2 = self._shield.pd2[0] - self._base.pd3 = self._shield.pd3[0] - self._end.px = self._shield.px[-1] - self._end.pd1 = self._shield.pd1[-1] - self._end.pd2 = self._shield.pd2[-1] - self._end.pd3 = self._shield.pd3[-1] - - def calculateEllipseParams(self, arcLengthAlong=None, cylinderCentralPath=None): - """ - Calculate the ellipses major and minor radii, major and minor axis and ellipses centres. - :param arcLengthAlong: arc length along the cylinder axis. Only if cylinderCentralPath is false. - :param cylinderCentralPath: Stores radii and centres of the ellipses along the cylinder length - """ - if not cylinderCentralPath: - self._centres = [self._base._centre for _ in range(self._elementsCountAlong+1)] - self._majorAxis = [self._base._majorAxis for _ in range(self._elementsCountAlong+1)] - self._minorAxis = [self._base._minorAxis for _ in range(self._elementsCountAlong+1)] - self._majorRadii = [self._base._majorRadius for _ in range(self._elementsCountAlong+1)] - self._minorRadii = [self._base._minorRadius for _ in range(self._elementsCountAlong+1)] - if cylinderCentralPath: - self._centres = cylinderCentralPath.centres - self._majorAxis = cylinderCentralPath.majorAxis - self._minorAxis = cylinderCentralPath.minorAxis - self._majorRadii = cylinderCentralPath.majorRadii - self._minorRadii = cylinderCentralPath.minorRadii - - elementsMinor = self._elementsCountAcrossMinor//2 - self._elementsCountAcrossShell*(1-self._shellProportion) - elementsMajor = self._elementsCountUp - self._elementsCountAcrossShell*(1-self._shellProportion) - for n3 in range(self._elementsCountAlong + 1): - self._coreMinorRadii.append((1-self._shellProportion*self._elementsCountAcrossShell/elementsMinor)*self._minorRadii[n3]) - self._coreMajorRadii.append((1-self._shellProportion*self._elementsCountAcrossShell/elementsMajor)*self._majorRadii[n3]) - - if self._cylinderType == CylinderType.CYLINDER_TAPERED and not cylinderCentralPath: - centre = self._base._centre - majorRadius = self._base._majorRadius - minorRadius = self._base._minorRadius - for n3 in range(1, self._elementsCountAlong+1): - majorRadius, majorAxis = computeNextRadius(majorRadius, self._base._majorAxis, - self._tapered.majorRatio, - self._tapered.majorProgressionMode) - minorRadius, minorAxis = computeNextRadius(minorRadius, self._base._minorAxis, - self._tapered.minorRatio, - self._tapered.minorProgressionMode) - centre = computeNextCentre(centre, arcLengthAlong, self._base._alongAxis) - self._centres[n3] = centre - self._majorAxis[n3] = majorAxis - self._minorAxis[n3] = minorAxis - self._majorRadii[n3] = majorRadius - self._minorRadii[n3] = minorRadius - - def copyEllipsesNodesToShieldNodes(self, n3): - """ - Copy coordinates and derivatives of ellipses to shield. + shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL if self._sphereShape is self._sphereShape.SPHERE_SHAPE_FULL \ + else ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP + + self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, + shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP) + + self.calculateBoundaryElipses(fieldModule, coordinates) + # self.generateNodes(nodes, fieldModule, coordinates) + # self.generateElements(mesh, fieldModule, coordinates) + + def calculateBoundaryElipses(self, fieldModule, coordinates): + """ + + :return: + """ + + centre = self._centre + elementsCountAcrossMajor = 2 * self._elementsCount[1] + elementsCountAcrossMinor = 2 * self._elementsCount[0] + elementsCountAcrossShell = self._elementsCountAcrossShell + elementsCountAcrossTransition = self._elementsCountAcrossTransition + shellProportion = self._shellProportion + + ellipseAxes = [[self._axes[0], self._axes[1], self._axes[2]], + [[-c for c in self._axes[2]], self._axes[1], self._axes[0]], + [self._axes[0], [-c for c in self._axes[2]], self._axes[1]]] + + coreRadius = [(self._coreRadius[0], self._coreRadius[1]), + (self._coreRadius[2], self._coreRadius[1]), + (self._coreRadius[0], self._coreRadius[2])] + + for i in range(3): + majorAxis = ellipseAxes[i][0] + minorAxis = ellipseAxes[i][1] + alongAxis = ellipseAxes[i][2] + coreMajorRadius = coreRadius[i][0] + coreMinorRadius = coreRadius[i][1] + ellipse = Ellipse2D(centre, majorAxis, minorAxis, + elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, + elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, + ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) + + self.copyEllipsesNodesToShieldNodes(ellipse, alongAxis, i) + + self._shield3D.getQudaruplePoint() + self._shield3D.pd2[1][1][0] = [self._shield3D.px[1][1][1][c] - self._shield3D.px[1][1][0][c] for c in range(3)] + self._shield3D.pd2[0][1][1] = [self._shield3D.px[1][1][1][c] - self._shield3D.px[0][1][1][c] for c in range(3)] + self._shield3D.pd2[1][2][1] = [-(self._shield3D.px[1][1][1][c] - self._shield3D.px[1][2][1][c]) for c in range(3)] + + temp = self._shield3D.pd2[1][1][0] + self._shield3D.pd2[1][1][0] = [-c for c in self._shield3D.pd3[1][1][0]] + self._shield3D.pd3[1][1][0] = [c for c in temp] + temp = self._shield3D.pd2[1][2][1] + self._shield3D.pd2[1][2][1] = [c for c in self._shield3D.pd1[1][2][1]] + self._shield3D.pd1[1][2][1] = temp + temp = self._shield3D.pd2[1][2][0] + self._shield3D.pd2[1][2][0] = [c for c in self._shield3D.pd1[1][2][0]] + self._shield3D.pd1[1][2][0] = temp + + x = [0.57735026, 0.57735026, 0.57735026] + self._shield3D.px[2][0][2] = x + self._shield3D.pd1[2][0][2] = [self._shield3D.px[2][2][2][c] - self._shield3D.px[2][0][2][c] for c in range(3)] + self._shield3D.pd2[2][0][2] = [-(self._shield3D.px[0][0][2][c] - self._shield3D.px[2][0][2][c]) for c in range(3)] + self._shield3D.pd3[2][0][2] = [-(self._shield3D.px[1][1][1][c] - self._shield3D.px[2][0][2][c]) for c in range(3)] + + radius = 1.0 + theta = math.atan(math.sqrt(1.0/2.0)) + arclength = radius*theta + self._shield3D.pd2[0][0][2] = vector.setMagnitude(self._shield3D.pd2[0][0][2], arclength) + self._shield3D.pd2[1][0][0] = vector.setMagnitude(self._shield3D.pd2[1][0][0], arclength) + self._shield3D.pd2[2][2][2] = vector.setMagnitude(self._shield3D.pd2[2][2][2], arclength) + self._shield3D.pd2[2][0][2] = vector.vectorRejection(self._shield3D.pd2[2][0][2], self._shield3D.pd3[2][0][2]) + self._shield3D.pd2[2][0][2] = vector.setMagnitude(self._shield3D.pd2[2][0][2], arclength) + self._shield3D.pd1[2][0][2] = vector.crossproduct3(self._shield3D.pd2[2][0][2], self._shield3D.pd3[2][0][2]) + self._shield3D.pd1[2][0][2] = vector.setMagnitude(self._shield3D.pd1[2][0][2], arclength) + + + self._shield3D.generateNodes(fieldModule, coordinates, 1) + self._shield3D.generateElements(fieldModule, coordinates, 1) + + def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): + """ + Copy coordinates and derivatives of ellipse to shield. :param n3: the index number of ellipse along the central path. """ - self._shield.px[n3] = self._ellipses[n3].px - self._shield.pd1[n3] = self._ellipses[n3].pd1 - self._shield.pd2[n3] = self._ellipses[n3].pd2 - self._shield.pd3[n3] = self._ellipses[n3].pd3 + + shield = ellipse.getShield() + + # Modify the shield12 to get only the quarter that you want. make others None so you can generate the nodes. + if ellipsenumber == 0: + for n2 in range(self._elementsCount[0] + 1): # TODO modify this to number of elements. + for n1 in range(self._elementsCount[1] + 1): + # only first quadrant is needed TODO we need to modify this to number of elements half of the elments across each direction. + self._shield3D.pd2[0][n2][n1] = [c for c in alongAxis] + if n2 == 0 and n1 == self._elementsCount[1] - 1: + n1s = n1 + 1 + else: + n1s = n1 + n1e = n1 + 2 + if shield.px[0][n2][n1 + self._elementsCount[1]]: + self._shield3D.px[0][n2][n1s] = [c for c in shield.px[0][n2][n1e]] + self._shield3D.pd1[0][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + self._shield3D.pd3[0][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] + elif ellipsenumber == 1: + n2s = self._elementsCount[0] + for n3 in range(self._elementsCount[2] + 1): + for n1 in range(self._elementsCount[1] + 1): + self._shield3D.pd2[n3][n2s][n1] = [c for c in alongAxis] + if n3 == self._elementsCount[2] and n1 == self._elementsCount[1] - 1: + n1s = n1 + 1 + else: + n1s = n1 + n2e = n3 + 2 + n1e = n1 + 2 + if n3 == 0: + self._shield3D.pd2[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] + else: + if shield.px[0][n2e][n1 + self._elementsCount[1]]: + self._shield3D.px[n3][n2s][n1s] = [c for c in shield.px[0][n2e][n1e]] + self._shield3D.pd1[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] + self._shield3D.pd3[n3][n2s][n1s] = [c for c in shield.pd3[0][n2e][n1e]] + elif ellipsenumber == 2: + n1s = 0 + for n3 in range(self._elementsCount[2] + 1): + for n2 in range(self._elementsCount[0] + 1): + + if n2 == self._elementsCount[2] and n3 == self._elementsCount[2] - 1: + n3s = n3 + 1 + else: + n3s = n3 + n1e = self._elementsCount[2] - n3 + if n3 == 0: + if n2 == 0: + self._shield3D.pd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + elif 0 < n2 < self._elementsCount[0]: + self._shield3D.pd2[n3][n2][n1s] = [-c for c in shield.pd3[0][n2][n1e]] + else: + if n2 < self._elementsCount[0]: + self._shield3D.pd2[n3][n2][n1s] = [c for c in alongAxis] + if shield.px[0][n2][n1e]: + self._shield3D.px[n3s][n2][n1s] = [c for c in shield.px[0][n2][n1e]] + self._shield3D.pd1[n3s][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + self._shield3D.pd3[n3s][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] + else: + self._shield3D.pd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + + def generateNodes(self, nodes, fieldModule, coordinates): """ @@ -362,438 +264,3 @@ def generateElements(self, mesh, fieldModule, coordinates): self._startElementIdentifier = elementIdentifier elementIdentifier = self._shield.generateElements(fieldModule, coordinates, elementIdentifier, []) self._endElementIdentifier = elementIdentifier - - def getElementsCountAround(self): - return self._elementsCountAround - - def getElementIdentifiers(self): - return self._shield.elementId - - -class Ellipse2D: - """ - Generate a 2D ellipse. - """ - - def __init__(self, centre, majorAxis, minorAxis, - elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, - elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, - ellipseShape=EllipseShape.Ellipse_SHAPE_FULL): - """ - :param centre: Ellipse centre. - :param majorAxis: A vector for ellipse major axis. - :param minorAxis: Ellipse minor axis. - :param elementsCountAcrossMajor: - :param elementsCountAcrossMinor: - :param ellipseShape: The shape of the ellipse which can be full or lower half. - """ - self.centre = centre - self.majorAxis = majorAxis - self.minorAxis = minorAxis - self.majorRadius = vector.magnitude(majorAxis) - self.minorRadius = vector.magnitude(minorAxis) - self.coreMajorRadius = coreMajorRadius - self.coreMinorRadius = coreMinorRadius - elementsCountRim = elementsCountAcrossShell + elementsCountAcrossTransition - 1 - shieldMode = ShieldShape2D.SHIELD_SHAPE_FULL if ellipseShape is EllipseShape.Ellipse_SHAPE_FULL\ - else ShieldShape2D.SHIELD_SHAPE_LOWER_HALF - shield = ShieldMesh2D(elementsCountAcrossMinor, elementsCountAcrossMajor, elementsCountRim, - None, 1, shieldMode, - shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND) - self.elementsCountAcrossMajor = elementsCountAcrossMajor - self.elementsCountAround = shield.elementsCountAroundFull - self.elementsCountUp = shield.elementsCountUp - self.elementsCountAcrossMinor = elementsCountAcrossMinor - self.elementsCountAcrossShell = elementsCountAcrossShell - self.elementsCountAcrossTransition = elementsCountAcrossTransition - self.elementsCountAcrossRim = elementsCountRim - self.shellProportion = shellProportion - self.nodeId = shield.nodeId - self.px = shield.px[0] - self.pd1 = shield.pd1[0] - self.pd2 = shield.pd2[0] - self.pd3 = shield.pd3[0] - self.__shield = shield - self.ellipseShape = ellipseShape - # generate the ellipse - self.generate2DEllipseMesh() - - def generate2DEllipseMesh(self): - """ - Generates a 2d ellipse using shield structure in shieldmesh. - """ - self.generateBase1DMesh(0) - if self.elementsCountAcrossShell > 0: - self.generateBase1DMesh(self.elementsCountAcrossShell) - self.setRimNodes() - rscx, rscd1, rscd2, rscd3 = self.createMirrorCurve() - self.createRegularRowCurves(rscx, rscd1, rscd3) - self.createRegularColumnCurves() - self.__shield.getTriplePoints(0) - self.smoothTriplePointsCurves() - self.smoothTransitionRims() - if self.ellipseShape == EllipseShape.Ellipse_SHAPE_FULL: - self.generateNodesForUpperHalf() - - def generateBase1DMesh(self, rx): - """ - Generate nodes around the perimeter of the ellipse. - """ - btx = self.px - btd1 = self.pd1 - btd2 = self.pd2 - btd3 = self.pd3 - - ratio = rx/self.elementsCountAcrossShell if self.elementsCountAcrossShell > 0 else 0 - majorAxis = [d*(1 - ratio*(1-self.coreMajorRadius/self.majorRadius)) for d in self.majorAxis] - minorAxis = [d*(1 - ratio*(1-self.coreMinorRadius/self.minorRadius)) for d in self.minorAxis] - majorRadius = vector.magnitude(majorAxis) - - nx, nd1 = createEllipsePerimeter( - self.centre, majorAxis, minorAxis, self.elementsCountAround, majorRadius) - nte = normalToEllipse(self.majorAxis, self.minorAxis) - - tbx, tbd1, tbd2, tbd3 = [], [], [], [] - for n in range(self.elementsCountAround + 1): - tbx.append(nx[n]) - tbd1.append(nd1[n]) - tbd2.append(nte) - tbd3.append(vector.normalise(vector.crossproduct3(tbd1[n], nte))) - - for n in range(self.elementsCountAround + 1): - n1, n2 = self.__shield.convertRimIndex(n, rx) - btx[n2][n1] = tbx[n] - btd1[n2][n1] = tbd1[n] - btd2[n2][n1] = tbd2[n] - btd3[n2][n1] = tbd3[n] - - def setRimNodes(self): - """ - Set nodes around the shell outer layer and core boundary in order needed for creating a shield mesh. - """ - btx = self.px - btd1 = self.pd1 - btd2 = self.pd2 - btd3 = self.pd3 - # - elementsCountShell = self.elementsCountAcrossShell - for n in range(self.elementsCountAround + 1): - if self.elementsCountAcrossShell > 1: - n1, n2 = self.__shield.convertRimIndex(n) - n1c, n2c = self.__shield.convertRimIndex(n, self.elementsCountAcrossShell) - tx, td3, pe, pxi, psf = sampleCubicHermiteCurves([btx[n2c][n1c], btx[n2][n1]], - [btd3[n2c][n1c], btd3[n2][n1]], elementsCountShell, - arcLengthDerivatives=True) - - for rx in range(1, self.elementsCountAcrossShell): - n1rx, n2rx = self.__shield.convertRimIndex(n, rx) - btx[n2rx][n1rx] = tx[-rx + elementsCountShell] - btd1[n2rx][n1rx] = btd1[n2][n1] - btd2[n2rx][n1rx] = btd2[n2][n1] - btd3[n2rx][n1rx] = btd3[n2][n1] - - for rx in range(1, self.elementsCountAcrossShell): - self.__shield.smoothDerivativesAroundRim(0, n3d=None, rx=rx) - - def createMirrorCurve(self): - """ - generate coordinates and derivatives for the mirror curve - :return: Coordinates and derivatives for the mirror curve - """ - btx = self.px - btd1 = self.pd1 - btd2 = self.pd2 - btd3 = self.pd3 - - n2a = self.elementsCountAcrossShell - rcx = [] - tmdx = btx[n2a][self.elementsCountAcrossMinor // 2] - tmdd3 = btd3[n2a][self.elementsCountAcrossMinor // 2] - tmux = [ - 0.5 * (btx[self.elementsCountUp][0][c] + btx[self.elementsCountUp][self.elementsCountAcrossMinor] - [c]) for c in range(3)] - rcx.append(tmdx) - rcx.append(tmux) - rcd3 = [vector.setMagnitude(tmdd3, -1), vector.setMagnitude(tmdd3, -1)] - rscx, rscd1 = sampleCubicHermiteCurves(rcx, rcd3, self.elementsCountUp - n2a, arcLengthDerivatives=True)[0:2] - - # get d2, d3 - rscd2 = [] - rscd3 = [] - for n in range(len(rscx)): - d3 = vector.normalise( - [btx[self.elementsCountUp][self.elementsCountAcrossMinor][c] - btx[self.elementsCountUp][0] - [c] for c in range(3)]) - d2 = vector.normalise(vector.crossproduct3(d3, rscd1[n])) - rscd2.append(d2) - rscd3.append(d3) - - return rscx, rscd1, rscd2, rscd3 - - def createRegularRowCurves(self, rscx, rscd1, rscd3): - """ - generate curves along regular rows using the mirror curve obtained from createMirrorCurve. - :param rscx: Coordinates of the nodes on the middle curve. - :param rscd1: d1 derivatives of the nodes on the middle curve. - :param rscd3: d3 derivatives of the nodes on the middle curve. - """ - btx = self.px - btd1 = self.pd1 - btd2 = self.pd2 - btd3 = self.pd3 - - elementsCountRim = self.elementsCountAcrossRim - n2a = self.elementsCountAcrossShell - n2b = elementsCountRim - n2d = n2b + 2 - n2m = self.elementsCountUp - n1a = self.elementsCountAcrossShell - n1b = elementsCountRim - n1z = self.elementsCountAcrossMinor - self.elementsCountAcrossShell - for n2 in range(n2d, n2m + 1): - txm, td3m, pe, pxi, psf = sampleCubicHermiteCurves( - [btx[n2][n1a], rscx[n2 - n2a], btx[n2][n1z]], - [vector.setMagnitude(btd3[n2][n1a], -1.0), rscd3[n2 - n2a], btd3[n2][n1z]], - self.elementsCountAcrossMinor-2*self.elementsCountAcrossShell, arcLengthDerivatives=True) - td1m = interpolateSampleCubicHermite([[-btd1[n2][n1a][c] for c in range(3)], rscd1[n2 - n2a], - btd1[n2][n1z]], [[0.0, 0.0, 0.0]] * 3, pe, pxi, psf)[0] - - tx = [] - td3 = [] - for n1 in range(self.elementsCountAcrossMinor + 1): - if n1 <= n1a: - tx.append(btx[n2][n1]) - td3.append([-btd3[n2][n1][c] for c in range(3)]) - elif (n1 > n1a) and (n1 < n1z): - tx.append(txm[n1 - n1a]) - td3.append(td3m[n1 - n1a]) - else: - tx.append(btx[n2][n1]) - td3.append((btd3[n2][n1])) - - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - - for n1 in range(self.elementsCountAcrossMinor + 1): - if n1 <= n1a: - btd3[n2][n1] = [-td3[n1][c] for c in range(3)] - elif (n1 > n1a) and (n1 < n1z): - btx[n2][n1] = tx[n1] - if n2 == n2m: - if n1 <= n1b: - btd1[n2][n1] = vector.setMagnitude(btd1[n2m][-1], -1.0) - else: - btd1[n2][n1] = vector.setMagnitude(btd1[n2m][-1], 1.0) - else: - if n1 <= n1b: - btd1[n2][n1] = [-d for d in td1m[n1 - n1a]] - else: - btd1[n2][n1] = td1m[n1 - n1a] - if n1 <= n1b: - btd3[n2][n1] = [-d for d in td3[n1]] - else: - btd3[n2][n1] = td3[n1] - else: - btd3[n2][n1] = td3[n1] - - def createRegularColumnCurves(self): - """ - up regular columns of shield: get d1, initial d3 below regular rows - """ - btx = self.px - btd1 = self.pd1 - btd2 = self.pd2 - btd3 = self.pd3 - - elementsCountRim = self.elementsCountAcrossRim - n1d = elementsCountRim + 2 - n1x = self.elementsCountAcrossMinor - elementsCountRim - 1 - n2a = self.elementsCountAcrossShell - n2b = elementsCountRim - n2d = 2 + n2b - n2m = self.elementsCountUp - for n1 in range(n1d, n1x): - txm, td1m, pe, pxi, psf = sampleCubicHermiteCurves( - [btx[n2a][n1], btx[n2d][n1]], [[-btd3[n2a][n1][c] for c in range(3)], btd1[n2d][n1]], - 2 + self.elementsCountAcrossTransition - 1, arcLengthDerivatives=True) - td3m = interpolateSampleCubicHermite([btd1[n2a][n1], btd3[n2d][n1]], [[0.0, 0.0, 0.0]] * 2, pe, pxi, psf)[0] - - tx = [] - td1 = [] - for n2 in range(n2m + 1): - if n2 <= n2a: - tx.append(btx[n2][n1]) - td1.append([-btd3[n2][n1][c] for c in range(3)]) - elif (n2 > n2a) and (n2 < n2d): - tx.append(txm[n2 - n2a]) - td1.append(td1m[n2 - n2a]) - else: - tx.append(btx[n2][n1]) - td1.append(btd1[n2][n1]) - - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) - - for n2 in range(n2m + 1): - if n2 <= n2a: - btd3[n2][n1] = [-td1[n2][c] for c in range(3)] - elif (n2 > n2a) and (n2 < n2d): - btx[n2][n1] = tx[n2] - if n2 <= n2b: - btd1[n2][n1] = td3m[n2 - n2a] - btd3[n2][n1] = [-d for d in td1[n2]] - else: - btd1[n2][n1] = td1[n2] - btd3[n2][n1] = td3m[n2 - n2a] - else: - btd1[n2][n1] = td1[n2] - - def smoothTriplePointsCurves(self): - """ - Smooth row and column curves passing triple points (i.e., row 1 and columns 1 and -2). - """ - btx = self.px - btd1 = self.pd1 - btd2 = self.pd2 - btd3 = self.pd3 - - n1c = 1 + self.elementsCountAcrossRim - n1y = self.elementsCountAcrossMinor - self.elementsCountAcrossRim - n1x = n1y - 1 - n2a = self.elementsCountAcrossShell - n2c = 1 + self.elementsCountAcrossRim - n2m = self.elementsCountUp - - # smooth shield row n2c - btd3[n2c][n1c:n1y] = smoothCubicHermiteDerivativesLine(btx[n2c][n1c:n1y], btd3[n2c][n1c:n1y]) - - # smooth Shield columns n1c, n1x - for n1 in [n1c, n1x]: - tx = [] - td1 = [] - for n2 in range(n2c, n2m + 1): - tx.append(btx[n2][n1]) - td1.append(btd1[n2][n1]) - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True, fixStartDerivative=True) - for n in range(n2m-n2c+1): - btd1[n + n2c][n1] = td1[n] - - # sample nodes to triple points - for n1 in [n1c, n1x]: - c1 = 1 if n1 == n1c else -1 - txm, td3m, pe, pxi, psf = sampleCubicHermiteCurves( - [btx[n2a][n1], btx[n2c][n1]], [[-btd3[n2a][n1][c] for c in range(3)], - [btd1[n2c][n1][c] + c1 * btd3[n2c][n1][c] for c in range(3)]], - 1 + self.elementsCountAcrossTransition - 1, arcLengthDerivatives=True) - td1m = interpolateSampleCubicHermite([btd1[n2a][n1], [-c1*d for d in btd1[n2c][n1]]], [[0.0, 0.0, 0.0]] * 2, pe, pxi, psf)[0] - - for n2 in range(n2a + 1, n2c): - btx[n2][n1] = txm[n2 - n2a] - btd1[n2][n1] = td1m[n2 - n2a] - btd3[n2][n1] = [-d for d in td3m[n2 - n2a]] - - # smooth - self.__shield.smoothDerivativesToTriplePoints(0, fixAllDirections=True) - - def smoothTransitionRims(self): - """ - smooth rims in the transition zone - """ - n2a = self.elementsCountAcrossShell - n2b = self.elementsCountAcrossRim - for rx in range(n2a + 1, n2b + 1): - self.__shield.smoothDerivativesAroundRim(0, n3d=None, rx=rx) - - def generateNodesForUpperHalf(self): - """ - Generates coordinates and derivatives for the upper half by mirroring the lower half nodes and derivatives. - It keeps the d1 direction. - It uses mirrorPlane: plane ax+by+cz=d in form of [a,b,c,d] - """ - mirrorPlane = [-d for d in self.majorAxis] + [-vector.dotproduct(self.majorAxis, self.centre)] - mirror = Mirror(mirrorPlane) - for n2 in range(self.elementsCountUp): - for n1 in range(self.elementsCountAcrossMinor + 1): - if self.px[n2][n1]: - self.px[2 * self.elementsCountUp - n2][n1] = mirror.mirrorImageOfPoint( - self.px[n2][n1]) - self.pd1[2 * self.elementsCountUp - n2][n1] = mirror.reverseMirrorVector( - self.pd1[n2][n1]) - self.pd3[2 * self.elementsCountUp - n2][n1] = mirror.mirrorVector( - self.pd3[n2][n1]) - - -def createEllipsePerimeter(centre, majorAxis, minorAxis, elementsCountAround, height): - """ - Generate a set of points and derivatives for an ellipse - starting at pole majorAxis from centre. - :param elementsCountAround: Number of elements around. - :param centre: Centre of full ellipse. - :param majorAxis: Vector in direction of starting major radius, magnitude is ellipse major radius. - :param minorAxis: Vector normal to major axis, magnitude is ellipse minor axis length. - :param height: Height of arc of ellipsoid from starting point along majorAxis. - :return: Lists nx, nd1. Ordered fastest around, starting at major radius. - """ - nx = [] - nd1 = [] - magMajorAxis = vector.magnitude(majorAxis) - magMinorAxis = vector.magnitude(minorAxis) - unitMajorAxis = vector.normalise(majorAxis) - unitMinorAxis = vector.normalise(minorAxis) - useHeight = min(max(0.0, height), 2.0 * magMajorAxis) - totalRadians = geometry.getEllipseRadiansToX(magMajorAxis, 0.0, magMajorAxis - useHeight, - initialTheta=0.5 * math.pi * useHeight / magMajorAxis) - radians = 0.0 - arcLengthUp = geometry.getEllipseArcLength(magMajorAxis, magMinorAxis, radians, totalRadians) - elementsCountUp = elementsCountAround // 2 - elementArcLength = arcLengthUp / elementsCountUp - radians = geometry.updateEllipseAngleByArcLength(magMajorAxis, magMinorAxis, radians, -arcLengthUp) - for n1 in range(2 * elementsCountUp + 1): - cosRadians = math.cos(radians) - sinRadians = math.sin(radians) - nx.append( - [(centre[c] + cosRadians * majorAxis[c] + sinRadians * minorAxis[c]) for c in range(3)]) - - ndab = vector.setMagnitude([-sinRadians * magMajorAxis, cosRadians * magMinorAxis], elementArcLength) - nd1.append( - [(ndab[0] * unitMajorAxis[c] + ndab[1] * unitMinorAxis[c]) for c in range(3)]) - radians = geometry.updateEllipseAngleByArcLength(magMajorAxis, magMinorAxis, radians, elementArcLength) - return nx, nd1 - - -def normalToEllipse(v1, v2): - """ - Find unit normal vector of an ellipse using two vectors in the ellipse. The direction is v1xv2 - :param v1: vector 1. - :param v2: vector 2. - :return: - """ - nte = vector.normalise(vector.crossproduct3(v1, v2)) - return nte - - -def computeNextRadius(radius, axis, ratio, progression): - """ - calculate next radius based on the progression method. r_n+1=r_n*ratio for geometric. r_n+1=r_ratio for arithmetic. - :param radius: radius (major or minor) along the central path. - :param axis: major or minor axis along the central path. - :param ratio: common ratio (common difference) for changing the next radius. - :param progression: arithmetic or geometric. - :return: next radius and axis. - """ - if progression == ConeBaseProgression.GEOMETRIC_PROGRESSION: - radius = radius * ratio - elif progression == ConeBaseProgression.ARITHMETIC_PROGRESSION: - radius += ratio - axis = vector.setMagnitude(axis, radius) - return radius, axis - - -def computeNextCentre(centre, arcLength, axis): - """ - compute next centre coordinate - :param axis: - :param arcLength: the length to go forward. - :param centre: the start centre. - :return: next centre coordinates. - """ - centre = [centre[c]+arcLength * vector.normalise(axis)[c] for c in range(3)] - return centre From 1b06d1ca8e141b2cb55ea0a03e4913a4462a2dee Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Thu, 26 Aug 2021 12:52:10 +1200 Subject: [PATCH 03/37] Fix refine function --- .../meshtypes/meshtype_3d_solidsphere2.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 7a0921ff..82f35dad 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -65,8 +65,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): # 'Lower half': False, 'Use cross derivatives': False, 'Refine': False, - 'Refine number of elements across major': 1, - 'Refine number of elements along': 1 + 'Refine number of elements across': 1, } return options @@ -83,8 +82,7 @@ def getOrderedOptionNames(): 'Shell element thickness proportion', # 'Lower half', 'Refine', - 'Refine number of elements across major', - 'Refine number of elements along' + 'Refine number of elements across' ] @classmethod @@ -196,8 +194,6 @@ def refineMesh(cls, meshRefinement, options): :param options: Dict containing options. See getDefaultOptions(). """ assert isinstance(meshRefinement, MeshRefinement) - refineElementsCountAcrossAxis1 = options['Refine number of elements across axis1'] - refineElementsCountAcrossAxis2 = options['Refine number of elements across axis2'] - refineElementsCountAcrossAxis3 = options['Refine number of elements across axis3'] + refineElementsCountAcross = options['Refine number of elements across'] # refineElementsCountAlong = options['Refine number of elements along'] - meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcrossAxis1, refineElementsCountAcrossAxis2, refineElementsCountAcrossAxis3) + meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcross, refineElementsCountAcross, refineElementsCountAcross) From 4bd166bbb11148a8052387921b51a69c9b78272a Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Thu, 26 Aug 2021 12:54:58 +1200 Subject: [PATCH 04/37] Tidy up the code --- src/scaffoldmaker/utils/shieldmesh.py | 55 +++-- src/scaffoldmaker/utils/spheremesh.py | 325 ++++++++++++++++++++++---- 2 files changed, 308 insertions(+), 72 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index b960510f..092d36ef 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -69,7 +69,7 @@ def __init__(self, elementsCountAcross, elementsCountRim, self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] - def getQudaruplePoint(self): + def getQuadruplePoint(self): """ :return: @@ -151,35 +151,25 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes # isEven = (self.elementsCountAcross % 2) == 0 e1a = self.elementsCountRim + e1b = e1a + 1 + # e1z = self.elementsCountAcross - 1 - self.elementsCountRim + # e1y = e1z - 1 + e2a = self.elementsCountRim + e2b = self.elementsCountRim + 1 + e2c = self.elementsCountRim + 2 + # e2z = 2*self.elementsCountUp-1-self.elementsCountRim + # e2y = e2z - 1 + # e2x = e2z - 2 for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): for e1 in range(self.elementsCountAcross[1]): eft1 = eft scalefactors = None - if e3==0 and e2==1 and e1==0: + if e3 == 0 and e2 > 0 and e1 == 0: nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+1][e2][e1+1],self.nodeId[e3+1][e2+1][e1+1]] - elif e3==0 and e2==1 and e1==1: - nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2-1][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2-1][e1+1],self.nodeId[e3+2][e2+1][e1+1]] - - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - - remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1,[8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - elif e3==0 and e2==0 and e1==0: - nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], + nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+2][e2][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2][e1+2],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2][e1+2],self.nodeId[e3+1][e2+1][e1+1]] eft1 = tricubichermite.createEftNoCrossDerivatives() @@ -187,7 +177,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes scalefactors = [-1.0] remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) @@ -199,9 +188,27 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) + elif e3==0 and e2==1 and e1==1: + nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], + self.nodeId[e3][e2-1][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2-1][e1+1],self.nodeId[e3+2][e2+1][e1+1]] + + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1,[8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elif e3 == 1 and e2 == 1 and e1 == 0: - nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3][e2-1][e1], self.nodeId[e3+1][e2+1][e1], + nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2-1][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2-1][e1+2], self.nodeId[e3+1][e2+1][e1+2]] eft1 = tricubichermite.createEftNoCrossDerivatives() diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 4ffdd722..626904c6 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -81,8 +81,8 @@ def createSphereMesh3d(self, fieldModule, coordinates): """ for i in range(3): assert (self._elementsCount[i] > 1), 'createSphereMesh3d: Invalid number of elements' - assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ - ' is not an even number' + # assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ + # ' is not an even number' assert (self._sphereShape in [self._sphereShape.SPHERE_SHAPE_FULL, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ @@ -99,19 +99,17 @@ def createSphereMesh3d(self, fieldModule, coordinates): self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP) - self.calculateBoundaryElipses(fieldModule, coordinates) - # self.generateNodes(nodes, fieldModule, coordinates) - # self.generateElements(mesh, fieldModule, coordinates) + self.calculateBoundaryElipses() + self.generateNodes(nodes, fieldModule, coordinates) + self.generateElements(mesh, fieldModule, coordinates) - def calculateBoundaryElipses(self, fieldModule, coordinates): + def calculateBoundaryElipses(self): """ :return: """ centre = self._centre - elementsCountAcrossMajor = 2 * self._elementsCount[1] - elementsCountAcrossMinor = 2 * self._elementsCount[0] elementsCountAcrossShell = self._elementsCountAcrossShell elementsCountAcrossTransition = self._elementsCountAcrossTransition shellProportion = self._shellProportion @@ -124,10 +122,16 @@ def calculateBoundaryElipses(self, fieldModule, coordinates): (self._coreRadius[2], self._coreRadius[1]), (self._coreRadius[0], self._coreRadius[2])] + elementsCount = [(2 * self._elementsCount[0], 2 * self._elementsCount[1]), + (2 * self._elementsCount[2], 2 * self._elementsCount[1]), + (2 * self._elementsCount[0], 2 * self._elementsCount[2])] + for i in range(3): majorAxis = ellipseAxes[i][0] minorAxis = ellipseAxes[i][1] alongAxis = ellipseAxes[i][2] + elementsCountAcrossMajor = elementsCount[i][0] + elementsCountAcrossMinor = elementsCount[i][1] coreMajorRadius = coreRadius[i][0] coreMinorRadius = coreRadius[i][1] ellipse = Ellipse2D(centre, majorAxis, minorAxis, @@ -137,41 +141,10 @@ def calculateBoundaryElipses(self, fieldModule, coordinates): self.copyEllipsesNodesToShieldNodes(ellipse, alongAxis, i) - self._shield3D.getQudaruplePoint() - self._shield3D.pd2[1][1][0] = [self._shield3D.px[1][1][1][c] - self._shield3D.px[1][1][0][c] for c in range(3)] - self._shield3D.pd2[0][1][1] = [self._shield3D.px[1][1][1][c] - self._shield3D.px[0][1][1][c] for c in range(3)] - self._shield3D.pd2[1][2][1] = [-(self._shield3D.px[1][1][1][c] - self._shield3D.px[1][2][1][c]) for c in range(3)] - - temp = self._shield3D.pd2[1][1][0] - self._shield3D.pd2[1][1][0] = [-c for c in self._shield3D.pd3[1][1][0]] - self._shield3D.pd3[1][1][0] = [c for c in temp] - temp = self._shield3D.pd2[1][2][1] - self._shield3D.pd2[1][2][1] = [c for c in self._shield3D.pd1[1][2][1]] - self._shield3D.pd1[1][2][1] = temp - temp = self._shield3D.pd2[1][2][0] - self._shield3D.pd2[1][2][0] = [c for c in self._shield3D.pd1[1][2][0]] - self._shield3D.pd1[1][2][0] = temp - - x = [0.57735026, 0.57735026, 0.57735026] - self._shield3D.px[2][0][2] = x - self._shield3D.pd1[2][0][2] = [self._shield3D.px[2][2][2][c] - self._shield3D.px[2][0][2][c] for c in range(3)] - self._shield3D.pd2[2][0][2] = [-(self._shield3D.px[0][0][2][c] - self._shield3D.px[2][0][2][c]) for c in range(3)] - self._shield3D.pd3[2][0][2] = [-(self._shield3D.px[1][1][1][c] - self._shield3D.px[2][0][2][c]) for c in range(3)] - radius = 1.0 - theta = math.atan(math.sqrt(1.0/2.0)) - arclength = radius*theta - self._shield3D.pd2[0][0][2] = vector.setMagnitude(self._shield3D.pd2[0][0][2], arclength) - self._shield3D.pd2[1][0][0] = vector.setMagnitude(self._shield3D.pd2[1][0][0], arclength) - self._shield3D.pd2[2][2][2] = vector.setMagnitude(self._shield3D.pd2[2][2][2], arclength) - self._shield3D.pd2[2][0][2] = vector.vectorRejection(self._shield3D.pd2[2][0][2], self._shield3D.pd3[2][0][2]) - self._shield3D.pd2[2][0][2] = vector.setMagnitude(self._shield3D.pd2[2][0][2], arclength) - self._shield3D.pd1[2][0][2] = vector.crossproduct3(self._shield3D.pd2[2][0][2], self._shield3D.pd3[2][0][2]) - self._shield3D.pd1[2][0][2] = vector.setMagnitude(self._shield3D.pd1[2][0][2], arclength) + self.createAdditionalPointsForIncreasingElementsCount() - self._shield3D.generateNodes(fieldModule, coordinates, 1) - self._shield3D.generateElements(fieldModule, coordinates, 1) def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): """ @@ -191,8 +164,8 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): n1s = n1 + 1 else: n1s = n1 - n1e = n1 + 2 - if shield.px[0][n2][n1 + self._elementsCount[1]]: + n1e = n1 + self._elementsCount[1] + if shield.px[0][n2][n1e]: self._shield3D.px[0][n2][n1s] = [c for c in shield.px[0][n2][n1e]] self._shield3D.pd1[0][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] self._shield3D.pd3[0][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] @@ -205,8 +178,8 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): n1s = n1 + 1 else: n1s = n1 - n2e = n3 + 2 - n1e = n1 + 2 + n2e = n3 + self._elementsCount[2] + n1e = n1 + self._elementsCount[1] if n3 == 0: self._shield3D.pd2[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] else: @@ -219,8 +192,8 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): for n3 in range(self._elementsCount[2] + 1): for n2 in range(self._elementsCount[0] + 1): - if n2 == self._elementsCount[2] and n3 == self._elementsCount[2] - 1: - n3s = n3 + 1 + if n2 == 0 and n3 == self._elementsCount[2] - 1: + n3s = self._elementsCount[2] else: n3s = n3 n1e = self._elementsCount[2] - n3 @@ -239,7 +212,238 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): else: self._shield3D.pd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + def createAdditionalPointsForIncreasingElementsCount(self): + """ + + :return: + """ + + self.calculate_regular_nodes() + self._shield3D.getQuadruplePoint() + self.fixD2DerivativesOnTheEllipses() + self.remapDerivativesOnTheEllipses() + + # reverse d2 for 0,0,0 + self._shield3D.pd2[0][0][0] = [-c for c in self._shield3D.pd2[0][0][0]] + + self.calculate_surface_nodes() + self.smooth_triple_curves() + + def calculate_regular_nodes(self): + """ + + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + if self._elementsCount[0] == 3: + self.CreateRegularNodeOnBoundary() + n3 = 0 + n1 = 0 + for n2 in range(n2a + 1, n2b): + # First create the node for regular node. We are using the neighbour nodes x,y,z to do it but TODO eventully we need to use the sampling between boundary nodes. + x = [self._shield3D.px[n3][n2][n1 + 1][0], self._shield3D.px[n3 + 1][n2 + 1][n1 + 1][1], + self._shield3D.px[n3 + 1][n2][n1][2]] + self._shield3D.px[n3 + 1][n2][n1 + 1] = x + self._shield3D.pd1[n3 + 1][n2][n1 + 1] = [ + (self._shield3D.px[n3 + 1][n2 + 1][n1 + 1][c] - self._shield3D.px[n3 + 1][n2][n1 + 1][c]) for c in + range(3)] + self._shield3D.pd2[n3 + 1][n2][n1 + 1] = [ + -(self._shield3D.px[n3][n2][n1 + 1][c] - self._shield3D.px[n3 + 1][n2][n1 + 1][c]) for c in + range(3)] + self._shield3D.pd3[n3 + 1][n2][n1 + 1] = [ + -(self._shield3D.px[n3 + 1][n2][n1][c] - self._shield3D.px[n3 + 1][n2][n1 + 1][c]) for c in + range(3)] + # using new point obtain the d2 derivatives of the neighbour nodes + self._shield3D.pd2[n3 + 1][n2][n1] = [ + self._shield3D.px[n3 + 1][n2][n1 + 1][c] - self._shield3D.px[n3 + 1][n2][n1][c] for c in range(3)] + self._shield3D.pd2[n3][n2][n1 + 1] = [ + self._shield3D.px[n3 + 1][n2][n1 + 1][c] - self._shield3D.px[n3][n2][n1 + 1][c] for c in range(3)] + self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] = [ + self._shield3D.px[n3 + 1][n2 + 1][n1 + 1][c] - self._shield3D.px[n3][n2 + 1][n1 + 1][c] for c in + range(3)] + + self.remapRegularCurvesOnEllipses() + + def remapRegularCurvesOnEllipses(self): + """ + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + # We need to remap the derivatives as we want d1 to be in -axis1 direction, d2, axis3 and d3, axis2. We need to think about the directions as well. e.g. + # d1, d2, d3 could be simply axis1,axis2 and axis3. However this one was chosen so it could be consistent with the cylinder mesh that makes joining them + # a little easier. TODO d1,d2,d3 directions in regular elements. + # for nodes on the ellipse2, d2 is -d3 and d3 is d2. TODO we can add another method to ellipse so it gives us what we expect for derivatives. + n3 = 0 + n1 = 0 + for n2 in range(n2a + 1, n2b): + temp = self._shield3D.pd2[n3 + 1][n2][n1] + self._shield3D.pd2[n3 + 1][n2][n1] = [-c for c in self._shield3D.pd3[n3 + 1][n2][n1]] + self._shield3D.pd3[n3 + 1][n2][n1] = temp + # for ellipse 1, swap d2 and d1 + temp = self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] + self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] = [c for c in self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1]] + self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1] = temp + + def CreateRegularNodeOnBoundary(self): + """ + + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + # create the other two nodes to create the elements. + radius = self._radius[0] # TODO need to be changed for spheroid + + elementsAroundEllipse12 = self._elementsCount[0] + self._elementsCount[1] - 2 + radiansAroundEllipse12 = math.pi / 2 + radiansPerElementAroundEllipse12 = radiansAroundEllipse12 / elementsAroundEllipse12 + elementsAroundEllipse13 = self._elementsCount[0] + self._elementsCount[2] - 2 + radiansAroundEllipse13 = math.pi / 2 + radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 + + n3 = 0 + n1 = 0 + for n2 in range(n2a + 1, n2b): + theta_2 = math.pi / 4 # TODO actually it should change with the number of elements. + theta_3 = radiansPerElementAroundEllipse12 + phi_3 = calculate_azimuth(theta_3, theta_2) + # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead + theta_3 = 2 * radiansPerElementAroundEllipse12 + x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), + radius * math.cos(phi_3)] + + e1, e2, e3 = sphere_local_orthogonal_unit_vectors(x, self._axes[2]) + self._shield3D.px[n3 + 1][n2][n1 + 2] = x + self._shield3D.pd1[n3 + 1][n2][n1 + 2] = e1 + self._shield3D.pd2[n3 + 1][n2][n1 + 2] = e2 + self._shield3D.pd3[n3 + 1][n2][n1 + 2] = e3 + + arcLength = radius * phi_3 + self._shield3D.pd2[n3 + 1][n2][n1 + 2] = vector.setMagnitude(self._shield3D.pd2[n3 + 1][n2][n1 + 2], arcLength) + + + def fixD2DerivativesOnTheEllipses(self): + """ + + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + self._shield3D.pd2[n3b][n2a][n1a] = [self._shield3D.px[n3b][n2a][n1b][c] - self._shield3D.px[n3b][n2a][n1a][c] + for c in range(3)] + self._shield3D.pd2[0][1][1] = [self._shield3D.px[1][1][1][c] - self._shield3D.px[0][1][1][c] for c in range(3)] + self._shield3D.pd2[n3b][n2b][n1b] = [ + -(self._shield3D.px[n3b][n2a][n1b][c] - self._shield3D.px[n3b][n2b][n1b][c]) for c in range(3)] + + def remapDerivativesOnTheEllipses(self): + """ + + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + temp = self._shield3D.pd2[1][1][0] + self._shield3D.pd2[1][1][0] = [-c for c in self._shield3D.pd3[1][1][0]] + self._shield3D.pd3[1][1][0] = [c for c in temp] + temp = self._shield3D.pd2[n3b][n2b][n1b] + self._shield3D.pd2[n3b][n2b][n1b] = [c for c in self._shield3D.pd1[n3b][n2b][n1b]] + self._shield3D.pd1[n3b][n2b][n1b] = temp + temp = self._shield3D.pd2[n3b][n2b][n1a] + self._shield3D.pd2[n3b][n2b][n1a] = [c for c in self._shield3D.pd1[n3b][n2b][n1a]] + self._shield3D.pd1[n3b][n2b][n1a] = temp + + def calculate_surface_nodes(self): + """ + + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + radius = self._radius[0] # TODO need to be changed for spheroid + + elementsAroundEllipse12 = self._elementsCount[0] + self._elementsCount[1] - 2 + radiansAroundEllipse12 = math.pi / 2 + radiansPerElementAroundEllipse12 = radiansAroundEllipse12 / elementsAroundEllipse12 + elementsAroundEllipse13 = self._elementsCount[0] + self._elementsCount[2] - 2 + radiansAroundEllipse13 = math.pi / 2 + radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 + + theta_2 = radiansPerElementAroundEllipse13 # TODO actually it should change with the number of elements. + theta_3 = radiansPerElementAroundEllipse12 + phi_3 = calculate_azimuth(theta_3, theta_2) + # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead + x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), + radius * math.cos(phi_3)] + self._shield3D.px[n3b + 1][0][n1b + 1] = x + self._shield3D.pd1[n3b + 1][0][n1b + 1] = [ + self._shield3D.px[n3b + 1][n2b][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c] for c in range(3)] + self._shield3D.pd2[n3b + 1][0][n1b + 1] = [ + -(self._shield3D.px[0][0][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n3b + 1][c]) for c in range(3)] + self._shield3D.pd3[n3b + 1][0][n1b + 1] = [ + -(self._shield3D.px[1][1][1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c]) for c in range(3)] + + def smooth_triple_curves(self): + """ + + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + radius = 1.0 + theta = math.atan(math.sqrt(1.0 / 2.0)) + arclength = radius * theta + self._shield3D.pd2[0][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[0][0][n1b + 1], arclength) + self._shield3D.pd2[n3b + 1][0][0] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][0], arclength) + self._shield3D.pd2[n3b + 1][n2b][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][n2b][n1b + 1], + arclength) + self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.vectorRejection(self._shield3D.pd2[n3b + 1][0][n1b + 1], + self._shield3D.pd3[n3b + 1][0][n1b + 1]) + self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1], + arclength) + self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.crossproduct3(self._shield3D.pd2[n3b + 1][0][n1b + 1], + self._shield3D.pd3[n3b + 1][0][n1b + 1]) + d2mag = vector.magnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1]) + thetad1ncurve = math.pi / 6 + self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], + d2mag / math.tan(thetad1ncurve)) def generateNodes(self, nodes, fieldModule, coordinates): """ @@ -250,7 +454,7 @@ def generateNodes(self, nodes, fieldModule, coordinates): """ nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) self._startNodeIdentifier = nodeIdentifier - nodeIdentifier = self._shield.generateNodes(fieldModule, coordinates, nodeIdentifier) + nodeIdentifier = self._shield3D.generateNodes(fieldModule, coordinates, nodeIdentifier) self._endNodeIdentifier = nodeIdentifier def generateElements(self, mesh, fieldModule, coordinates): @@ -262,5 +466,30 @@ def generateElements(self, mesh, fieldModule, coordinates): """ elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1) self._startElementIdentifier = elementIdentifier - elementIdentifier = self._shield.generateElements(fieldModule, coordinates, elementIdentifier, []) + elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, []) self._endElementIdentifier = elementIdentifier + + +def calculate_azimuth(theta, theta_p): + """ + Given polar angles in different planes, calculates the azimuth angle. + :param theta: polar angle. + :param theta_p: polar angle wrt other direction. + :return: Azimuth angle. + """ + return math.atan(1/(math.tan(theta_p)*math.cos(theta))) + + +def sphere_local_orthogonal_unit_vectors(x, axis3): + """ + Find local orthogonal unit vectors for a point on a sphere + :param x: coordinates of the point. + :param axis3: The third axis in Cartesian coordinate system (axis1, axis2, axis3) + :return: e1, e2, e3. Unit vectors. e3 is normal to the boundary, e2 is in (e3, axis3) plane and e1 normal to them. + """ + e3 = vector.normalise(x) + e2 = vector.vectorRejection(axis3, e3) + e2 = vector.normalise(e2) + e1 = vector.crossproduct3(e2, e3) + + return e1, e2, e3 From 69b229295f70c59e126d6be0fb04a643be4d3c72 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Mon, 30 Aug 2021 12:34:36 +1200 Subject: [PATCH 05/37] Fix remapping problem for derivatives for swapping them --- src/scaffoldmaker/utils/shieldmesh.py | 78 ++++++++++++----- src/scaffoldmaker/utils/spheremesh.py | 115 ++++++++++++++++---------- src/scaffoldmaker/utils/vector.py | 7 ++ 3 files changed, 138 insertions(+), 62 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 092d36ef..12f8ab28 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -84,6 +84,35 @@ def getQuadruplePoint(self): self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + def smoothDerivativesToSurfaceQuadruple(self, n3, fixAllDirections=False): + ''' + Smooth derivatives leading to quadruple point where 3 hex elements merge. + :param n3: Index of through-wall coordinates to use. + ''' + n1b = self.elementsCountAcross[1] - (self.elementsCountRim + 1) + # n1z = self.elementsCountAcross[] - self.elementsCountRim + # n1y = n1z - 1 + # m1a = self.elementsCountAcross - self.elementsCountRim + # m1b = m1a - 1 + n2a = self.elementsCountRim + n2b = n2a + 1 + n2c = n2a + 2 + + tx = [] + td3 = [] + for n2 in range(n2c): + if n2 < n2b: + tx.append(self.px[n3][n2][n1b + 1]) + td3.append([-self.pd3[n3][n2][n1b+1][c] for c in range(3)]) + else: + tx.append(self.px[n3-1][n2][n1b]) + td3.append([(self.pd1[n3-1][n2b][n1b][c] - self.pd2[n3-1][n2b][n1b][c] - self.pd3[n3-1][n2b][n1b][c]) for c in range(3)] ) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + + for n2 in range(n2b): + self.pd3[n3][n2][n1b+1] = [-td3[n2][c] for c in range(3)] + def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlane=None): """ Create shield nodes from coordinates. @@ -101,6 +130,7 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan 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_D_DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) cache = fieldmodule.createFieldcache() #for n2 in range(self.elementsCountUp, -1, -1): @@ -157,7 +187,7 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes e2a = self.elementsCountRim e2b = self.elementsCountRim + 1 e2c = self.elementsCountRim + 2 - # e2z = 2*self.elementsCountUp-1-self.elementsCountRim + e2z = self.elementsCountAcross[0] - 1 # e2y = e2z - 1 # e2x = e2z - 2 for e3 in range(self.elementsCountAcross[2]): @@ -176,10 +206,14 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + + remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS1, @@ -205,11 +239,15 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1,[8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - elif e3 == 1 and e2 == 1 and e1 == 0: - nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2-1][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2-1][e1+2], self.nodeId[e3+1][e2+1][e1+2]] + elif e3 == 1 and e2 >= e2b and e1 == 0: + if e2 == 1: + e2r = e2 - 1 + else: + e2r = e2 + nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2r][e1], self.nodeId[e3+1][e2+1][e1], + self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2r][e1+2], self.nodeId[e3+1][e2+1][e1+2]] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) @@ -218,22 +256,24 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + + if e2 == e2z: + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) # The order is important + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - - else: diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 626904c6..b8b90186 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -270,33 +270,6 @@ def calculate_regular_nodes(self): self.remapRegularCurvesOnEllipses() - def remapRegularCurvesOnEllipses(self): - """ - - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - # We need to remap the derivatives as we want d1 to be in -axis1 direction, d2, axis3 and d3, axis2. We need to think about the directions as well. e.g. - # d1, d2, d3 could be simply axis1,axis2 and axis3. However this one was chosen so it could be consistent with the cylinder mesh that makes joining them - # a little easier. TODO d1,d2,d3 directions in regular elements. - # for nodes on the ellipse2, d2 is -d3 and d3 is d2. TODO we can add another method to ellipse so it gives us what we expect for derivatives. - n3 = 0 - n1 = 0 - for n2 in range(n2a + 1, n2b): - temp = self._shield3D.pd2[n3 + 1][n2][n1] - self._shield3D.pd2[n3 + 1][n2][n1] = [-c for c in self._shield3D.pd3[n3 + 1][n2][n1]] - self._shield3D.pd3[n3 + 1][n2][n1] = temp - # for ellipse 1, swap d2 and d1 - temp = self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] - self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] = [c for c in self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1]] - self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1] = temp - def CreateRegularNodeOnBoundary(self): """ @@ -319,26 +292,51 @@ def CreateRegularNodeOnBoundary(self): radiansAroundEllipse13 = math.pi / 2 radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 - n3 = 0 + n3 = 1 n1 = 0 for n2 in range(n2a + 1, n2b): - theta_2 = math.pi / 4 # TODO actually it should change with the number of elements. - theta_3 = radiansPerElementAroundEllipse12 - phi_3 = calculate_azimuth(theta_3, theta_2) + theta_1 = math.pi / 4 # TODO actually it should change with the number of elements. + theta_3 = 2*radiansPerElementAroundEllipse12 + phi_3 = calculate_azimuth(math.pi/2 - theta_3, theta_1) # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - theta_3 = 2 * radiansPerElementAroundEllipse12 x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), radius * math.cos(phi_3)] - e1, e2, e3 = sphere_local_orthogonal_unit_vectors(x, self._axes[2]) + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) self._shield3D.px[n3 + 1][n2][n1 + 2] = x - self._shield3D.pd1[n3 + 1][n2][n1 + 2] = e1 - self._shield3D.pd2[n3 + 1][n2][n1 + 2] = e2 - self._shield3D.pd3[n3 + 1][n2][n1 + 2] = e3 + self._shield3D.pd1[n3 + 1][n2][n1 + 2] = a1 + self._shield3D.pd2[n3 + 1][n2][n1 + 2] = a2 + self._shield3D.pd3[n3 + 1][n2][n1 + 2] = a3 arcLength = radius * phi_3 self._shield3D.pd2[n3 + 1][n2][n1 + 2] = vector.setMagnitude(self._shield3D.pd2[n3 + 1][n2][n1 + 2], arcLength) + def remapRegularCurvesOnEllipses(self): + """ + + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + # We need to remap the derivatives as we want d1 to be in -axis1 direction, d2, axis3 and d3, axis2. We need to think about the directions as well. e.g. + # d1, d2, d3 could be simply axis1,axis2 and axis3. However this one was chosen so it could be consistent with the cylinder mesh that makes joining them + # a little easier. TODO d1,d2,d3 directions in regular elements. + # for nodes on the ellipse2, d2 is -d3 and d3 is d2. TODO we can add another method to ellipse so it gives us what we expect for derivatives. + n3 = 0 + n1 = 0 + for n2 in range(n2a + 1, n2b): + temp = self._shield3D.pd2[n3 + 1][n2][n1] + self._shield3D.pd2[n3 + 1][n2][n1] = [-c for c in self._shield3D.pd3[n3 + 1][n2][n1]] + self._shield3D.pd3[n3 + 1][n2][n1] = temp + # for ellipse 1, swap d2 and d1 + temp = self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] + self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] = [c for c in self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1]] + self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1] = temp def fixD2DerivativesOnTheEllipses(self): """ @@ -407,13 +405,32 @@ def calculate_surface_nodes(self): # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), radius * math.cos(phi_3)] + + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) self._shield3D.px[n3b + 1][0][n1b + 1] = x + self._shield3D.pd1[n3b + 1][0][n1b + 1] = a1 + self._shield3D.pd2[n3b + 1][0][n1b + 1] = a2 + self._shield3D.pd3[n3b + 1][0][n1b + 1] = a3 + + arcLength = calculate_arc_length(x, self._shield3D.px[n3a][0][n1b + 1], radius) + self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1], arcLength) + self._shield3D.smoothDerivativesToSurfaceQuadruple(n3b+1) + self._shield3D.pd1[n3b + 1][0][n1b + 1] = [ self._shield3D.px[n3b + 1][n2b][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c] for c in range(3)] - self._shield3D.pd2[n3b + 1][0][n1b + 1] = [ - -(self._shield3D.px[0][0][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n3b + 1][c]) for c in range(3)] - self._shield3D.pd3[n3b + 1][0][n1b + 1] = [ - -(self._shield3D.px[1][1][1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c]) for c in range(3)] + # self._shield3D.pd2[n3b + 1][0][n1b + 1] = [ + # -(self._shield3D.px[0][0][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n3b + 1][c]) for c in range(3)] + # self._shield3D.pd3[n3b + 1][0][n1b + 1] = [ + # -(self._shield3D.px[1][1][1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c]) for c in range(3)] + + + + n1a = 1 + n2a = 1 + n3a = 1 + self._shield3D.pd1[n3a][n2a][n1a] = [-(self._shield3D.px[n3a+1][n2a-1][n1a+1][0] - self._shield3D.px[n3a][n2a][n1a][0]), 0.0, 0.0] + self._shield3D.pd2[n3a][n2a][n1a] = [0.0, 0.0, (self._shield3D.px[n3a+1][n2a-1][n1a+1][2] - self._shield3D.px[n3a][n2a][n1a][2])] + self._shield3D.pd3[n3a][n2a][n1a] = [0.0, (self._shield3D.px[n3a+1][n2a-1][n1a+1][1] - self._shield3D.px[n3a][n2a][n1a][1]), 0.0] def smooth_triple_curves(self): """ @@ -472,15 +489,16 @@ def generateElements(self, mesh, fieldModule, coordinates): def calculate_azimuth(theta, theta_p): """ - Given polar angles in different planes, calculates the azimuth angle. - :param theta: polar angle. + Given polar angles of a point on the sphere surfaces, calculate the azimuth angle. + :param theta: polar angle. In orthonormal coordinate system (axis1, axis2, axis3) with right-hand rule, + theta is angle between common axis and point projection on plane of theta. In case theta=theta_3 and theta_p = theta_1, theta is between axis2 and projection :param theta_p: polar angle wrt other direction. :return: Azimuth angle. """ return math.atan(1/(math.tan(theta_p)*math.cos(theta))) -def sphere_local_orthogonal_unit_vectors(x, axis3): +def local_orthogonal_unit_vectors(x, axis3): """ Find local orthogonal unit vectors for a point on a sphere :param x: coordinates of the point. @@ -493,3 +511,14 @@ def sphere_local_orthogonal_unit_vectors(x, axis3): e1 = vector.crossproduct3(e2, e3) return e1, e2, e3 + + +def calculate_arc_length(x1, x2, radius): + """ + Calculate the arc length between points x1 and x2. + :param x1, x2: points coordinates. + :param radius: sphere radius. + :return: arc length + """ + angle = vector.angleBetweenVectors(x1, x2) + return radius * angle diff --git a/src/scaffoldmaker/utils/vector.py b/src/scaffoldmaker/utils/vector.py index 340753a1..c132153a 100644 --- a/src/scaffoldmaker/utils/vector.py +++ b/src/scaffoldmaker/utils/vector.py @@ -88,3 +88,10 @@ def parallelVectors(v1, v2): if magnitude(crossproduct3(v1, v2)) < TOL * (magnitude(v1)+magnitude(v2)): return True return False + + +def angleBetweenVectors(v1, v2): + """ + :return: Angle between vectors v1 and v2 in radians + """ + return math.acos(dotproduct(normalise(v1), normalise(v2))) From 6b7615afed8503576462099c31a0a8821db625bf Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Tue, 31 Aug 2021 12:23:26 +1200 Subject: [PATCH 06/37] Fix derivatives for the surface node --- src/scaffoldmaker/utils/shieldmesh.py | 18 +++++------ src/scaffoldmaker/utils/spheremesh.py | 43 +++++++++++++++++++-------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 12f8ab28..aac7f4d5 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -77,10 +77,10 @@ def getQuadruplePoint(self): n1a = 1 n2a = 1 n3a = 1 - n2b = self.elementsCountAcross[0] - x = [self.px[0][n2a][n1a][0],self.px[n3a][n2b][n1a][1],self.px[n3a][n2a][0][2]] + # n2b = self.elementsCountAcross[0] + x = [self.px[0][n2a][n1a][0],self.px[n3a][n2a+1][n1a][1],self.px[n3a][n2a][0][2]] self.px[n3a][n2a][n1a] = [c for c in x] - self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2b][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2a+1][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] @@ -218,8 +218,9 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) elif e3==0 and e2==1 and e1==1: @@ -236,7 +237,7 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) @@ -265,9 +266,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) # The order is important + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index b8b90186..dc381342 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -414,10 +414,19 @@ def calculate_surface_nodes(self): arcLength = calculate_arc_length(x, self._shield3D.px[n3a][0][n1b + 1], radius) self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1], arcLength) + + + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[0]) + # btd1 = [ + # self._shield3D.px[n3b + 1][n2b][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c] for c in range(3)] + self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) self._shield3D.smoothDerivativesToSurfaceQuadruple(n3b+1) - self._shield3D.pd1[n3b + 1][0][n1b + 1] = [ - self._shield3D.px[n3b + 1][n2b][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c] for c in range(3)] + + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[1]) + # btd1 = [ + # self._shield3D.px[n3b + 1][n2b][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c] for c in range(3)] + self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) # self._shield3D.pd2[n3b + 1][0][n1b + 1] = [ # -(self._shield3D.px[0][0][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n3b + 1][c]) for c in range(3)] # self._shield3D.pd3[n3b + 1][0][n1b + 1] = [ @@ -451,16 +460,26 @@ def smooth_triple_curves(self): self._shield3D.pd2[n3b + 1][0][0] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][0], arclength) self._shield3D.pd2[n3b + 1][n2b][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][n2b][n1b + 1], arclength) - self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.vectorRejection(self._shield3D.pd2[n3b + 1][0][n1b + 1], - self._shield3D.pd3[n3b + 1][0][n1b + 1]) - self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1], - arclength) - self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.crossproduct3(self._shield3D.pd2[n3b + 1][0][n1b + 1], - self._shield3D.pd3[n3b + 1][0][n1b + 1]) - d2mag = vector.magnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1]) - thetad1ncurve = math.pi / 6 - self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], - d2mag / math.tan(thetad1ncurve)) + # atz = vector.vectorRejection(self._shield3D.pd2[n3b + 1][0][n1b + 1], self._shield3D.pd3[n3b + 1][0][n1b + 1]) + # self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(atz, arclength) + atx = vector.vectorRejection(self._shield3D.pd1[n3b + 1][0][n1b + 1], self._shield3D.pd3[n3b + 1][0][n1b + 1]) + self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(atx, arclength) + + + # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.crossproduct3(self._shield3D.pd2[n3b + 1][0][n1b + 1], + # self._shield3D.pd3[n3b + 1][0][n1b + 1]) + # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], + # arclength) + + # dmag = calculate_arc_length(self._shield3D.px[n3b + 1][0][n1b + 1], self._shield3D.px[n3b + 1][2][n1b + 1], radius) + # d2mag = vector.magnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1]) + # d1mag = math.sqrt(dmag*dmag - d2mag*d2mag) + # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], d1mag) + # d2mag = vector.magnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1]) + # thetad1ncurve = math.pi / 6 + # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], + # d2mag / math.tan(thetad1ncurve)) + def generateNodes(self, nodes, fieldModule, coordinates): """ From 9c095877ee040d62d235796469523ea39b4ca624 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Tue, 7 Sep 2021 11:05:41 +1200 Subject: [PATCH 07/37] Add rotate vector around vector function --- src/scaffoldmaker/utils/vector.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/scaffoldmaker/utils/vector.py b/src/scaffoldmaker/utils/vector.py index c132153a..c19e2a12 100644 --- a/src/scaffoldmaker/utils/vector.py +++ b/src/scaffoldmaker/utils/vector.py @@ -57,7 +57,7 @@ def vectorProjection(v1, v2): :return: A projection vector. """ s1 = scalarProjection(v1, v2) - return scalarProduct(s1, normalise(v2)) + return scaleVector(normalise(v2), s1) def vectorRejection(v1, v2): @@ -69,14 +69,14 @@ def vectorRejection(v1, v2): return addVectors(v1, v1p, 1.0, -1.0) -def scalarProduct(s, v): +def scaleVector(v, s): """ Calculate s * v - :param s: Scalar. :param v: Vector. + :param s: Scalar. :return: """ - return [s * v[c] for c in range(len(v))] + return [s * c for c in v] def parallelVectors(v1, v2): @@ -95,3 +95,14 @@ def angleBetweenVectors(v1, v2): :return: Angle between vectors v1 and v2 in radians """ return math.acos(dotproduct(normalise(v1), normalise(v2))) + + +def rotateVectorAroundVector(v, k, a): + """ + Rotate vector v, by an angle a (right-hand rule) in radians around vector k. + :return: rotated vector. + """ + k = normalise(k) + vperp = addVectors(v, crossproduct3(k, v), math.cos(a), math.sin(a)) + vparal = scaleVector(k, dotproduct(k, v)*(1 - math.cos(a))) + return addVectors(vperp, vparal) From d9ab2234de83d9f799d7f6c4c8da8a2757eb7f04 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Tue, 7 Sep 2021 11:09:23 +1200 Subject: [PATCH 08/37] calculate d2 for ellipse --- src/scaffoldmaker/utils/cylindermesh.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/scaffoldmaker/utils/cylindermesh.py b/src/scaffoldmaker/utils/cylindermesh.py index 676a5170..6cc7a9c8 100644 --- a/src/scaffoldmaker/utils/cylindermesh.py +++ b/src/scaffoldmaker/utils/cylindermesh.py @@ -463,6 +463,7 @@ def generate2DEllipseMesh(self): self.smoothTransitionRims() if self.ellipseShape == EllipseShape.Ellipse_SHAPE_FULL: self.generateNodesForUpperHalf() + self.calculateD2() def generateBase1DMesh(self, rx): """ @@ -749,6 +750,19 @@ def generateNodesForUpperHalf(self): self.pd3[2 * self.elementsCountUp - n2][n1] = mirror.mirrorVector( self.pd3[n2][n1]) + def calculateD2(self): + """ + :return: + """ + btx = self.px + btd2 = self.pd2 + + nte = normalToEllipse(self.majorAxis, self.minorAxis) + for n2 in range(self.elementsCountAcrossMajor + 1): + for n1 in range(self.elementsCountAcrossMinor + 1): + if btx[n2][n1]: + btd2[n2][n1] = nte + def getShield(self): return self.__shield From babfff1f3b7d42c8eb182f4b995cb33f67705457 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Tue, 7 Sep 2021 11:15:52 +1200 Subject: [PATCH 09/37] For the shield mesh (2D), allow the derivatives in the regular curves and the circles around to be configurable --- src/scaffoldmaker/utils/shieldmesh.py | 146 +++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 17 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index aac7f4d5..572f1113 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -69,6 +69,47 @@ def __init__(self, elementsCountAcross, elementsCountRim, self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] + def getQuadruplePoint2(self): + """ + + :return: + """ + n1a = 1 + n2a = 1 + n3a = 1 + # n2b = self.elementsCountAcross[0] + for n2 in range(self.elementsCountAcross[0]): + if n2 > 0: + x = [self.px[0][n2][n1a][0], self.px[0][n2][n1a][1],self.px[n3a][n2][0][2]] + self.px[n3a][n2][n1a] = x + n2r = n2 - 1 if n2 == 1 else n2 + if n2 == 1: + self.pd1[n3a][n2][n1a] = [-(self.px[n3a + 1][n2r][n1a + 1][0] - self.px[n3a][n2][n1a][0]), 0.0, 0.0] + else: + self.pd1[n3a][n2][n1a] = self.pd1[0][n2][n1a] + self.pd2[n3a][n2][n1a] = [0.0, 0.0, (self.px[n3a + 1][n2r][n1a + 1][2] - self.px[n3a][n2][n1a][2])] + self.pd3[n3a][n2][n1a] = [0.0, (self.px[n3a + 1][n2r][n1a + 1][1] - self.px[n3a][n2][n1a][1]), 0.0] + + n3 = 1 + n1 = 1 + tx = [] + td1 = [] + for n2 in range(self.elementsCountAcross[0] + 1): + if n2 > 0: + tx.append(self.px[n3][n2][n1]) + td1.append(self.pd1[n3][n2][n1]) + + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) + + for n2 in range(self.elementsCountAcross[0] + 1): + if n2 > 1: + n2t = n2 - 1 + self.pd1[n3][n2][n1] = td1[n2t] + + # self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2a+1][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + # self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + # self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + def getQuadruplePoint(self): """ @@ -78,11 +119,16 @@ def getQuadruplePoint(self): n2a = 1 n3a = 1 # n2b = self.elementsCountAcross[0] - x = [self.px[0][n2a][n1a][0],self.px[n3a][n2a+1][n1a][1],self.px[n3a][n2a][0][2]] - self.px[n3a][n2a][n1a] = [c for c in x] - self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2a+1][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] - self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] - self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + for n2 in range(self.elementsCountAcross[0]): + if n2 > 0: + x = [self.px[0][n2][n1a][0], self.px[0][n2][n1a][1],self.px[n3a][n2][0][2]] + self.px[n3a][n2][n1a] = x + self.pd1[n3a][n2][n1a] = self.pd1[0][n2][n1a] + self.pd2[n3a][n2][n1a] = self.pd2[0][n2][n1a] + self.pd3[n3a][n2][n1a] = self.pd3[0][n2][n1a] + # self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2a+1][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + # self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] + # self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] def smoothDerivativesToSurfaceQuadruple(self, n3, fixAllDirections=False): ''' @@ -182,7 +228,7 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes # isEven = (self.elementsCountAcross % 2) == 0 e1a = self.elementsCountRim e1b = e1a + 1 - # e1z = self.elementsCountAcross - 1 - self.elementsCountRim + # e1z = self.elementsCountAcross[1] - 1 - self.elementsCountRim # e1y = e1z - 1 e2a = self.elementsCountRim e2b = self.elementsCountRim + 1 @@ -195,10 +241,10 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes for e1 in range(self.elementsCountAcross[1]): eft1 = eft scalefactors = None - if e3 == 0 and e2 > 0 and e1 == 0: + if e3 == 0 and e2 > e2a and e1 == 0: nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+1][e2][e1+1],self.nodeId[e3+1][e2+1][e1+1]] - elif e3==0 and e2==0 and e1==0: + elif e3 == 0 and e2 == 0 and e1 == 0: nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+2][e2][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2][e1+2],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2][e1+2],self.nodeId[e3+1][e2+1][e1+1]] @@ -223,24 +269,33 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) - elif e3==0 and e2==1 and e1==1: + elif e3 == 0 and e2 >= e2b and e1 == 1: + if e2 == 1: + e2r = e2 - 1 + else: + e2r = e2 nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2-1][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2-1][e1+1],self.nodeId[e3+2][e2+1][e1+1]] + self.nodeId[e3][e2r][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2r][e1+1],self.nodeId[e3+2][e2+1][e1+1]] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + + if e2 == e2b: + remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + + if e2 == e2z: + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) elif e3 == 1 and e2 >= e2b and e1 == 0: if e2 == 1: @@ -254,13 +309,18 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + + if e2 == e2b: + remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + if e2 == e2z: remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) @@ -271,6 +331,17 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + else: + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) # finish swap + remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) @@ -593,6 +664,47 @@ def smoothDerivativesAroundRim(self, n3, n3d=None, rx=0): else: self.pd1[n3][n2][n1] = td1[ix] + def remap_derivatives(self, squareMapping, circleMapping=None): + """ + It remaps the derivatives as indicated by squareMapping and circleMapping. Limited to SHIELD_RIM_DERIVATIVE_MODE_AROUND. + :param squareMapping: List[up, right]. Determines what derivatives should be in the up and right directions in the + square part. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. + The negative sign reverses the direction. e.g. [-3,2] means d3 is down and d2 is right. The third derivative + is determined by the other two. RH rule applied. Assumes [1,3] initially. + :param circleMapping: List[circumferential, radial]. Determines what derivatives should be used for + circumferential and radial directions around the circle. + [-1, 3] means d1 -> clockwise and around. d3 -> outward and radial. Assumes [1,3] initially. + :return: + """ + dct = {1: self.pd1, 2: self.pd2, 3: self.pd3} + perm = {(1, 2): -3, (2, 3): -1, (3, 1): -2, (3, 2): 1, (1, 3): 2, (2, 1): 3} + + square = True + tripleRow = [self.elementsCountRim + 1, self.elementsCountUpFull - (self.elementsCountRim + 1)] + ellipseMapping = [squareMapping, circleMapping] + for mapping in ellipseMapping: + if mapping: + signs = [] + for c in mapping: + sign = 1 if c > 0 else -1 + signs.append(sign) + derv = (abs(mapping[0]), abs(mapping[1])) + sign = 1 if perm[derv] > 0 else -1 + signs.append(signs[0]*signs[1]*sign) + dervMapping = (derv[0], derv[1], abs(perm[derv])) + temp1 = copy.deepcopy(self.pd3) + temp2 = copy.deepcopy(self.pd2) + for n2 in range(self.elementsCountUpFull + 1): + for n3 in range(self.elementsCountAlong+1): + for n1 in range(self.elementsCountAcross + 1): + if self.px[n3][n2][n1]: + is_on_square = ((self.px[n3][n2][0] and self.px[n3][0][n1]) or n2 in tripleRow) + if (is_on_square and square) or (not is_on_square and not square): + dct[dervMapping[0]][n3][n2][n1] = [signs[0]*c for c in self.pd1[n3][n2][n1]] + dct[dervMapping[1]][n3][n2][n1] = [signs[1]*c for c in temp1[n3][n2][n1]] + dct[dervMapping[2]][n3][n2][n1] = [signs[2]*c for c in temp2[n3][n2][n1]] + square = False + def generateNodesForOtherHalf(self, mirrorPlane): """ Generates coordinates and derivatives for the other half by mirroring them. It keeps the d1 direction. From 9e7e19420f4e95938139dbb12c45c67251bb76ba Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Tue, 7 Sep 2021 11:20:04 +1200 Subject: [PATCH 10/37] Make number of elemens across x configurable --- src/scaffoldmaker/utils/spheremesh.py | 719 +++++++++++++++++++++----- 1 file changed, 599 insertions(+), 120 deletions(-) diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index dc381342..44c05899 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -9,7 +9,7 @@ from opencmiss.utils.zinc.finiteelement import getMaximumNodeIdentifier, getMaximumElementIdentifier from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D, ShieldRimDerivativeMode from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, interpolateSampleCubicHermite, \ - smoothCubicHermiteDerivativesLine, interpolateSampleLinear + smoothCubicHermiteDerivativesLine, interpolateSampleLinear, interpolateCubicHermite from opencmiss.zinc.node import Node from scaffoldmaker.utils.mirror import Mirror from scaffoldmaker.meshtypes.meshtype_1d_path1 import extractPathParametersFromRegion @@ -96,13 +96,135 @@ def createSphereMesh3d(self, fieldModule, coordinates): shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL if self._sphereShape is self._sphereShape.SPHERE_SHAPE_FULL \ else ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP - self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, - shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP) + self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode) - self.calculateBoundaryElipses() + self.calculateBoundaryElipses2() self.generateNodes(nodes, fieldModule, coordinates) self.generateElements(mesh, fieldModule, coordinates) + def calculateBoundaryElipses2(self): + """ + + :return: + """ + + centre = self._centre + elementsCountAcrossShell = self._elementsCountAcrossShell + elementsCountAcrossTransition = self._elementsCountAcrossTransition + shellProportion = self._shellProportion + + ellipseAxes = [[self._axes[0], self._axes[1], self._axes[2]], + [[-c for c in self._axes[2]], self._axes[1], self._axes[0]], + [self._axes[0], [-c for c in self._axes[2]], self._axes[1]]] + + coreRadius = [(self._coreRadius[0], self._coreRadius[1]), + (self._coreRadius[2], self._coreRadius[1]), + (self._coreRadius[0], self._coreRadius[2])] + + elementsCount = [(2 * self._elementsCount[0], 2 * self._elementsCount[1]), + (2 * self._elementsCount[2], 2 * self._elementsCount[1]), + (2 * self._elementsCount[0], 2 * self._elementsCount[2])] + + for i in range(3): + majorAxis = ellipseAxes[i][0] + minorAxis = ellipseAxes[i][1] + alongAxis = ellipseAxes[i][2] + elementsCountAcrossMajor = elementsCount[i][0] + elementsCountAcrossMinor = elementsCount[i][1] + coreMajorRadius = coreRadius[i][0] + coreMinorRadius = coreRadius[i][1] + ellipse = Ellipse2D(centre, majorAxis, minorAxis, + elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, + elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, + ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) + + self.copyEllipsesNodesToShieldNodes2(ellipse, alongAxis, i) + + + self.createAdditionalPointsForIncreasingElementsCount2() + + def copyEllipsesNodesToShieldNodes2(self, ellipse, alongAxis, ellipsenumber): + """ + Copy coordinates and derivatives of ellipse to shield. + :param n3: the index number of ellipse along the central path. + """ + + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + shield = ellipse.getShield() + + # Modify the shield12 to get only the quarter that you want. make others None so you can generate the nodes. + if ellipsenumber == 0: + for n2 in range(self._elementsCount[0] + 1): # TODO modify this to number of elements. + for n1 in range(self._elementsCount[1] + 1): + # only first quadrant is needed TODO we need to modify this to number of elements half of the elments across each direction. + # btd2[0][n2][n1] = [c for c in alongAxis] + if n2 == 0 and n1 == self._elementsCount[1] - 1: + n1s = n1 + 1 + else: + n1s = n1 + n1e = n1 + self._elementsCount[1] + if shield.px[0][n2][n1e]: + btx[0][n2][n1s] = shield.px[0][n2][n1e] + btd1[0][n2][n1s] = shield.pd1[0][n2][n1e] + btd2[0][n2][n1s] = shield.pd2[0][n2][n1e] + btd3[0][n2][n1s] = shield.pd3[0][n2][n1e] + elif ellipsenumber == 1: + shield.remap_derivatives([2, 3], circleMapping=None) + n2s = self._elementsCount[0] + for n3 in range(self._elementsCount[2] + 1): + for n1 in range(self._elementsCount[1] + 1): + # btd2[n3][n2s][n1] = [c for c in alongAxis] + if n3 == self._elementsCount[2] and n1 == self._elementsCount[1] - 1: + n1s = n1 + 1 + else: + n1s = n1 + n2e = n3 + self._elementsCount[2] + n1e = n1 + self._elementsCount[1] + if n3 == 0: + if n1 == self._elementsCount[1]: + btd2[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] + else: + btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] + else: + if shield.px[0][n2e][n1 + self._elementsCount[1]]: + btx[n3][n2s][n1s] = [c for c in shield.px[0][n2e][n1e]] + btd1[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] + btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] + btd3[n3][n2s][n1s] = [c for c in shield.pd3[0][n2e][n1e]] + elif ellipsenumber == 2: + shield.remap_derivatives([1, -2], circleMapping=None) + n1s = 0 + for n3 in range(self._elementsCount[2] + 1): + for n2 in range(self._elementsCount[0] + 1): + + if n2 == 0 and n3 == self._elementsCount[2] - 1: + n3s = self._elementsCount[2] + else: + n3s = n3 + n1e = self._elementsCount[2] - n3 + if n3 == 0: + if n2 == 0: + btd2[n3][n2][n1s] = [-c for c in shield.pd1[0][n2][n1e]] + elif 0 < n2 < self._elementsCount[0]: + btd2[n3][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] + else: + if n2 < self._elementsCount[0]: + # btd2[n3][n2][n1s] = [c for c in alongAxis] + if shield.px[0][n2][n1e]: + btx[n3s][n2][n1s] = [c for c in shield.px[0][n2][n1e]] + btd1[n3s][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + btd2[n3s][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] + btd3[n3s][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] + else: + if n3 == self._elementsCount[2]: + btd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + else: + btd1[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + def calculateBoundaryElipses(self): """ @@ -145,13 +267,17 @@ def calculateBoundaryElipses(self): self.createAdditionalPointsForIncreasingElementsCount() - def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): """ Copy coordinates and derivatives of ellipse to shield. :param n3: the index number of ellipse along the central path. """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + shield = ellipse.getShield() # Modify the shield12 to get only the quarter that you want. make others None so you can generate the nodes. @@ -159,21 +285,22 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): for n2 in range(self._elementsCount[0] + 1): # TODO modify this to number of elements. for n1 in range(self._elementsCount[1] + 1): # only first quadrant is needed TODO we need to modify this to number of elements half of the elments across each direction. - self._shield3D.pd2[0][n2][n1] = [c for c in alongAxis] + # btd2[0][n2][n1] = [c for c in alongAxis] if n2 == 0 and n1 == self._elementsCount[1] - 1: n1s = n1 + 1 else: n1s = n1 n1e = n1 + self._elementsCount[1] if shield.px[0][n2][n1e]: - self._shield3D.px[0][n2][n1s] = [c for c in shield.px[0][n2][n1e]] - self._shield3D.pd1[0][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - self._shield3D.pd3[0][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] + btx[0][n2][n1s] = [c for c in shield.px[0][n2][n1e]] + btd1[0][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + btd2[0][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] + btd3[0][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] elif ellipsenumber == 1: n2s = self._elementsCount[0] for n3 in range(self._elementsCount[2] + 1): for n1 in range(self._elementsCount[1] + 1): - self._shield3D.pd2[n3][n2s][n1] = [c for c in alongAxis] + btd2[n3][n2s][n1] = [c for c in alongAxis] if n3 == self._elementsCount[2] and n1 == self._elementsCount[1] - 1: n1s = n1 + 1 else: @@ -181,12 +308,12 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): n2e = n3 + self._elementsCount[2] n1e = n1 + self._elementsCount[1] if n3 == 0: - self._shield3D.pd2[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] + btd2[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] else: if shield.px[0][n2e][n1 + self._elementsCount[1]]: - self._shield3D.px[n3][n2s][n1s] = [c for c in shield.px[0][n2e][n1e]] - self._shield3D.pd1[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] - self._shield3D.pd3[n3][n2s][n1s] = [c for c in shield.pd3[0][n2e][n1e]] + btx[n3][n2s][n1s] = [c for c in shield.px[0][n2e][n1e]] + btd1[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] + btd3[n3][n2s][n1s] = [c for c in shield.pd3[0][n2e][n1e]] elif ellipsenumber == 2: n1s = 0 for n3 in range(self._elementsCount[2] + 1): @@ -199,18 +326,187 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): n1e = self._elementsCount[2] - n3 if n3 == 0: if n2 == 0: - self._shield3D.pd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + btd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] elif 0 < n2 < self._elementsCount[0]: - self._shield3D.pd2[n3][n2][n1s] = [-c for c in shield.pd3[0][n2][n1e]] + btd2[n3][n2][n1s] = [-c for c in shield.pd3[0][n2][n1e]] else: if n2 < self._elementsCount[0]: - self._shield3D.pd2[n3][n2][n1s] = [c for c in alongAxis] + btd2[n3][n2][n1s] = [c for c in alongAxis] if shield.px[0][n2][n1e]: - self._shield3D.px[n3s][n2][n1s] = [c for c in shield.px[0][n2][n1e]] - self._shield3D.pd1[n3s][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - self._shield3D.pd3[n3s][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] + btx[n3s][n2][n1s] = [c for c in shield.px[0][n2][n1e]] + btd1[n3s][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + btd3[n3s][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] else: - self._shield3D.pd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + btd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + + def createAdditionalPointsForIncreasingElementsCount2(self): + """ + + :return: + """ + + self.calculate_surface_quadruple_point() + self.sample_triple_curves() + # self.calculate_regular_nodes2() + # + self._shield3D.getQuadruplePoint2() + self.fixD2DerivativesOnTheEllipses2() + n3z = self._elementsCount[2] + self._shield3D.smoothDerivativesToSurfaceQuadruple(n3z) + self.smoothDerivativesToSurface() + + def remap_ellipse_derivatives(self): + """ + + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + + + + # temp = btd2[1][1][0] + # btd2[1][1][0] = [-c for c in btd3[1][1][0]] + # btd3[1][1][0] = [c for c in temp] + # temp = btd2[n3b][n2b][n1b] + # btd2[n3b][n2b][n1b] = [c for c in btd1[n3b][n2b][n1b]] + # btd1[n3b][n2b][n1b] = temp + # temp = btd2[n3b][n2b][n1a] + # btd2[n3b][n2b][n1a] = [c for c in btd1[n3b][n2b][n1a]] + # btd1[n3b][n2b][n1a] = temp + + + + def calculate_surface_quadruple_point(self): + """ + Calculate coordinates and derivatives of points where 3 hex elements merge. + :return: + """ + + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + n1z = self._elementsCount[1] + n3z = self._elementsCount[2] + + radius = self._radius[0] # TODO need to be changed for spheroid + + elementsAroundEllipse12 = self._elementsCount[0] + self._elementsCount[1] - 2 + radiansAroundEllipse12 = math.pi / 2 + radiansPerElementAroundEllipse12 = radiansAroundEllipse12 / elementsAroundEllipse12 + elementsAroundEllipse13 = self._elementsCount[0] + self._elementsCount[2] - 2 + radiansAroundEllipse13 = math.pi / 2 + radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 + + theta_2 = radiansPerElementAroundEllipse13 + theta_3 = radiansPerElementAroundEllipse12 + phi_3 = calculate_azimuth(theta_3, theta_2) + # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead + x = spherical_to_cartesian(radius, theta_3, phi_3) + + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) + btx[n3z][0][n1z] = x + btd1[n3z][0][n1z] = a1 # initialise + btd2[n3z][0][n1z] = a2 # initialise + btd3[n3z][0][n1z] = a3 + + def sample_triple_curves(self): + """ + Sample points on the triple curves of quadruple point on the sphere surface. + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n3a = 0 + n1z = self._elementsCount[1] + n2z = self._elementsCount[0] + n3z = self._elementsCount[2] + + # sample on curve 1 of the triple curves and smooth the end derivatives. + nx, nd1 = sample_curves_sphere(btx[n3z][0][n1z], btx[n3z][n2z][n1z], self._elementsCount[0] - 1) + for nc in range(self._elementsCount[0]): + if nc == 0: + btd1[n3z][0][n1z] = nd1[0] + elif nc == n2z - 1: + btd2[n3z][n2z][n1z] = vector.scaleVector(nd1[-1], -1) + else: + btx[n3z][nc + 1][n1z] = nx[nc] + btd1[n3z][nc + 1][n1z] = nd1[nc] + + # smooth d2 curve + for n2 in range(n2a + 1, n2z): + a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][n2][n1z], self._axes[2]) + btd3[n3z][n2][n1z] = a3 + tx = [] + td2 = [] + for n1 in range(self._elementsCount[1] - 1): + tx.append(btx[n3z][n2][n1]) + td2.append(btd2[n3z][n2][n1]) + tx.append(btx[n3z][n2][n1z]) + td2.append(vector.crossproduct3(btd3[n3z][n2][n1z],btd1[n3z][n2][n1z])) + for n3 in range(self._elementsCount[2] - 2, -1, -1): + tx.append(btx[n3][n2][n1z]) + td2.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) + + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDirection=True) + + btd2[n3z][n2][0] = td2[0] + for n1 in range(1, self._elementsCount[1] - 1): + btd2[n3z][n2][n1] = td2[n1] + btd2[n3z][n2][n1z] = vector.scaleVector(td2[1], -1) + for n3 in range(self._elementsCount[2] - 2, -1, -1): + btd2[n3][n2][n1z] = vector.scaleVector(td2[-1 - n3], -1) + + # sample on curve 2 of the triple curves and smooth the end derivatives. + arcLength = calculate_arc_length(btx[n3z][0][n1z], btx[n3a][0][n1z]) + a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][0][n1z], self._axes[1]) + btd2[n3z][0][n1z] = vector.setMagnitude([-c for c in a2], arcLength) + btd2[0][0][n1z] = vector.setMagnitude(btd2[0][0][n1z], arcLength) + btd2[n3z][0][0] = vector.setMagnitude(btd2[n3z][0][0], arcLength) + + def calculate_regular_nodes2(self): + """ + Node 1,2,1. + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + if self._elementsCount[0] == 3: + # self.CreateRegularNodeOnBoundary() + n3 = 0 + n1 = 0 + for n2 in range(n2a + 1, n2b): + # First create the node for regular node. We are using the neighbour nodes x,y,z to do it but TODO eventualy we need to use the sampling between boundary nodes. + x = [btx[n3][n2][n1 + 1][0], btx[n3 + 1][n2 + 1][n1 + 1][1], btx[n3 + 1][n2][n1][2]] + btx[n3 + 1][n2][n1 + 1] = x + btd1[n3 + 1][n2][n1 + 1] = [(btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] + btd2[n3 + 1][n2][n1 + 1] = [-(btx[n3][n2][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] + btd3[n3 + 1][n2][n1 + 1] = [-(btx[n3 + 1][n2][n1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] + # using new point obtain the d2 derivatives of the neighbour nodes + btd2[n3 + 1][n2][n1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3 + 1][n2][n1][c] for c in range(3)] + btd2[n3][n2][n1 + 1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3][n2][n1 + 1][c] for c in range(3)] + btd2[n3 + 1][n2 + 1][n1 + 1] = [btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3][n2 + 1][n1 + 1][c] for c in range(3)] + + self.remapRegularCurvesOnEllipses() def createAdditionalPointsForIncreasingElementsCount(self): """ @@ -231,7 +527,7 @@ def createAdditionalPointsForIncreasingElementsCount(self): def calculate_regular_nodes(self): """ - + Node 1,2,1. :return: """ n3a = 0 @@ -241,36 +537,30 @@ def calculate_regular_nodes(self): n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + if self._elementsCount[0] == 3: self.CreateRegularNodeOnBoundary() n3 = 0 n1 = 0 for n2 in range(n2a + 1, n2b): - # First create the node for regular node. We are using the neighbour nodes x,y,z to do it but TODO eventully we need to use the sampling between boundary nodes. - x = [self._shield3D.px[n3][n2][n1 + 1][0], self._shield3D.px[n3 + 1][n2 + 1][n1 + 1][1], - self._shield3D.px[n3 + 1][n2][n1][2]] - self._shield3D.px[n3 + 1][n2][n1 + 1] = x - self._shield3D.pd1[n3 + 1][n2][n1 + 1] = [ - (self._shield3D.px[n3 + 1][n2 + 1][n1 + 1][c] - self._shield3D.px[n3 + 1][n2][n1 + 1][c]) for c in - range(3)] - self._shield3D.pd2[n3 + 1][n2][n1 + 1] = [ - -(self._shield3D.px[n3][n2][n1 + 1][c] - self._shield3D.px[n3 + 1][n2][n1 + 1][c]) for c in - range(3)] - self._shield3D.pd3[n3 + 1][n2][n1 + 1] = [ - -(self._shield3D.px[n3 + 1][n2][n1][c] - self._shield3D.px[n3 + 1][n2][n1 + 1][c]) for c in - range(3)] + # First create the node for regular node. We are using the neighbour nodes x,y,z to do it but TODO eventualy we need to use the sampling between boundary nodes. + x = [btx[n3][n2][n1 + 1][0], btx[n3 + 1][n2 + 1][n1 + 1][1], btx[n3 + 1][n2][n1][2]] + btx[n3 + 1][n2][n1 + 1] = x + btd1[n3 + 1][n2][n1 + 1] = [(btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] + btd2[n3 + 1][n2][n1 + 1] = [-(btx[n3][n2][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] + btd3[n3 + 1][n2][n1 + 1] = [-(btx[n3 + 1][n2][n1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] # using new point obtain the d2 derivatives of the neighbour nodes - self._shield3D.pd2[n3 + 1][n2][n1] = [ - self._shield3D.px[n3 + 1][n2][n1 + 1][c] - self._shield3D.px[n3 + 1][n2][n1][c] for c in range(3)] - self._shield3D.pd2[n3][n2][n1 + 1] = [ - self._shield3D.px[n3 + 1][n2][n1 + 1][c] - self._shield3D.px[n3][n2][n1 + 1][c] for c in range(3)] - self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] = [ - self._shield3D.px[n3 + 1][n2 + 1][n1 + 1][c] - self._shield3D.px[n3][n2 + 1][n1 + 1][c] for c in - range(3)] + btd2[n3 + 1][n2][n1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3 + 1][n2][n1][c] for c in range(3)] + btd2[n3][n2][n1 + 1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3][n2][n1 + 1][c] for c in range(3)] + btd2[n3 + 1][n2 + 1][n1 + 1] = [btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3][n2 + 1][n1 + 1][c] for c in range(3)] self.remapRegularCurvesOnEllipses() - def CreateRegularNodeOnBoundary(self): + def remapRegularCurvesOnEllipses(self): """ :return: @@ -282,6 +572,43 @@ def CreateRegularNodeOnBoundary(self): n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + # We need to remap the derivatives as we want d1 to be in -axis1 direction, d2, axis3 and d3, axis2. We need to think about the directions as well. e.g. + # d1, d2, d3 could be simply axis1,axis2 and axis3. However this one was chosen so it could be consistent with the cylinder mesh that makes joining them + # a little easier. TODO d1,d2,d3 directions in regular elements. + # for nodes on the ellipse2, d2 is -d3 and d3 is d2. TODO we can add another method to ellipse so it gives us what we expect for derivatives. + n3 = 0 + n1 = 0 + for n2 in range(n2a + 1, n2b): + temp = btd2[n3 + 1][n2][n1] + btd2[n3 + 1][n2][n1] = [-c for c in btd3[n3 + 1][n2][n1]] + btd3[n3 + 1][n2][n1] = temp + # for ellipse 1, swap d2 and d1 + temp = btd2[n3 + 1][n2 + 1][n1 + 1] + btd2[n3 + 1][n2 + 1][n1 + 1] = [c for c in btd1[n3 + 1][n2 + 1][n1 + 1]] + btd1[n3 + 1][n2 + 1][n1 + 1] = temp + + def CreateRegularNodeOnBoundary(self): + """ + Node 2,n2,2, triple curves or quadruple 0 or Q0. + :return: + """ + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + # create the other two nodes to create the elements. radius = self._radius[0] # TODO need to be changed for spheroid @@ -303,15 +630,15 @@ def CreateRegularNodeOnBoundary(self): radius * math.cos(phi_3)] a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - self._shield3D.px[n3 + 1][n2][n1 + 2] = x - self._shield3D.pd1[n3 + 1][n2][n1 + 2] = a1 - self._shield3D.pd2[n3 + 1][n2][n1 + 2] = a2 - self._shield3D.pd3[n3 + 1][n2][n1 + 2] = a3 + btx[n3 + 1][n2][n1 + 2] = x + btd1[n3 + 1][n2][n1 + 2] = a1 + btd2[n3 + 1][n2][n1 + 2] = a2 + btd3[n3 + 1][n2][n1 + 2] = a3 arcLength = radius * phi_3 - self._shield3D.pd2[n3 + 1][n2][n1 + 2] = vector.setMagnitude(self._shield3D.pd2[n3 + 1][n2][n1 + 2], arcLength) + btd2[n3 + 1][n2][n1 + 2] = vector.setMagnitude(btd2[n3 + 1][n2][n1 + 2], arcLength) - def remapRegularCurvesOnEllipses(self): + def fixD2DerivativesOnTheEllipses2(self): """ :return: @@ -323,20 +650,16 @@ def remapRegularCurvesOnEllipses(self): n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - # We need to remap the derivatives as we want d1 to be in -axis1 direction, d2, axis3 and d3, axis2. We need to think about the directions as well. e.g. - # d1, d2, d3 could be simply axis1,axis2 and axis3. However this one was chosen so it could be consistent with the cylinder mesh that makes joining them - # a little easier. TODO d1,d2,d3 directions in regular elements. - # for nodes on the ellipse2, d2 is -d3 and d3 is d2. TODO we can add another method to ellipse so it gives us what we expect for derivatives. - n3 = 0 - n1 = 0 - for n2 in range(n2a + 1, n2b): - temp = self._shield3D.pd2[n3 + 1][n2][n1] - self._shield3D.pd2[n3 + 1][n2][n1] = [-c for c in self._shield3D.pd3[n3 + 1][n2][n1]] - self._shield3D.pd3[n3 + 1][n2][n1] = temp - # for ellipse 1, swap d2 and d1 - temp = self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] - self._shield3D.pd2[n3 + 1][n2 + 1][n1 + 1] = [c for c in self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1]] - self._shield3D.pd1[n3 + 1][n2 + 1][n1 + 1] = temp + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + for n2 in range(self._elementsCount[0] + 1): + if n2a <= n2 < self._elementsCount[0]: + btd3[n3b][n2][n1a] = [btx[n3b][n2][n1b][c] - btx[n3b][n2][n1a][c] for c in range(3)] + btd2[0][n2][1] = [btx[1][n2][1][c] - btx[0][n2][1][c] for c in range(3)] + btd1[n3b][n2b][n1b] = [-(btx[n3b][n2b-1][n1b][c] - btx[n3b][n2b][n1b][c]) for c in range(3)] def fixD2DerivativesOnTheEllipses(self): """ @@ -350,11 +673,14 @@ def fixD2DerivativesOnTheEllipses(self): n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - self._shield3D.pd2[n3b][n2a][n1a] = [self._shield3D.px[n3b][n2a][n1b][c] - self._shield3D.px[n3b][n2a][n1a][c] - for c in range(3)] - self._shield3D.pd2[0][1][1] = [self._shield3D.px[1][1][1][c] - self._shield3D.px[0][1][1][c] for c in range(3)] - self._shield3D.pd2[n3b][n2b][n1b] = [ - -(self._shield3D.px[n3b][n2a][n1b][c] - self._shield3D.px[n3b][n2b][n1b][c]) for c in range(3)] + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + btd2[n3b][n2a][n1a] = [btx[n3b][n2a][n1b][c] - btx[n3b][n2a][n1a][c] for c in range(3)] + btd2[0][1][1] = [btx[1][1][1][c] - btx[0][1][1][c] for c in range(3)] + btd2[n3b][n2b][n1b] = [-(btx[n3b][n2a][n1b][c] - btx[n3b][n2b][n1b][c]) for c in range(3)] def remapDerivativesOnTheEllipses(self): """ @@ -368,15 +694,20 @@ def remapDerivativesOnTheEllipses(self): n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - temp = self._shield3D.pd2[1][1][0] - self._shield3D.pd2[1][1][0] = [-c for c in self._shield3D.pd3[1][1][0]] - self._shield3D.pd3[1][1][0] = [c for c in temp] - temp = self._shield3D.pd2[n3b][n2b][n1b] - self._shield3D.pd2[n3b][n2b][n1b] = [c for c in self._shield3D.pd1[n3b][n2b][n1b]] - self._shield3D.pd1[n3b][n2b][n1b] = temp - temp = self._shield3D.pd2[n3b][n2b][n1a] - self._shield3D.pd2[n3b][n2b][n1a] = [c for c in self._shield3D.pd1[n3b][n2b][n1a]] - self._shield3D.pd1[n3b][n2b][n1a] = temp + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + temp = btd2[1][1][0] + btd2[1][1][0] = [-c for c in btd3[1][1][0]] + btd3[1][1][0] = [c for c in temp] + temp = btd2[n3b][n2b][n1b] + btd2[n3b][n2b][n1b] = [c for c in btd1[n3b][n2b][n1b]] + btd1[n3b][n2b][n1b] = temp + temp = btd2[n3b][n2b][n1a] + btd2[n3b][n2b][n1a] = [c for c in btd1[n3b][n2b][n1a]] + btd1[n3b][n2b][n1a] = temp def calculate_surface_nodes(self): """ @@ -390,6 +721,11 @@ def calculate_surface_nodes(self): n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + radius = self._radius[0] # TODO need to be changed for spheroid elementsAroundEllipse12 = self._elementsCount[0] + self._elementsCount[1] - 2 @@ -403,43 +739,96 @@ def calculate_surface_nodes(self): theta_3 = radiansPerElementAroundEllipse12 phi_3 = calculate_azimuth(theta_3, theta_2) # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), - radius * math.cos(phi_3)] + # x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), + # radius * math.cos(phi_3)] + x = spherical_to_cartesian(radius, theta_3, phi_3) a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - self._shield3D.px[n3b + 1][0][n1b + 1] = x - self._shield3D.pd1[n3b + 1][0][n1b + 1] = a1 - self._shield3D.pd2[n3b + 1][0][n1b + 1] = a2 - self._shield3D.pd3[n3b + 1][0][n1b + 1] = a3 - - arcLength = calculate_arc_length(x, self._shield3D.px[n3a][0][n1b + 1], radius) - self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1], arcLength) - - - a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[0]) + btx[n3b + 1][0][n1b + 1] = x + # btd1[n3b + 1][0][n1b + 1] = a1 + # btd2[n3b + 1][0][n1b + 1] = a2 + btd3[n3b + 1][0][n1b + 1] = a3 + nx, nd1 = sample_curves_sphere(x, btx[n3b + 1][n2b][n1b + 1], self._elementsCount[0]-1) + for nc in range(self._elementsCount[0]): + if nc == 0: + btd1[n3b + 1][0][n1b + 1] = nd1[0] + elif nc == n2b-1: + btd2[n3b + 1][n2b][n1b + 1] = vector.scaleVector(nd1[-1], -1) + else: + btx[n3b + 1][nc+1][n1b + 1] = nx[nc] + btd1[n3b + 1][nc+1][n1b + 1] = nd1[nc] + + # for n2 in range(1, n2b - 1): + # for n1 in range(n1b+1): + # xi = 0.5 + # btd2[n3b + 1][n2][n1b + 1] = interpolateCubicHermite(btd2[0][n2][n1b + 1], [0, 0, 0], vector.scaleVector(btd2[n3b + 1][n2][0], -1), [0, 0, 0], xi) + if n2b > 2: + tx = [] + td2 = [] + n2 = 2 + for n1 in range(self._elementsCount[1] - 1): + tx.append(btx[n3b + 1][n2][n1]) + td2.append(btd2[n3b + 1][n2][n1]) + tx.append(btx[n3b + 1][n2][n1b + 1]) + td2.append(btd2[n3b + 1][n2][n1b + 1]) + for n3 in range(self._elementsCount[2] - 2, -1, -1): + tx.append(btx[n3][n2][n1b + 1]) + td2.append(vector.scaleVector(btd2[n3][n2][n1b + 1], -1)) + + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDirection=True) + + btd2[n3b + 1][n2][0] = td2[0] + for n1 in range(1, self._elementsCount[1] - 1): + btd2[n3b + 1][n2][n1] = td2[n1] + btd2[n3b + 1][n2][n1b + 1] = vector.scaleVector(td2[1], -1) + for n3 in range(self._elementsCount[2] - 2, -1, -1): + btd2[n3][n2][n1b + 1] = vector.scaleVector(td2[-1-n3], -1) + + + # btd + # for n2 in range(self._elementsCountAcrossMajor + 1): + # for n1 in range(self._elementsCountAcrossMinor + 1): + # td2 = [] + # tx = [] + # if btx[0][n2][n1]: + # for n3 in range(self._elementsCountAlong + 1): + # tx.append(btx[n3][n2][n1]) + # td2.append(btd2[n3][n2][n1]) + # td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True) + # for n3 in range(self._elementsCountAlong + 1): + # btd2[n3][n2][n1] = td2[n3] + + + + arcLength = calculate_arc_length(x, btx[n3a][0][n1b + 1]) + # btd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd2[n3b + 1][0][n1b + 1], arcLength) + + + + # a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[0]) # btd1 = [ - # self._shield3D.px[n3b + 1][n2b][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c] for c in range(3)] - self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) + # btx[n3b + 1][n2b][n1b + 1][c] - btx[n3b + 1][0][n1b + 1][c] for c in range(3)] + # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) self._shield3D.smoothDerivativesToSurfaceQuadruple(n3b+1) a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[1]) # btd1 = [ - # self._shield3D.px[n3b + 1][n2b][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c] for c in range(3)] - self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) - # self._shield3D.pd2[n3b + 1][0][n1b + 1] = [ - # -(self._shield3D.px[0][0][n1b + 1][c] - self._shield3D.px[n3b + 1][0][n3b + 1][c]) for c in range(3)] - # self._shield3D.pd3[n3b + 1][0][n1b + 1] = [ - # -(self._shield3D.px[1][1][1][c] - self._shield3D.px[n3b + 1][0][n1b + 1][c]) for c in range(3)] + # btx[n3b + 1][n2b][n1b + 1][c] - btx[n3b + 1][0][n1b + 1][c] for c in range(3)] + btd2[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) + # btd2[n3b + 1][0][n1b + 1] = [ + # -(btx[0][0][n1b + 1][c] - btx[n3b + 1][0][n3b + 1][c]) for c in range(3)] + # btd3[n3b + 1][0][n1b + 1] = [ + # -(btx[1][1][1][c] - btx[n3b + 1][0][n1b + 1][c]) for c in range(3)] n1a = 1 n2a = 1 n3a = 1 - self._shield3D.pd1[n3a][n2a][n1a] = [-(self._shield3D.px[n3a+1][n2a-1][n1a+1][0] - self._shield3D.px[n3a][n2a][n1a][0]), 0.0, 0.0] - self._shield3D.pd2[n3a][n2a][n1a] = [0.0, 0.0, (self._shield3D.px[n3a+1][n2a-1][n1a+1][2] - self._shield3D.px[n3a][n2a][n1a][2])] - self._shield3D.pd3[n3a][n2a][n1a] = [0.0, (self._shield3D.px[n3a+1][n2a-1][n1a+1][1] - self._shield3D.px[n3a][n2a][n1a][1]), 0.0] + btd1[n3a][n2a][n1a] = [-(btx[n3a+1][n2a-1][n1a+1][0] - btx[n3a][n2a][n1a][0]), 0.0, 0.0] + btd2[n3a][n2a][n1a] = [0.0, 0.0, (btx[n3a+1][n2a-1][n1a+1][2] - btx[n3a][n2a][n1a][2])] + btd3[n3a][n2a][n1a] = [0.0, (btx[n3a+1][n2a-1][n1a+1][1] - btx[n3a][n2a][n1a][1]), 0.0] def smooth_triple_curves(self): """ @@ -453,33 +842,76 @@ def smooth_triple_curves(self): n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + radius = 1.0 theta = math.atan(math.sqrt(1.0 / 2.0)) arclength = radius * theta - self._shield3D.pd2[0][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[0][0][n1b + 1], arclength) - self._shield3D.pd2[n3b + 1][0][0] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][0][0], arclength) - self._shield3D.pd2[n3b + 1][n2b][n1b + 1] = vector.setMagnitude(self._shield3D.pd2[n3b + 1][n2b][n1b + 1], - arclength) - # atz = vector.vectorRejection(self._shield3D.pd2[n3b + 1][0][n1b + 1], self._shield3D.pd3[n3b + 1][0][n1b + 1]) - # self._shield3D.pd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(atz, arclength) - atx = vector.vectorRejection(self._shield3D.pd1[n3b + 1][0][n1b + 1], self._shield3D.pd3[n3b + 1][0][n1b + 1]) - self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(atx, arclength) - - - # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.crossproduct3(self._shield3D.pd2[n3b + 1][0][n1b + 1], - # self._shield3D.pd3[n3b + 1][0][n1b + 1]) - # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], + btd2[0][0][n1b + 1] = vector.setMagnitude(btd2[0][0][n1b + 1], arclength) + btd2[n3b + 1][0][0] = vector.setMagnitude(btd2[n3b + 1][0][0], arclength) + + self.smoothDerivativesToSurface() + # btd2[n3b + 1][n2b][n1b + 1] = vector.setMagnitude(btd2[n3b + 1][n2b][n1b + 1], + # arclength) + # atz = vector.vectorRejection(btd2[n3b + 1][0][n1b + 1], btd3[n3b + 1][0][n1b + 1]) + # btd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(atz, arclength) + # atx = vector.vectorRejection(btd1[n3b + 1][0][n1b + 1], btd3[n3b + 1][0][n1b + 1]) + # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(atx, arclength) + + + # btd1[n3b + 1][0][n1b + 1] = vector.crossproduct3(btd2[n3b + 1][0][n1b + 1], + # btd3[n3b + 1][0][n1b + 1]) + # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd1[n3b + 1][0][n1b + 1], # arclength) - # dmag = calculate_arc_length(self._shield3D.px[n3b + 1][0][n1b + 1], self._shield3D.px[n3b + 1][2][n1b + 1], radius) - # d2mag = vector.magnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1]) + # dmag = calculate_arc_length(btx[n3b + 1][0][n1b + 1], btx[n3b + 1][2][n1b + 1], radius) + # d2mag = vector.magnitude(btd2[n3b + 1][0][n1b + 1]) # d1mag = math.sqrt(dmag*dmag - d2mag*d2mag) - # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], d1mag) - # d2mag = vector.magnitude(self._shield3D.pd2[n3b + 1][0][n1b + 1]) + # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd1[n3b + 1][0][n1b + 1], d1mag) + # d2mag = vector.magnitude(btd2[n3b + 1][0][n1b + 1]) # thetad1ncurve = math.pi / 6 - # self._shield3D.pd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(self._shield3D.pd1[n3b + 1][0][n1b + 1], + # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd1[n3b + 1][0][n1b + 1], # d2mag / math.tan(thetad1ncurve)) + def smoothDerivativesToSurface(self): + ''' + Smooth derivatives leading to quadruple point where 3 hex elements merge. + :param n3: Index of through-wall coordinates to use. + ''' + n3a = 0 + n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n2b = self._elementsCount[0] + n1a = 0 + n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + for n2 in range(self._elementsCount[0] + 1): + if 1 < n2 < self._elementsCount[0]: + tx = [] + td3 = [] + for n3 in range(n3b, n3b+2): + n1 = n3 + tx.append(btx[n3][n2][n1]) + if n3 == n3b: + td3.append(vector.addVectors(btd2[n3][n2][n1], btd3[n3][n2][n1])) + else: + td3.append(btd3[n3][n2][n1]) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + + for nc3 in range(1, self._elementsCountAcrossShell + self._elementsCountAcrossTransition + 1): + n3 = nc3 + n3b + n1 = n3 + btd3[n3][n2][n1] = td3[nc3] + def generateNodes(self, nodes, fieldModule, coordinates): """ @@ -532,12 +964,59 @@ def local_orthogonal_unit_vectors(x, axis3): return e1, e2, e3 -def calculate_arc_length(x1, x2, radius): +def calculate_arc_length(x1, x2): """ Calculate the arc length between points x1 and x2. :param x1, x2: points coordinates. - :param radius: sphere radius. :return: arc length """ + radius = vector.magnitude(x1) angle = vector.angleBetweenVectors(x1, x2) return radius * angle + + +def sample_curves_sphere(x1, x2, elementsOut): + """ + + :param x1, x2: points coordinates. + :param elementsOut: + :return: + """ + deltax = vector.addVectors(x1, x2, -1, 1) + normal = vector.crossproduct3(x1, deltax) + angle = vector.angleBetweenVectors(x1, x2) + anglePerElement = angle/elementsOut + arcLengthPerElement = calculate_arc_length(x1, x2)/elementsOut + + nx = [] + nd1 = [] + for n1 in range(elementsOut + 1): + radiansAcross = n1 * anglePerElement + x = vector.rotateVectorAroundVector(x1, normal, radiansAcross) + d1 = vector.setMagnitude(vector.crossproduct3(normal, x), arcLengthPerElement) + nx.append(x) + nd1.append(d1) + + return nx, nd1 + + +def spherical_to_cartesian(r, theta, phi): + """ + :param r: Radius. + :param theta: in radians. + :param phi: azimuth angle in radians + :return: x=[x1, x2, x3] coordinates. + """ + return [r*math.sin(phi)*math.cos(theta), r*math.sin(phi)*math.sin(theta), r*math.cos(phi)] + + +def cartesian_to_spherical(x): + """ + :return: [r, theta, phi]. + """ + r = vector.magnitude(x) + theta = math.atan2(x[1], x[0]) + phi = math.acos(x[2]/r) + return r, theta, phi + + From 09e2ad8a951001f29eeed9e31ecd5e282d22d7b4 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 10 Sep 2021 14:23:04 +1200 Subject: [PATCH 11/37] Make number of elements across y direction configurable. --- src/scaffoldmaker/utils/shieldmesh.py | 363 ++++++++++++++++++++------ src/scaffoldmaker/utils/spheremesh.py | 169 +++++++++--- 2 files changed, 424 insertions(+), 108 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 572f1113..985da7b7 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -74,41 +74,142 @@ def getQuadruplePoint2(self): :return: """ - n1a = 1 + n1z = self.elementsCountAcross[1] + n1y = n1z - 1 + n1a = self.elementsCountAcross[1] - 1 n2a = 1 n3a = 1 + n3z = self.elementsCountAcross[2] + n3y = n3z - 1 + n2z = self.elementsCountAcross[0] # n2b = self.elementsCountAcross[0] - for n2 in range(self.elementsCountAcross[0]): - if n2 > 0: - x = [self.px[0][n2][n1a][0], self.px[0][n2][n1a][1],self.px[n3a][n2][0][2]] - self.px[n3a][n2][n1a] = x - n2r = n2 - 1 if n2 == 1 else n2 - if n2 == 1: - self.pd1[n3a][n2][n1a] = [-(self.px[n3a + 1][n2r][n1a + 1][0] - self.px[n3a][n2][n1a][0]), 0.0, 0.0] - else: - self.pd1[n3a][n2][n1a] = self.pd1[0][n2][n1a] - self.pd2[n3a][n2][n1a] = [0.0, 0.0, (self.px[n3a + 1][n2r][n1a + 1][2] - self.px[n3a][n2][n1a][2])] - self.pd3[n3a][n2][n1a] = [0.0, (self.px[n3a + 1][n2r][n1a + 1][1] - self.px[n3a][n2][n1a][1]), 0.0] - - n3 = 1 - n1 = 1 + # for n2 in range(self.elementsCountAcross[0]): + # if n2 > 0: + # x = [self.px[0][n2][n1a][0], self.px[0][n2][n1a][1],self.px[n3a][n2][0][2]] + # self.px[n3a][n2][n1a] = x + # n2r = n2 - 1 if n2 == 1 else n2 + # if n2 == 1: + # self.pd1[n3a][n2][n1a] = [-(self.px[n3a + 1][n2r][n1a + 1][0] - self.px[n3a][n2][n1a][0]), 0.0, 0.0] + # else: + # self.pd1[n3a][n2][n1a] = self.pd1[0][n2][n1a] + # self.pd2[n3a][n2][n1a] = [0.0, 0.0, (self.px[n3a + 1][n2r][n1a + 1][2] - self.px[n3a][n2][n1a][2])] + # self.pd3[n3a][n2][n1a] = [0.0, (self.px[n3a + 1][n2r][n1a + 1][1] - self.px[n3a][n2][n1a][1]), 0.0] + + # n3 = 1 + # n1 = 1 + self.elementsCountAcross[1] - 2 + # tx = [] + # td1 = [] + # for n2 in range(self.elementsCountAcross[0] + 1): + # if n2 > 0: + # tx.append(self.px[n3][n2][n1]) + # td1.append(self.pd1[n3][n2][n1]) + # + # td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) + # + # for n2 in range(self.elementsCountAcross[0] + 1): + # if n2 > 1: + # n2t = n2 - 1 + # self.pd1[n3][n2][n1] = td1[n2t] + + x = [min(self.px[0][1][n1y][0], self.px[n3y][1][0][0]), + min(self.px[0][1][n1y][1], self.px[n3y][n2z][n1y][1]), + min(self.px[n3y][1][0][2], self.px[n3y][n2z][n1y][2])] + self.px[n3a][1][n1a] = x + n2r = 0 + self.pd1[n3a][1][n1a] = [-(self.px[n3a + 1][n2r][n1a + 1][0] - self.px[n3a][1][n1a][0]), 0.0, 0.0] + self.pd2[n3a][1][n1a] = [0.0, 0.0, (self.px[n3a + 1][n2r][n1a + 1][2] - self.px[n3a][1][n1a][2])] + self.pd3[n3a][1][n1a] = [0.0, (self.px[n3a + 1][n2r][n1a + 1][1] - self.px[n3a][1][n1a][1]), 0.0] + + # curve 1 + tx, td1 = sampleCubicHermiteCurves([self.px[n3z-1][1][n1y], self.px[n3z-1][n2z][n1y]], + [self.pd1[0][1][n1y], self.pd1[0][n2z][n1y]], self.elementsCountAcross[0] - 1)[:2] + + for n2 in range(2, self.elementsCountAcross[0]): + self.px[n3z-1][n2][n1y] = tx[n2-1] + self.pd1[n3z-1][n2][n1y] = td1[n2-1] + self.pd2[n3z-1][n2][n1y] = [0.0, 0.0, (self.px[n3z][n2][n1z][2] - self.px[n3z-1][n2][n1y][2])] + self.pd3[n3z-1][n2][n1y] = [0.0, (self.px[n3z][n2][n1z][1] - self.px[n3z-1][n2][n1y][1]), 0.0] + + # smooth d1 in curve1 tx = [] td1 = [] - for n2 in range(self.elementsCountAcross[0] + 1): - if n2 > 0: - tx.append(self.px[n3][n2][n1]) - td1.append(self.pd1[n3][n2][n1]) + for n2 in range(1, self.elementsCountAcross[0]+1): + tx.append(self.px[n3z-1][n2][n1y]) + td1.append(self.pd1[n3z-1][n2][n1y]) td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) + for n2 in range(2, self.elementsCountAcross[0]+1): + self.pd1[n3z-1][n2][n1y] = td1[n2-1] + + + # curve 2 and parallel curves + for n2 in range(1, self.elementsCountAcross[0]): + tx, td3 = sampleCubicHermiteCurves([self.px[1][n2][0], self.px[1][n2][n1a]], + [self.pd3[0][n2][0], self.pd3[0][n2][n1a]], self.elementsCountAcross[1] - 1)[:2] + + for n1 in range(1, self.elementsCountAcross[1] - 1): + self.px[1][n2][n1] = tx[n1] + self.pd3[1][n2][n1] = td3[n1] + if n2 == 1: + self.pd1[1][n2][n1] = [self.px[1][1][n1][0] - self.px[n3z][0][n1][0], 0.0, 0.0] + self.pd2[1][n2][n1] = [0.0, 0.0, -self.px[1][1][n1][2] + self.px[n3z][0][n1][2]] + else: + self.pd1[1][n2][n1] = vector.addVectors(self.px[1][n2][n1], self.px[1][n2+1][n1], -1, 1) + self.pd2[1][n2][n1] = vector.addVectors(self.px[1][n2][n1], self.px[0][n2][n1], 1, -1) + + tx = [] + td3 = [] + for n1 in range(self.elementsCountAcross[1]): + tx.append(self.px[1][n2][n1]) + td3.append(self.pd3[1][n2][n1]) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True) + + for n1 in range(self.elementsCountAcross[1]-1): + self.pd3[1][n2][n1] = td3[n1] + + # smooth d1 in regular 1 + for n1 in range(1, self.elementsCountAcross[1] - 1): + tx = [] + td1 = [] + for n2 in range(1, self.elementsCountAcross[0]+1): + tx.append(self.px[1][n2][n1]) + td1.append(self.pd1[1][n2][n1]) + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) + for n2 in range(1, self.elementsCountAcross[0]+1): + self.pd1[1][n2][n1] = td1[n2-1] + + # regular curves d2 + for n2 in range(1, self.elementsCountAcross[0]): + for n1 in range(1, self.elementsCountAcross[1]): + tx = [] + td2 = [] + for n3 in range(2): + tx.append(self.px[n3][n2][n1]) + td2.append(self.pd2[n3][n2][n1]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDerivative=True) + for n3 in range(1): + self.pd2[n3][n2][n1] = td2[n3] + + + # smooth d3 on the surface of regular ones. + # for n2 in range(self.elementsCountAcross[0]): + # for n1 in range(1, self.elementsCountAcross[1]+1): + # if self.px[n3z][n2][n1]: + # if n2 == 0: + # if n1 == n1z: + # xin = self.px[n3z-1][n2+1][n1-1] + # else: + # xin = self.px[n3z - 1][n2 + 1][n1] + # else: + # xin = self.px[n3z - 1][n2][n1 - 1] + # + # self.pd3[n3z][n2][n1] = vector.setMagnitude(self.pd3[n3z][n2][n1], mag) + + + - for n2 in range(self.elementsCountAcross[0] + 1): - if n2 > 1: - n2t = n2 - 1 - self.pd1[n3][n2][n1] = td1[n2t] - # self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2a+1][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] - # self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] - # self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] def getQuadruplePoint(self): """ @@ -228,8 +329,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes # isEven = (self.elementsCountAcross % 2) == 0 e1a = self.elementsCountRim e1b = e1a + 1 - # e1z = self.elementsCountAcross[1] - 1 - self.elementsCountRim - # e1y = e1z - 1 + e1z = self.elementsCountAcross[1] - 1 - self.elementsCountRim + e1y = e1z - 1 e2a = self.elementsCountRim e2b = self.elementsCountRim + 1 e2c = self.elementsCountRim + 2 @@ -241,10 +342,10 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes for e1 in range(self.elementsCountAcross[1]): eft1 = eft scalefactors = None - if e3 == 0 and e2 > e2a and e1 == 0: + if e3 == 0 and e2 > e2a and e1 < e1z: nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+1][e2][e1+1],self.nodeId[e3+1][e2+1][e1+1]] - elif e3 == 0 and e2 == 0 and e1 == 0: + elif e3 == 0 and e2 == 0 and e1 == e1y: nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+2][e2][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2][e1+2],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2][e1+2],self.nodeId[e3+1][e2+1][e1+1]] @@ -252,14 +353,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) - - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS1, @@ -269,7 +364,38 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) - elif e3 == 0 and e2 >= e2b and e1 == 1: + + if e1y == 0: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + else: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + + + elif e3 == 0 and e2 == 0 and e1= e2b and e1 == e1z: if e2 == 1: e2r = e2 - 1 else: @@ -277,27 +403,33 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3][e2r][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2r][e1+1],self.nodeId[e3+2][e2+1][e1+1]] - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - + if e2 == e2b or e2 == e2z: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) if e2 == e2b: remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + if e2b == e2z: + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elif e2 == e2z: + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - if e2 == e2z: remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - elif e3 == 1 and e2 >= e2b and e1 == 0: + elif e3 == 1 and e2 >= e2b and e1 == e1y: if e2 == 1: e2r = e2 - 1 else: @@ -310,42 +442,125 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes scalefactors = [-1.0] - - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap - - if e2 == e2b: remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - - if e2 == e2z: - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - else: - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + if e2b == e2z: + + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + if e1y == 0: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + else: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + else: + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + if e1y == 0: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + else: + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + elif e2 == e2z: + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) # finish swap - remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - - + if e1y == 0: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + else: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + else: + if e1y == 0: + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [7, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [7, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + elif e3 == 1 and e2 >= e2b and e1 < e1y: + if e2 == e2b: + e2r = e2 - 1 + else: + e2r = e2 + nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2r][e1], self.nodeId[e3+1][e2+1][e1], + self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2r][e1+1], self.nodeId[e3+1][e2+1][e1+1]] + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + if e2 == e2b: + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + # remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + # remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + # remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + if e2 == e2z: + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + if e1 == 0: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + else: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + else: + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + # remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + elif e2 == e2z: + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) else: continue diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 44c05899..eaa52839 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -403,17 +403,20 @@ def calculate_surface_quadruple_point(self): radiansAroundEllipse13 = math.pi / 2 radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 - theta_2 = radiansPerElementAroundEllipse13 - theta_3 = radiansPerElementAroundEllipse12 - phi_3 = calculate_azimuth(theta_3, theta_2) - # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - x = spherical_to_cartesian(radius, theta_3, phi_3) + for n in range(min(self._elementsCount[0], self._elementsCount[1]) - 1): + theta_2 = (n+1) * radiansPerElementAroundEllipse13 + theta_3 = (self._elementsCount[1] - 1) * radiansPerElementAroundEllipse12 + phi_3 = calculate_azimuth(theta_3, theta_2) + # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead + x = spherical_to_cartesian(radius, theta_3, phi_3) - a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - btx[n3z][0][n1z] = x - btd1[n3z][0][n1z] = a1 # initialise - btd2[n3z][0][n1z] = a2 # initialise - btd3[n3z][0][n1z] = a3 + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) + n1 = self._elementsCount[1] - n if n == 0 else self._elementsCount[1] - n - 1 + n2 = n if n == 0 else n+1 + btx[n3z][n2][n1] = x + btd1[n3z][n2][n1] = a1 # initialise + btd2[n3z][n2][n1] = a2 # initialise + btd3[n3z][n2][n1] = a3 def sample_triple_curves(self): """ @@ -461,17 +464,78 @@ def sample_triple_curves(self): btd2[n3z][n2][0] = td2[0] for n1 in range(1, self._elementsCount[1] - 1): - btd2[n3z][n2][n1] = td2[n1] - btd2[n3z][n2][n1z] = vector.scaleVector(td2[1], -1) + btd2[n3z][n2][n1] = vector.scaleVector(td2[n1], -1) + btd2[n3z][n2][n1z] = vector.scaleVector(td2[self._elementsCount[1] - 1], -1) for n3 in range(self._elementsCount[2] - 2, -1, -1): btd2[n3][n2][n1z] = vector.scaleVector(td2[-1 - n3], -1) - # sample on curve 2 of the triple curves and smooth the end derivatives. - arcLength = calculate_arc_length(btx[n3z][0][n1z], btx[n3a][0][n1z]) - a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][0][n1z], self._axes[1]) - btd2[n3z][0][n1z] = vector.setMagnitude([-c for c in a2], arcLength) + # curve 2 + nx, nd1 = sample_curves_sphere(btx[n3z][0][0], btx[n3z][0][n1z], self._elementsCount[1] - 1) + for n1 in range(self._elementsCount[1]+1): + if n1 == n1z-1: + continue + if n1 == 0: + btd2[n3z][0][0] = nd1[0] + elif n1 == n1z: + btd2[n3z][0][n1z] = vector.scaleVector(nd1[-1], -1) + else: + btx[n3z][0][n1] = nx[n1] + btd2[n3z][0][n1] = vector.scaleVector(nd1[n1], -1) + + # smooth d1 curve + for n1 in range(1, n1z - 1): + a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][0][n1], self._axes[2]) + btd3[n3z][0][n1] = a3 + tx = [] + td1 = [] + tx.append(btx[0][0][n1]) + td1.append(btd2[0][0][n1]) + for n3 in range(1, self._elementsCount[2] - 1): + tx.append(btx[n3][0][n1]) + td1.append(btd1[n3][0][n1]) + tx.append(btx[n3z][0][n1]) + td1.append(vector.crossproduct3(btd2[n3z][0][n1], btd3[n3z][0][n1])) + for n2 in range(2, self._elementsCount[0]): + tx.append(btx[n3z][n2][n1]) + td1.append(btd1[n3z][n2][n1]) + tx.append(btx[n3z][n2z][n1]) + td1.append(vector.scaleVector(btd2[n3z][n2z][n1], -1)) + + # for n2 in range(self._elementsCount[1] - 1): + # tx.append(btx[n3z][n2][n1]) + # td1.append(btd2[n3z][n2][n1]) + # tx.append(btx[n3z][n2][n1z]) + # td1.append(vector.crossproduct3(btd3[n3z][n2][n1z],btd1[n3z][n2][n1z])) + # for n3 in range(self._elementsCount[2] - 2, -1, -1): + # tx.append(btx[n3][n2][n1z]) + # td1.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) + + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) + btd2[0][0][n1] = td1[0] + for n3 in range(1, self._elementsCount[2] - 1): + btd1[n3][0][n1] = td1[n3] + btd1[n3z][0][n1] = td1[self._elementsCount[2] - 1] + for n2 in range(2, self._elementsCount[0]): + btd1[n3z][n2][n1] = td1[self._elementsCount[2] + n2-2] + btd2[n3z][n2z][n1] = vector.scaleVector(td1[-1], -1) + + + + # btd2[n3z][n2][0] = td1[0] + # for n1 in range(1, self._elementsCount[1] - 1): + # btd2[n3z][n2][n1] = td1[n1] + # btd2[n3z][n2][n1z] = vector.scaleVector(td1[1], -1) + # for n3 in range(self._elementsCount[2] - 2, -1, -1): + # btd2[n3][n2][n1z] = vector.scaleVector(td1[-1 - n3], -1) + + + + + + # sample on curve 3 of the triple curves and smooth the end derivatives. + arcLength = calculate_arc_length(btx[0][0][n1z], btx[n3z][0][n1z]) btd2[0][0][n1z] = vector.setMagnitude(btd2[0][0][n1z], arcLength) - btd2[n3z][0][0] = vector.setMagnitude(btd2[n3z][0][0], arcLength) + def calculate_regular_nodes2(self): """ @@ -655,11 +719,12 @@ def fixD2DerivativesOnTheEllipses2(self): btd2 = self._shield3D.pd2 btd3 = self._shield3D.pd3 + n1 = 1 + self._elementsCount[1] - 2 for n2 in range(self._elementsCount[0] + 1): if n2a <= n2 < self._elementsCount[0]: btd3[n3b][n2][n1a] = [btx[n3b][n2][n1b][c] - btx[n3b][n2][n1a][c] for c in range(3)] - btd2[0][n2][1] = [btx[1][n2][1][c] - btx[0][n2][1][c] for c in range(3)] - btd1[n3b][n2b][n1b] = [-(btx[n3b][n2b-1][n1b][c] - btx[n3b][n2b][n1b][c]) for c in range(3)] + btd2[0][n2][n1] = [btx[1][n2][n1][c] - btx[0][n2][n1][c] for c in range(3)] + # btd1[n3b][n2b][n1b] = [-(btx[n3b][n2b-1][n1b][c] - btx[n3b][n2b][n1b][c]) for c in range(3)] def fixD2DerivativesOnTheEllipses(self): """ @@ -882,35 +947,71 @@ def smoothDerivativesToSurface(self): :param n3: Index of through-wall coordinates to use. ''' n3a = 0 + n3z = self._elementsCount[2] n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) n2b = self._elementsCount[0] n1a = 0 n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + n1z = self._elementsCount[1] btx = self._shield3D.px btd1 = self._shield3D.pd1 btd2 = self._shield3D.pd2 btd3 = self._shield3D.pd3 - for n2 in range(self._elementsCount[0] + 1): - if 1 < n2 < self._elementsCount[0]: - tx = [] - td3 = [] - for n3 in range(n3b, n3b+2): - n1 = n3 - tx.append(btx[n3][n2][n1]) - if n3 == n3b: - td3.append(vector.addVectors(btd2[n3][n2][n1], btd3[n3][n2][n1])) + for n2 in range(self._elementsCount[0]): + for n1 in range(1, self._elementsCount[1]+1): + if btx[n3z][n2][n1]: + tx = [] + td3 = [] + if n2 == 0: + if n1 == n1z: + n2r = n2 + 1 + n1r = n1 - 1 + co = [-1, 1, 1] + else: + n2r = n2 + 1 + n1r = n1 + co = [-1, 1, 0] else: + if n1 == n1z: + n2r = n2 + n1r = n1 - 1 + co = [0, 1, 1] + else: + n2r = n2 + n1r = n1 + co = [0, 1, 0] + + tx.append(btx[n3z-1][n2r][n1r]) + td3.append( + [(co[0]*btd1[n3z-1][n2r][n1r][c] + co[1]*btd2[n3z-1][n2r][n1r][c] + co[2]*btd3[n3z-1][n2r][n1r][c]) for c in range(3)]) + for n3 in range(n3z, n3z + 1): + tx.append(btx[n3][n2][n1]) td3.append(btd3[n3][n2][n1]) + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + for n3 in range(n3z, n3z + 1): + btd3[n3][n2][n1] = td3[n3 - n3z + 1] - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - - for nc3 in range(1, self._elementsCountAcrossShell + self._elementsCountAcrossTransition + 1): - n3 = nc3 + n3b - n1 = n3 - btd3[n3][n2][n1] = td3[nc3] + # for n2 in range(self._elementsCount[0] + 1): + # if 1 < n2 < self._elementsCount[0]: + # tx = [] + # td3 = [] + # for n3 in range(n3b, n3b+2): + # n1 = self._elementsCount[1] - 2 + n3 + # tx.append(btx[n3][n2][n1]) + # if n3 == n3b: + # td3.append(vector.addVectors(btd2[n3][n2][n1], btd3[n3][n2][n1])) + # else: + # td3.append(btd3[n3][n2][n1]) + # + # td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + # + # for nc3 in range(1, self._elementsCountAcrossShell + self._elementsCountAcrossTransition + 1): + # n3 = nc3 + n3b + # n1 = n3 + # btd3[n3][n2][n1] = td3[nc3] def generateNodes(self, nodes, fieldModule, coordinates): From 31a3dcba7292f7972450243a6bc52ecacf71d17b Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Mon, 13 Sep 2021 18:55:28 +1200 Subject: [PATCH 12/37] Make remaps in generating elements easier to modify. --- src/scaffoldmaker/utils/shieldmesh.py | 422 +++++++++++++------- src/scaffoldmaker/utils/spheremesh.py | 544 +------------------------- 2 files changed, 279 insertions(+), 687 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 985da7b7..ee972c67 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -304,6 +304,47 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan return nodeIdentifier + # node types + CORNER_1 = 1 + CORNER_2 = 29 + CORNER_3 = 28 + + QUADRUPLE_DOWN_LEFT = 6 + QUADRUPLE_RIGHT = 12 + QUADRUPLE_UP = 18 + QUADRUPLE0_DOWN_LEFT = 7 + QUADRUPLE0_RIGHT = 11 + QUADRUPLE0_UP = 30 + + TRIPLE_12_LEFT = 5 + TRIPLE_12_RIGHT = 9 + TRIPLE_13_DOWN = 2 + TRIPLE_13_UP = 21 + TRIPLE_23_UP = 20 + TRIPLE_23_DOWN = 14 + TRIPLE0_12_LEFT = 32 + TRIPLE0_12_RIGHT = 33 + TRIPLE0_13_DOWN = 4 + TRIPLE0_13_Up = 27 + TRIPLE0_23_DOWN = 13 + TRIPLE0_23_UP = 26 + + + BOUNDARY_12 = 3 + BOUNDARY_13 = 24 + BOUNDARY_23 = 19 + + TRIPLE_CURVE_1_DOWN = 15 + TRIPLE_CURVE_1_UP = 23 + TRIPLE_CURVE_2_DOWN = 8 + TRIPLE_CURVE_2_UP = 22 + TRIPLE_CURVE0_1_UP = 17 + TRIPLE_CURVE0_1_DOWN = 31 + TRIPLE_CURVE0_2_DOWN = 10 + TRIPLE_CURVE0_2_UP = 16 + + SURFACE_REGULAR = 25 + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): """ Create shield elements from nodes. @@ -337,235 +378,193 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes e2z = self.elementsCountAcross[0] - 1 # e2y = e2z - 1 # e2x = e2z - 2 + for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): for e1 in range(self.elementsCountAcross[1]): eft1 = eft scalefactors = None - if e3 == 0 and e2 > e2a and e1 < e1z: - nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+1][e2][e1+1],self.nodeId[e3+1][e2+1][e1+1]] - elif e3 == 0 and e2 == 0 and e1 == e1y: - nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+2][e2][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2][e1+2],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2][e1+2],self.nodeId[e3+1][e2+1][e1+1]] + nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3 + 1][e2][e1], self.nodeId[e3 + 1][e2 + 1][e1], + self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3 + 1][e2][e1 + 1], self.nodeId[e3 + 1][e2 + 1][e1 + 1]] + + element_regular = (e3 == 0 and e2 > e2a and e1 < e1z) + element_quadruple_down_left = (e3 == 0 and e2 == 0 and e1 == e1y) + element_quadruple_down_right = (e3 == 0 and e2 >= e2b and e1 == e1z) + element_quadruple_up_left = (e3 == 1 and e2 >= e2b and e1 == e1y) + element_quadruple_down = (e3 == 0 and e2 == 0 and e1 < e1y) + element_quadruple_up = (e3 == 1 and e2 >= e2b and e1 < e1y) + + if element_regular: + pass + elif element_quadruple_down_left: + nids[2] = self.nodeId[e3+2][e2][e1] + nids[4] = self.nodeId[e3][e2][e1+2] + nids[6] = self.nodeId[e3+2][e2][e1+2] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) + self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_12_LEFT) + self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_12_LEFT) + self.remap_eft_node_value_label(eft1, [7], self.QUADRUPLE_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [8], self.QUADRUPLE0_DOWN_LEFT) if e1y == 0: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_13_DOWN) + self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_DOWN) else: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - + self.remap_eft_node_value_label(eft1, [4], self.TRIPLE_CURVE0_2_DOWN) + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12) + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_DOWN) - elif e3 == 0 and e2 == 0 and e1= e2b and e1 == e1z: + elif element_quadruple_down_right: if e2 == 1: e2r = e2 - 1 else: e2r = e2 - nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1],self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2r][e1+1],self.nodeId[e3][e2+1][e1+1],self.nodeId[e3+2][e2r][e1+1],self.nodeId[e3+2][e2+1][e1+1]] + + nids[4] = self.nodeId[e3][e2r][e1+1] + nids[6] = self.nodeId[e3+2][e2r][e1+1] + nids[7] = self.nodeId[e3+2][e2+1][e1+1] if e2 == e2b or e2 == e2z: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - if e2 == e2b: - remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + self.remap_eft_node_value_label(eft1, [1], self.TRIPLE0_12_RIGHT) + self.remap_eft_node_value_label(eft1, [3], self.QUADRUPLE0_RIGHT) + self.remap_eft_node_value_label(eft1, [7], self.QUADRUPLE_RIGHT) if e2b == e2z: - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_23_DOWN) + self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_DOWN) elif e2 == e2z: - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE0_1_DOWN) + self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_23_DOWN) + self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_DOWN) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - - elif e3 == 1 and e2 >= e2b and e1 == e1y: + elif element_quadruple_up_left: if e2 == 1: e2r = e2 - 1 else: e2r = e2 - nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2r][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2r][e1+2], self.nodeId[e3+1][e2+1][e1+2]] + nids[2] = self.nodeId[e3+1][e2r][e1] + nids[6] = self.nodeId[e3+1][e2r][e1+2] + nids[7] = self.nodeId[e3+1][e2+1][e1+2] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - if e2 == e2b: - remapEftNodeValueLabel(eft1, [1], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [1], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [6], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [7], self.QUADRUPLE_UP) if e2b == e2z: - - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) + self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_UP) if e1y == 0: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) else: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) else: - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_CURVE_1_UP) if e1y == 0: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13) else: - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR) elif e2 == e2z: - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_UP) + self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_23_UP) + self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_1_UP) if e1y == 0: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) + self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13) else: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) + self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR) else: if e1y == 0: - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps - remapEftNodeValueLabel(eft1, [5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [7, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - - elif e3 == 1 and e2 >= e2b and e1 < e1y: + self.remap_eft_node_value_label(eft1, [3, 4], self.BOUNDARY_13) + self.remap_eft_node_value_label(eft1, [5, 6], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_UP) + + elif element_quadruple_up: if e2 == e2b: e2r = e2 - 1 else: e2r = e2 - nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2r][e1], self.nodeId[e3+1][e2+1][e1], - self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2r][e1+1], self.nodeId[e3+1][e2+1][e1+1]] + + nids[2] = self.nodeId[e3+1][e2r][e1] + nids[6] = self.nodeId[e3+1][e2r][e1+1] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] if e2 == e2b: - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - # remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - # remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - # remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - if e2 == e2z: - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + if e1 == 0: + self.remap_eft_node_value_label(eft1, [1], self.TRIPLE0_13_Up) + else: + self.remap_eft_node_value_label(eft1, [1], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_2_UP) + if e2b == e2z: + self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23) if e1 == 0: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) + self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) else: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) else: - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - # remapEftNodeValueLabel(eft1, [4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3, 4], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - + if e1 == 0: + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13) + else: + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR) + self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR) elif e2 == e2z: - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [3], Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + if e1 == 0: + self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13) + self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) + else: + self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) + self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR) + self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23) else: continue - if eft1 is not eft: elementtemplate1.defineField(coordinates, -1, eft1) element = mesh.createElement(elementIdentifier, elementtemplate1) @@ -583,6 +582,125 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes return elementIdentifier + def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): + """ + remaps derivatives for common types of nodes. + :return: + """ + if NODE_TYPE == self.CORNER_1: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + elif NODE_TYPE == self.CORNER_2: + pass + elif NODE_TYPE == self.CORNER_3: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + elif NODE_TYPE == self.QUADRUPLE_DOWN_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + elif NODE_TYPE == self.QUADRUPLE_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elif NODE_TYPE == self.QUADRUPLE_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.QUADRUPLE0_DOWN_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) + elif NODE_TYPE == self.QUADRUPLE0_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.QUADRUPLE0_UP: + pass + + elif NODE_TYPE == self.TRIPLE_12_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + elif NODE_TYPE == self.TRIPLE_12_RIGHT: + pass + elif NODE_TYPE == self.TRIPLE_13_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + elif NODE_TYPE == self.TRIPLE_13_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + elif NODE_TYPE == self.TRIPLE_23_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elif NODE_TYPE == self.TRIPLE_23_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE0_12_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) + elif NODE_TYPE == self.TRIPLE0_12_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE0_13_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + elif NODE_TYPE == self.TRIPLE0_13_Up: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elif NODE_TYPE == self.TRIPLE0_23_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE0_23_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + + elif NODE_TYPE == self.BOUNDARY_12: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + elif NODE_TYPE == self.BOUNDARY_13: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + elif NODE_TYPE == self.BOUNDARY_23: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + + elif NODE_TYPE == self.TRIPLE_CURVE_1_DOWN: + pass + elif NODE_TYPE == self.TRIPLE_CURVE_1_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE_CURVE_2_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + elif NODE_TYPE == self.TRIPLE_CURVE_2_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE_CURVE0_1_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE_CURVE0_1_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE_CURVE0_2_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + elif NODE_TYPE == self.TRIPLE_CURVE0_2_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elif NODE_TYPE == self.SURFACE_REGULAR: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + else: + raise ValueError("Remapping for derivatives of this 'node type' is not implemented") + class ShieldMesh2D: ''' diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index eaa52839..ce0582e1 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -98,11 +98,11 @@ def createSphereMesh3d(self, fieldModule, coordinates): self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode) - self.calculateBoundaryElipses2() + self.calculateBoundaryElipses() self.generateNodes(nodes, fieldModule, coordinates) self.generateElements(mesh, fieldModule, coordinates) - def calculateBoundaryElipses2(self): + def calculateBoundaryElipses(self): """ :return: @@ -138,12 +138,10 @@ def calculateBoundaryElipses2(self): elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) - self.copyEllipsesNodesToShieldNodes2(ellipse, alongAxis, i) - - - self.createAdditionalPointsForIncreasingElementsCount2() + self.copyEllipsesNodesToShieldNodes(ellipse, i) + self.createAdditionalPointsForIncreasingElementsCount() - def copyEllipsesNodesToShieldNodes2(self, ellipse, alongAxis, ellipsenumber): + def copyEllipsesNodesToShieldNodes(self, ellipse, ellipsenumber): """ Copy coordinates and derivatives of ellipse to shield. :param n3: the index number of ellipse along the central path. @@ -225,121 +223,7 @@ def copyEllipsesNodesToShieldNodes2(self, ellipse, alongAxis, ellipsenumber): else: btd1[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - def calculateBoundaryElipses(self): - """ - - :return: - """ - - centre = self._centre - elementsCountAcrossShell = self._elementsCountAcrossShell - elementsCountAcrossTransition = self._elementsCountAcrossTransition - shellProportion = self._shellProportion - - ellipseAxes = [[self._axes[0], self._axes[1], self._axes[2]], - [[-c for c in self._axes[2]], self._axes[1], self._axes[0]], - [self._axes[0], [-c for c in self._axes[2]], self._axes[1]]] - - coreRadius = [(self._coreRadius[0], self._coreRadius[1]), - (self._coreRadius[2], self._coreRadius[1]), - (self._coreRadius[0], self._coreRadius[2])] - - elementsCount = [(2 * self._elementsCount[0], 2 * self._elementsCount[1]), - (2 * self._elementsCount[2], 2 * self._elementsCount[1]), - (2 * self._elementsCount[0], 2 * self._elementsCount[2])] - - for i in range(3): - majorAxis = ellipseAxes[i][0] - minorAxis = ellipseAxes[i][1] - alongAxis = ellipseAxes[i][2] - elementsCountAcrossMajor = elementsCount[i][0] - elementsCountAcrossMinor = elementsCount[i][1] - coreMajorRadius = coreRadius[i][0] - coreMinorRadius = coreRadius[i][1] - ellipse = Ellipse2D(centre, majorAxis, minorAxis, - elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, - elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, - ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) - - self.copyEllipsesNodesToShieldNodes(ellipse, alongAxis, i) - - - self.createAdditionalPointsForIncreasingElementsCount() - - - def copyEllipsesNodesToShieldNodes(self, ellipse, alongAxis, ellipsenumber): - """ - Copy coordinates and derivatives of ellipse to shield. - :param n3: the index number of ellipse along the central path. - """ - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - shield = ellipse.getShield() - - # Modify the shield12 to get only the quarter that you want. make others None so you can generate the nodes. - if ellipsenumber == 0: - for n2 in range(self._elementsCount[0] + 1): # TODO modify this to number of elements. - for n1 in range(self._elementsCount[1] + 1): - # only first quadrant is needed TODO we need to modify this to number of elements half of the elments across each direction. - # btd2[0][n2][n1] = [c for c in alongAxis] - if n2 == 0 and n1 == self._elementsCount[1] - 1: - n1s = n1 + 1 - else: - n1s = n1 - n1e = n1 + self._elementsCount[1] - if shield.px[0][n2][n1e]: - btx[0][n2][n1s] = [c for c in shield.px[0][n2][n1e]] - btd1[0][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - btd2[0][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] - btd3[0][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] - elif ellipsenumber == 1: - n2s = self._elementsCount[0] - for n3 in range(self._elementsCount[2] + 1): - for n1 in range(self._elementsCount[1] + 1): - btd2[n3][n2s][n1] = [c for c in alongAxis] - if n3 == self._elementsCount[2] and n1 == self._elementsCount[1] - 1: - n1s = n1 + 1 - else: - n1s = n1 - n2e = n3 + self._elementsCount[2] - n1e = n1 + self._elementsCount[1] - if n3 == 0: - btd2[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] - else: - if shield.px[0][n2e][n1 + self._elementsCount[1]]: - btx[n3][n2s][n1s] = [c for c in shield.px[0][n2e][n1e]] - btd1[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] - btd3[n3][n2s][n1s] = [c for c in shield.pd3[0][n2e][n1e]] - elif ellipsenumber == 2: - n1s = 0 - for n3 in range(self._elementsCount[2] + 1): - for n2 in range(self._elementsCount[0] + 1): - - if n2 == 0 and n3 == self._elementsCount[2] - 1: - n3s = self._elementsCount[2] - else: - n3s = n3 - n1e = self._elementsCount[2] - n3 - if n3 == 0: - if n2 == 0: - btd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - elif 0 < n2 < self._elementsCount[0]: - btd2[n3][n2][n1s] = [-c for c in shield.pd3[0][n2][n1e]] - else: - if n2 < self._elementsCount[0]: - btd2[n3][n2][n1s] = [c for c in alongAxis] - if shield.px[0][n2][n1e]: - btx[n3s][n2][n1s] = [c for c in shield.px[0][n2][n1e]] - btd1[n3s][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - btd3[n3s][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] - else: - btd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - - def createAdditionalPointsForIncreasingElementsCount2(self): + def createAdditionalPointsForIncreasingElementsCount(self): """ :return: @@ -347,39 +231,12 @@ def createAdditionalPointsForIncreasingElementsCount2(self): self.calculate_surface_quadruple_point() self.sample_triple_curves() - # self.calculate_regular_nodes2() - # self._shield3D.getQuadruplePoint2() - self.fixD2DerivativesOnTheEllipses2() + self.fixD2DerivativesOnTheEllipses() n3z = self._elementsCount[2] self._shield3D.smoothDerivativesToSurfaceQuadruple(n3z) self.smoothDerivativesToSurface() - def remap_ellipse_derivatives(self): - """ - - :return: - """ - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - - - - # temp = btd2[1][1][0] - # btd2[1][1][0] = [-c for c in btd3[1][1][0]] - # btd3[1][1][0] = [c for c in temp] - # temp = btd2[n3b][n2b][n1b] - # btd2[n3b][n2b][n1b] = [c for c in btd1[n3b][n2b][n1b]] - # btd1[n3b][n2b][n1b] = temp - # temp = btd2[n3b][n2b][n1a] - # btd2[n3b][n2b][n1a] = [c for c in btd1[n3b][n2b][n1a]] - # btd1[n3b][n2b][n1a] = temp - - - def calculate_surface_quadruple_point(self): """ Calculate coordinates and derivatives of points where 3 hex elements merge. @@ -536,173 +393,7 @@ def sample_triple_curves(self): arcLength = calculate_arc_length(btx[0][0][n1z], btx[n3z][0][n1z]) btd2[0][0][n1z] = vector.setMagnitude(btd2[0][0][n1z], arcLength) - - def calculate_regular_nodes2(self): - """ - Node 1,2,1. - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - if self._elementsCount[0] == 3: - # self.CreateRegularNodeOnBoundary() - n3 = 0 - n1 = 0 - for n2 in range(n2a + 1, n2b): - # First create the node for regular node. We are using the neighbour nodes x,y,z to do it but TODO eventualy we need to use the sampling between boundary nodes. - x = [btx[n3][n2][n1 + 1][0], btx[n3 + 1][n2 + 1][n1 + 1][1], btx[n3 + 1][n2][n1][2]] - btx[n3 + 1][n2][n1 + 1] = x - btd1[n3 + 1][n2][n1 + 1] = [(btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] - btd2[n3 + 1][n2][n1 + 1] = [-(btx[n3][n2][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] - btd3[n3 + 1][n2][n1 + 1] = [-(btx[n3 + 1][n2][n1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] - # using new point obtain the d2 derivatives of the neighbour nodes - btd2[n3 + 1][n2][n1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3 + 1][n2][n1][c] for c in range(3)] - btd2[n3][n2][n1 + 1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3][n2][n1 + 1][c] for c in range(3)] - btd2[n3 + 1][n2 + 1][n1 + 1] = [btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3][n2 + 1][n1 + 1][c] for c in range(3)] - - self.remapRegularCurvesOnEllipses() - - def createAdditionalPointsForIncreasingElementsCount(self): - """ - - :return: - """ - - self.calculate_regular_nodes() - self._shield3D.getQuadruplePoint() - self.fixD2DerivativesOnTheEllipses() - self.remapDerivativesOnTheEllipses() - - # reverse d2 for 0,0,0 - self._shield3D.pd2[0][0][0] = [-c for c in self._shield3D.pd2[0][0][0]] - - self.calculate_surface_nodes() - self.smooth_triple_curves() - - def calculate_regular_nodes(self): - """ - Node 1,2,1. - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - if self._elementsCount[0] == 3: - self.CreateRegularNodeOnBoundary() - n3 = 0 - n1 = 0 - for n2 in range(n2a + 1, n2b): - # First create the node for regular node. We are using the neighbour nodes x,y,z to do it but TODO eventualy we need to use the sampling between boundary nodes. - x = [btx[n3][n2][n1 + 1][0], btx[n3 + 1][n2 + 1][n1 + 1][1], btx[n3 + 1][n2][n1][2]] - btx[n3 + 1][n2][n1 + 1] = x - btd1[n3 + 1][n2][n1 + 1] = [(btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] - btd2[n3 + 1][n2][n1 + 1] = [-(btx[n3][n2][n1 + 1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] - btd3[n3 + 1][n2][n1 + 1] = [-(btx[n3 + 1][n2][n1][c] - btx[n3 + 1][n2][n1 + 1][c]) for c in range(3)] - # using new point obtain the d2 derivatives of the neighbour nodes - btd2[n3 + 1][n2][n1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3 + 1][n2][n1][c] for c in range(3)] - btd2[n3][n2][n1 + 1] = [btx[n3 + 1][n2][n1 + 1][c] - btx[n3][n2][n1 + 1][c] for c in range(3)] - btd2[n3 + 1][n2 + 1][n1 + 1] = [btx[n3 + 1][n2 + 1][n1 + 1][c] - btx[n3][n2 + 1][n1 + 1][c] for c in range(3)] - - self.remapRegularCurvesOnEllipses() - - def remapRegularCurvesOnEllipses(self): - """ - - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - # We need to remap the derivatives as we want d1 to be in -axis1 direction, d2, axis3 and d3, axis2. We need to think about the directions as well. e.g. - # d1, d2, d3 could be simply axis1,axis2 and axis3. However this one was chosen so it could be consistent with the cylinder mesh that makes joining them - # a little easier. TODO d1,d2,d3 directions in regular elements. - # for nodes on the ellipse2, d2 is -d3 and d3 is d2. TODO we can add another method to ellipse so it gives us what we expect for derivatives. - n3 = 0 - n1 = 0 - for n2 in range(n2a + 1, n2b): - temp = btd2[n3 + 1][n2][n1] - btd2[n3 + 1][n2][n1] = [-c for c in btd3[n3 + 1][n2][n1]] - btd3[n3 + 1][n2][n1] = temp - # for ellipse 1, swap d2 and d1 - temp = btd2[n3 + 1][n2 + 1][n1 + 1] - btd2[n3 + 1][n2 + 1][n1 + 1] = [c for c in btd1[n3 + 1][n2 + 1][n1 + 1]] - btd1[n3 + 1][n2 + 1][n1 + 1] = temp - - def CreateRegularNodeOnBoundary(self): - """ - Node 2,n2,2, triple curves or quadruple 0 or Q0. - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - # create the other two nodes to create the elements. - radius = self._radius[0] # TODO need to be changed for spheroid - - elementsAroundEllipse12 = self._elementsCount[0] + self._elementsCount[1] - 2 - radiansAroundEllipse12 = math.pi / 2 - radiansPerElementAroundEllipse12 = radiansAroundEllipse12 / elementsAroundEllipse12 - elementsAroundEllipse13 = self._elementsCount[0] + self._elementsCount[2] - 2 - radiansAroundEllipse13 = math.pi / 2 - radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 - - n3 = 1 - n1 = 0 - for n2 in range(n2a + 1, n2b): - theta_1 = math.pi / 4 # TODO actually it should change with the number of elements. - theta_3 = 2*radiansPerElementAroundEllipse12 - phi_3 = calculate_azimuth(math.pi/2 - theta_3, theta_1) - # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), - radius * math.cos(phi_3)] - - a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - btx[n3 + 1][n2][n1 + 2] = x - btd1[n3 + 1][n2][n1 + 2] = a1 - btd2[n3 + 1][n2][n1 + 2] = a2 - btd3[n3 + 1][n2][n1 + 2] = a3 - - arcLength = radius * phi_3 - btd2[n3 + 1][n2][n1 + 2] = vector.setMagnitude(btd2[n3 + 1][n2][n1 + 2], arcLength) - - def fixD2DerivativesOnTheEllipses2(self): + def fixD2DerivativesOnTheEllipses(self): """ :return: @@ -719,227 +410,11 @@ def fixD2DerivativesOnTheEllipses2(self): btd2 = self._shield3D.pd2 btd3 = self._shield3D.pd3 - n1 = 1 + self._elementsCount[1] - 2 + n1 = self._elementsCount[1] - 1 for n2 in range(self._elementsCount[0] + 1): if n2a <= n2 < self._elementsCount[0]: btd3[n3b][n2][n1a] = [btx[n3b][n2][n1b][c] - btx[n3b][n2][n1a][c] for c in range(3)] btd2[0][n2][n1] = [btx[1][n2][n1][c] - btx[0][n2][n1][c] for c in range(3)] - # btd1[n3b][n2b][n1b] = [-(btx[n3b][n2b-1][n1b][c] - btx[n3b][n2b][n1b][c]) for c in range(3)] - - def fixD2DerivativesOnTheEllipses(self): - """ - - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - btd2[n3b][n2a][n1a] = [btx[n3b][n2a][n1b][c] - btx[n3b][n2a][n1a][c] for c in range(3)] - btd2[0][1][1] = [btx[1][1][1][c] - btx[0][1][1][c] for c in range(3)] - btd2[n3b][n2b][n1b] = [-(btx[n3b][n2a][n1b][c] - btx[n3b][n2b][n1b][c]) for c in range(3)] - - def remapDerivativesOnTheEllipses(self): - """ - - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - temp = btd2[1][1][0] - btd2[1][1][0] = [-c for c in btd3[1][1][0]] - btd3[1][1][0] = [c for c in temp] - temp = btd2[n3b][n2b][n1b] - btd2[n3b][n2b][n1b] = [c for c in btd1[n3b][n2b][n1b]] - btd1[n3b][n2b][n1b] = temp - temp = btd2[n3b][n2b][n1a] - btd2[n3b][n2b][n1a] = [c for c in btd1[n3b][n2b][n1a]] - btd1[n3b][n2b][n1a] = temp - - def calculate_surface_nodes(self): - """ - - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - radius = self._radius[0] # TODO need to be changed for spheroid - - elementsAroundEllipse12 = self._elementsCount[0] + self._elementsCount[1] - 2 - radiansAroundEllipse12 = math.pi / 2 - radiansPerElementAroundEllipse12 = radiansAroundEllipse12 / elementsAroundEllipse12 - elementsAroundEllipse13 = self._elementsCount[0] + self._elementsCount[2] - 2 - radiansAroundEllipse13 = math.pi / 2 - radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 - - theta_2 = radiansPerElementAroundEllipse13 # TODO actually it should change with the number of elements. - theta_3 = radiansPerElementAroundEllipse12 - phi_3 = calculate_azimuth(theta_3, theta_2) - # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - # x = [radius * math.sin(phi_3) * math.cos(theta_3), radius * math.sin(phi_3) * math.sin(theta_3), - # radius * math.cos(phi_3)] - x = spherical_to_cartesian(radius, theta_3, phi_3) - - a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - btx[n3b + 1][0][n1b + 1] = x - # btd1[n3b + 1][0][n1b + 1] = a1 - # btd2[n3b + 1][0][n1b + 1] = a2 - btd3[n3b + 1][0][n1b + 1] = a3 - nx, nd1 = sample_curves_sphere(x, btx[n3b + 1][n2b][n1b + 1], self._elementsCount[0]-1) - for nc in range(self._elementsCount[0]): - if nc == 0: - btd1[n3b + 1][0][n1b + 1] = nd1[0] - elif nc == n2b-1: - btd2[n3b + 1][n2b][n1b + 1] = vector.scaleVector(nd1[-1], -1) - else: - btx[n3b + 1][nc+1][n1b + 1] = nx[nc] - btd1[n3b + 1][nc+1][n1b + 1] = nd1[nc] - - # for n2 in range(1, n2b - 1): - # for n1 in range(n1b+1): - # xi = 0.5 - # btd2[n3b + 1][n2][n1b + 1] = interpolateCubicHermite(btd2[0][n2][n1b + 1], [0, 0, 0], vector.scaleVector(btd2[n3b + 1][n2][0], -1), [0, 0, 0], xi) - if n2b > 2: - tx = [] - td2 = [] - n2 = 2 - for n1 in range(self._elementsCount[1] - 1): - tx.append(btx[n3b + 1][n2][n1]) - td2.append(btd2[n3b + 1][n2][n1]) - tx.append(btx[n3b + 1][n2][n1b + 1]) - td2.append(btd2[n3b + 1][n2][n1b + 1]) - for n3 in range(self._elementsCount[2] - 2, -1, -1): - tx.append(btx[n3][n2][n1b + 1]) - td2.append(vector.scaleVector(btd2[n3][n2][n1b + 1], -1)) - - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDirection=True) - - btd2[n3b + 1][n2][0] = td2[0] - for n1 in range(1, self._elementsCount[1] - 1): - btd2[n3b + 1][n2][n1] = td2[n1] - btd2[n3b + 1][n2][n1b + 1] = vector.scaleVector(td2[1], -1) - for n3 in range(self._elementsCount[2] - 2, -1, -1): - btd2[n3][n2][n1b + 1] = vector.scaleVector(td2[-1-n3], -1) - - - # btd - # for n2 in range(self._elementsCountAcrossMajor + 1): - # for n1 in range(self._elementsCountAcrossMinor + 1): - # td2 = [] - # tx = [] - # if btx[0][n2][n1]: - # for n3 in range(self._elementsCountAlong + 1): - # tx.append(btx[n3][n2][n1]) - # td2.append(btd2[n3][n2][n1]) - # td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True) - # for n3 in range(self._elementsCountAlong + 1): - # btd2[n3][n2][n1] = td2[n3] - - - - arcLength = calculate_arc_length(x, btx[n3a][0][n1b + 1]) - # btd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd2[n3b + 1][0][n1b + 1], arcLength) - - - - # a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[0]) - # btd1 = [ - # btx[n3b + 1][n2b][n1b + 1][c] - btx[n3b + 1][0][n1b + 1][c] for c in range(3)] - # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) - self._shield3D.smoothDerivativesToSurfaceQuadruple(n3b+1) - - - a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[1]) - # btd1 = [ - # btx[n3b + 1][n2b][n1b + 1][c] - btx[n3b + 1][0][n1b + 1][c] for c in range(3)] - btd2[n3b + 1][0][n1b + 1] = vector.setMagnitude([-c for c in a2], arcLength) - # btd2[n3b + 1][0][n1b + 1] = [ - # -(btx[0][0][n1b + 1][c] - btx[n3b + 1][0][n3b + 1][c]) for c in range(3)] - # btd3[n3b + 1][0][n1b + 1] = [ - # -(btx[1][1][1][c] - btx[n3b + 1][0][n1b + 1][c]) for c in range(3)] - - - - n1a = 1 - n2a = 1 - n3a = 1 - btd1[n3a][n2a][n1a] = [-(btx[n3a+1][n2a-1][n1a+1][0] - btx[n3a][n2a][n1a][0]), 0.0, 0.0] - btd2[n3a][n2a][n1a] = [0.0, 0.0, (btx[n3a+1][n2a-1][n1a+1][2] - btx[n3a][n2a][n1a][2])] - btd3[n3a][n2a][n1a] = [0.0, (btx[n3a+1][n2a-1][n1a+1][1] - btx[n3a][n2a][n1a][1]), 0.0] - - def smooth_triple_curves(self): - """ - - :return: - """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - radius = 1.0 - theta = math.atan(math.sqrt(1.0 / 2.0)) - arclength = radius * theta - btd2[0][0][n1b + 1] = vector.setMagnitude(btd2[0][0][n1b + 1], arclength) - btd2[n3b + 1][0][0] = vector.setMagnitude(btd2[n3b + 1][0][0], arclength) - - self.smoothDerivativesToSurface() - # btd2[n3b + 1][n2b][n1b + 1] = vector.setMagnitude(btd2[n3b + 1][n2b][n1b + 1], - # arclength) - # atz = vector.vectorRejection(btd2[n3b + 1][0][n1b + 1], btd3[n3b + 1][0][n1b + 1]) - # btd2[n3b + 1][0][n1b + 1] = vector.setMagnitude(atz, arclength) - # atx = vector.vectorRejection(btd1[n3b + 1][0][n1b + 1], btd3[n3b + 1][0][n1b + 1]) - # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(atx, arclength) - - - # btd1[n3b + 1][0][n1b + 1] = vector.crossproduct3(btd2[n3b + 1][0][n1b + 1], - # btd3[n3b + 1][0][n1b + 1]) - # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd1[n3b + 1][0][n1b + 1], - # arclength) - - # dmag = calculate_arc_length(btx[n3b + 1][0][n1b + 1], btx[n3b + 1][2][n1b + 1], radius) - # d2mag = vector.magnitude(btd2[n3b + 1][0][n1b + 1]) - # d1mag = math.sqrt(dmag*dmag - d2mag*d2mag) - # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd1[n3b + 1][0][n1b + 1], d1mag) - # d2mag = vector.magnitude(btd2[n3b + 1][0][n1b + 1]) - # thetad1ncurve = math.pi / 6 - # btd1[n3b + 1][0][n1b + 1] = vector.setMagnitude(btd1[n3b + 1][0][n1b + 1], - # d2mag / math.tan(thetad1ncurve)) def smoothDerivativesToSurface(self): ''' @@ -1013,7 +488,6 @@ def smoothDerivativesToSurface(self): # n1 = n3 # btd3[n3][n2][n1] = td3[nc3] - def generateNodes(self, nodes, fieldModule, coordinates): """ Create cylinder nodes from coordinates. From 95637e9e858cbbac82c5735b9dad74924484eaf2 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 17 Sep 2021 14:25:52 +1200 Subject: [PATCH 13/37] Add octant, hemisphere and full options for the sphere. --- .../meshtypes/meshtype_3d_solidsphere2.py | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 82f35dad..dfbdd115 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -62,7 +62,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, + 'Octant': True, + 'Hemisphere': False, + 'Full': False, 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements across': 1, @@ -80,7 +82,9 @@ def getOrderedOptionNames(): 'Number of elements across transition', # 'Number of elements along', 'Shell element thickness proportion', - # 'Lower half', + 'Octant', + 'Hemisphere', + 'Full', 'Refine', 'Refine number of elements across' ] @@ -157,6 +161,9 @@ def generateBaseMesh(region, options): # centralPath = options['Central path'] # full = not options['Lower half'] + octant = options['Octant'] + hemisphere = options['Hemisphere'] + full = options['Full'] elementsCountAcrossAxis1 = options['Number of elements across axis 1'] elementsCountAcrossAxis2 = options['Number of elements across axis 2'] elementsCountAcrossAxis3 = options['Number of elements across axis 3'] @@ -173,6 +180,7 @@ def generateBaseMesh(region, options): coordinates = findOrCreateFieldCoordinates(fm) centre = [0.0, 0.0, 0.0] + axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] axis3 = [0.0, 0.0, 1.0] @@ -183,6 +191,72 @@ def generateBaseMesh(region, options): elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + axis1 = [0.0, -1.0, 0.0] + if (hemisphere or full) and not octant: + axis2 = [1.0, 0.0, 0.0] + axis3 = [0.0, 0.0, 1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + + axis1 = [-1.0, 0.0, 0.0] + axis2 = [0.0, -1.0, 0.0] + axis3 = [0.0, 0.0, 1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + + axis1 = [0.0, 1.0, 0.0] + axis2 = [-1.0, 0.0, 0.0] + axis3 = [0.0, 0.0, 1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + + if full and not octant and not hemisphere: + axis1 = [0.0, 1.0, 0.0] + axis2 = [1.0, 0.0, 0.0] + axis3 = [0.0, 0.0, -1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + + sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + + axis2 = [0.0, -1.0, 0.0] + axis1 = [1.0, 0.0, 0.0] + axis3 = [0.0, 0.0, -1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + + axis2 = [-1.0, 0.0, 0.0] + axis1 = [0.0, -1.0, 0.0] + axis3 = [0.0, 0.0, -1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + + axis2 = [0.0, 1.0, 0.0] + axis1 = [-1.0, 0.0, 0.0] + axis3 = [0.0, 0.0, -1.0] + axes = [axis1, axis2, axis3] + elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + annotationGroup = [] return annotationGroup From 7f5fbd49cae6254f414250736178ffca2a3804bf Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 17 Sep 2021 14:30:48 +1200 Subject: [PATCH 14/37] Make number of elements across axis 3 configurable --- src/scaffoldmaker/utils/shieldmesh.py | 501 ++++++++++++++++++-------- src/scaffoldmaker/utils/spheremesh.py | 355 +++++++++++++----- 2 files changed, 612 insertions(+), 244 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index ee972c67..58781d32 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -76,49 +76,30 @@ def getQuadruplePoint2(self): """ n1z = self.elementsCountAcross[1] n1y = n1z - 1 - n1a = self.elementsCountAcross[1] - 1 - n2a = 1 - n3a = 1 n3z = self.elementsCountAcross[2] n3y = n3z - 1 n2z = self.elementsCountAcross[0] - # n2b = self.elementsCountAcross[0] - # for n2 in range(self.elementsCountAcross[0]): - # if n2 > 0: - # x = [self.px[0][n2][n1a][0], self.px[0][n2][n1a][1],self.px[n3a][n2][0][2]] - # self.px[n3a][n2][n1a] = x - # n2r = n2 - 1 if n2 == 1 else n2 - # if n2 == 1: - # self.pd1[n3a][n2][n1a] = [-(self.px[n3a + 1][n2r][n1a + 1][0] - self.px[n3a][n2][n1a][0]), 0.0, 0.0] - # else: - # self.pd1[n3a][n2][n1a] = self.pd1[0][n2][n1a] - # self.pd2[n3a][n2][n1a] = [0.0, 0.0, (self.px[n3a + 1][n2r][n1a + 1][2] - self.px[n3a][n2][n1a][2])] - # self.pd3[n3a][n2][n1a] = [0.0, (self.px[n3a + 1][n2r][n1a + 1][1] - self.px[n3a][n2][n1a][1]), 0.0] - - # n3 = 1 - # n1 = 1 + self.elementsCountAcross[1] - 2 - # tx = [] - # td1 = [] - # for n2 in range(self.elementsCountAcross[0] + 1): - # if n2 > 0: - # tx.append(self.px[n3][n2][n1]) - # td1.append(self.pd1[n3][n2][n1]) - # - # td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) - # - # for n2 in range(self.elementsCountAcross[0] + 1): - # if n2 > 1: - # n2t = n2 - 1 - # self.pd1[n3][n2][n1] = td1[n2t] - - x = [min(self.px[0][1][n1y][0], self.px[n3y][1][0][0]), - min(self.px[0][1][n1y][1], self.px[n3y][n2z][n1y][1]), - min(self.px[n3y][1][0][2], self.px[n3y][n2z][n1y][2])] - self.px[n3a][1][n1a] = x + + if self.elementsCountAcross[2] == min(self.elementsCountAcross): + n3r0, n2r0, n1r0 = 0, 1, n1y + n3r, n2r, n1r = 0, 0, n1z + elif self.elementsCountAcross[1] == min(self.elementsCountAcross): + n3r0, n2r0, n1r0 = n3y, 1, 0 + n3r, n2r, n1r = n3z, 0, 0 + else: + n3r0, n2r0, n1r0 = n3y, n2z, n1y + n3r, n2r, n1r = n3z, n2z, n1z + + ts = vector.magnitude(vector.addVectors(self.px[n3r0][n2r0][n1r0], self.px[n3r][n2r][n1r], 1, -1)) + ra = vector.magnitude(self.px[n3z][0][n1z]) + x = vector.scaleVector(self.px[n3z][0][n1z], (1 - ts/ra)) + self.px[n3y][1][n1y] = x n2r = 0 - self.pd1[n3a][1][n1a] = [-(self.px[n3a + 1][n2r][n1a + 1][0] - self.px[n3a][1][n1a][0]), 0.0, 0.0] - self.pd2[n3a][1][n1a] = [0.0, 0.0, (self.px[n3a + 1][n2r][n1a + 1][2] - self.px[n3a][1][n1a][2])] - self.pd3[n3a][1][n1a] = [0.0, (self.px[n3a + 1][n2r][n1a + 1][1] - self.px[n3a][1][n1a][1]), 0.0] + self.pd1[n3y][1][n1y] = [-(self.px[n3y + 1][n2r][n1y + 1][0] - self.px[n3y][1][n1y][0]), 0.0, 0.0] + self.pd2[n3y][1][n1y] = [0.0, 0.0, (self.px[n3y + 1][n2r][n1y + 1][2] - self.px[n3y][1][n1y][2])] + self.pd3[n3y][1][n1y] = [0.0, (self.px[n3y + 1][n2r][n1y + 1][1] - self.px[n3y][1][n1y][1]), 0.0] + + # curve 1 tx, td1 = sampleCubicHermiteCurves([self.px[n3z-1][1][n1y], self.px[n3z-1][n2z][n1y]], @@ -130,66 +111,105 @@ def getQuadruplePoint2(self): self.pd2[n3z-1][n2][n1y] = [0.0, 0.0, (self.px[n3z][n2][n1z][2] - self.px[n3z-1][n2][n1y][2])] self.pd3[n3z-1][n2][n1y] = [0.0, (self.px[n3z][n2][n1z][1] - self.px[n3z-1][n2][n1y][1]), 0.0] - # smooth d1 in curve1 - tx = [] - td1 = [] - for n2 in range(1, self.elementsCountAcross[0]+1): - tx.append(self.px[n3z-1][n2][n1y]) - td1.append(self.pd1[n3z-1][n2][n1y]) - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) - for n2 in range(2, self.elementsCountAcross[0]+1): - self.pd1[n3z-1][n2][n1y] = td1[n2-1] + # curve 2 and parallel curves TODO change all [1] to n3y. + for n2 in range(1, self.elementsCountAcross[0]): + tx, td3 = sampleCubicHermiteCurves([self.px[n3y][n2][0], self.px[n3y][n2][n1y]], + [self.pd3[0][n2][0], self.pd3[0][n2][n1y]], self.elementsCountAcross[1] - 1)[:2] + for n1 in range(1, self.elementsCountAcross[1] - 1): + self.px[n3y][n2][n1] = tx[n1] + self.pd3[n3y][n2][n1] = td3[n1] - # curve 2 and parallel curves for n2 in range(1, self.elementsCountAcross[0]): - tx, td3 = sampleCubicHermiteCurves([self.px[1][n2][0], self.px[1][n2][n1a]], - [self.pd3[0][n2][0], self.pd3[0][n2][n1a]], self.elementsCountAcross[1] - 1)[:2] - for n1 in range(1, self.elementsCountAcross[1] - 1): - self.px[1][n2][n1] = tx[n1] - self.pd3[1][n2][n1] = td3[n1] if n2 == 1: - self.pd1[1][n2][n1] = [self.px[1][1][n1][0] - self.px[n3z][0][n1][0], 0.0, 0.0] - self.pd2[1][n2][n1] = [0.0, 0.0, -self.px[1][1][n1][2] + self.px[n3z][0][n1][2]] + self.pd1[n3y][n2][n1] = [self.px[n3y][1][n1][0] - self.px[n3z][0][n1][0], 0.0, 0.0] + self.pd2[n3y][n2][n1] = [0.0, 0.0, -self.px[n3y][1][n1][2] + self.px[n3z][0][n1][2]] else: - self.pd1[1][n2][n1] = vector.addVectors(self.px[1][n2][n1], self.px[1][n2+1][n1], -1, 1) - self.pd2[1][n2][n1] = vector.addVectors(self.px[1][n2][n1], self.px[0][n2][n1], 1, -1) + self.pd1[n3y][n2][n1] = vector.addVectors(self.px[n3y][n2][n1], self.px[n3y][n2+1][n1], -1, 1) + self.pd2[n3y][n2][n1] = vector.addVectors(self.px[n3y][n2][n1], self.px[0][n2][n1], 1, -1) + - tx = [] - td3 = [] - for n1 in range(self.elementsCountAcross[1]): - tx.append(self.px[1][n2][n1]) - td3.append(self.pd3[1][n2][n1]) - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True) - for n1 in range(self.elementsCountAcross[1]-1): - self.pd3[1][n2][n1] = td3[n1] + # sample along curve0_3 + for n2 in range(1, self.elementsCountAcross[0]): + for n1 in range(1, self.elementsCountAcross[1]): + tx, td2 = sampleCubicHermiteCurves([self.px[0][n2][n1], self.px[n3y][n2][n1]], + [self.pd2[0][n2][0], self.pd2[n3y][n2][0]], self.elementsCountAcross[2]-1)[:2] + + for n3 in range(1, self.elementsCountAcross[2] - 1): + self.px[n3][n2][n1] = tx[n3] + self.pd2[n3][n2][n1] = td2[n3] + + for n3 in range(1, self.elementsCountAcross[2] - 1): + for n2 in range(1, self.elementsCountAcross[0]): + for n1 in range(1, self.elementsCountAcross[1]): + if n2 == 1 and n1 == n1y: + self.pd1[n3][n2][n1] = [self.px[n3][n2][n1][0] - self.px[n3][n2-1][n1+1][0], 0.0, 0.0] + self.pd3[n3][n2][n1] = [0.0, self.px[n3][n2-1][n1+1][1] - self.px[n3][n2][n1][1], 0.0] + else: + self.pd1[n3][n2][n1] = vector.addVectors(self.px[n3][n2+1][n1], self.px[n3][n2][n1], 1, -1) + self.pd3[n3][n2][n1] = vector.addVectors(self.px[n3][n2][n1+1], self.px[n3][n2][n1], 1, -1) + # smooth d1 in regular 1 - for n1 in range(1, self.elementsCountAcross[1] - 1): - tx = [] - td1 = [] - for n2 in range(1, self.elementsCountAcross[0]+1): - tx.append(self.px[1][n2][n1]) - td1.append(self.pd1[1][n2][n1]) - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) - for n2 in range(1, self.elementsCountAcross[0]+1): - self.pd1[1][n2][n1] = td1[n2-1] + if self.elementsCountAcross[0] >= 3: + for n3 in range(1, self.elementsCountAcross[2]): + for n1 in range(1, self.elementsCountAcross[1]): + tx = [] + td1 = [] + for n2 in range(1, self.elementsCountAcross[0]+1): + tx.append(self.px[n3][n2][n1]) + td1.append(self.pd1[n3][n2][n1]) + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) + for n2 in range(1, self.elementsCountAcross[0]+1): + self.pd1[n3][n2][n1] = td1[n2-1] + else: + for n3 in range(1, self.elementsCountAcross[2]): + for n1 in range(1, self.elementsCountAcross[1]): + self.pd1[n3][1][n1] = vector.addVectors(self.px[n3][2][n1], self.px[n3][1][n1], 1, -1) + self.pd1[n3][2][n1] = vector.setMagnitude(self.pd1[n3][2][n1], vector.magnitude(self.pd1[n3][1][n1])) + + # smooth d3 in regular + if self.elementsCountAcross[1] >= 3: + for n3 in range(1, self.elementsCountAcross[2]): + for n2 in range(1, self.elementsCountAcross[0]): + tx = [] + td3 = [] + for n1 in range(self.elementsCountAcross[1]): + tx.append(self.px[n3][n2][n1]) + td3.append(self.pd3[n3][n2][n1]) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True) + + for n1 in range(self.elementsCountAcross[1]): + self.pd3[n3][n2][n1] = td3[n1] + else: + for n3 in range(1, self.elementsCountAcross[2]): + for n2 in range(1, self.elementsCountAcross[0]): + self.pd3[n3][n2][1] = vector.addVectors(self.px[n3][n2][1], self.px[n3][n2][0], 1, -1) + self.pd3[n3][n2][0] = vector.setMagnitude(self.pd3[n3][n2][0], vector.magnitude(self.pd3[n3][n2][1])) + # regular curves d2 for n2 in range(1, self.elementsCountAcross[0]): for n1 in range(1, self.elementsCountAcross[1]): - tx = [] - td2 = [] - for n3 in range(2): - tx.append(self.px[n3][n2][n1]) - td2.append(self.pd2[n3][n2][n1]) - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDerivative=True) - for n3 in range(1): - self.pd2[n3][n2][n1] = td2[n3] + if self.elementsCountAcross[2] >= 3: + tx = [] + td2 = [] + for n3 in range(self.elementsCountAcross[2]): + tx.append(self.px[n3][n2][n1]) + td2.append(self.pd2[n3][n2][n1]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True) + for n3 in range(self.elementsCountAcross[2]): + self.pd2[n3][n2][n1] = td2[n3] + else: + self.pd2[1][n2][n1] = vector.addVectors(self.px[1][n2][n1], self.px[0][n2][n1], 1, -1) + self.pd2[0][n2][n1] = vector.setMagnitude(self.pd2[0][n2][n1], vector.magnitude(self.pd2[1][n2][n1])) + + # smooth d3 on the surface of regular ones. @@ -306,44 +326,53 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan # node types CORNER_1 = 1 - CORNER_2 = 29 - CORNER_3 = 28 + CORNER_2 = 2 + CORNER_3 = 3 - QUADRUPLE_DOWN_LEFT = 6 - QUADRUPLE_RIGHT = 12 - QUADRUPLE_UP = 18 + QUADRUPLE_DOWN_LEFT = 4 + QUADRUPLE_RIGHT = 5 + QUADRUPLE_UP = 6 QUADRUPLE0_DOWN_LEFT = 7 - QUADRUPLE0_RIGHT = 11 - QUADRUPLE0_UP = 30 - - TRIPLE_12_LEFT = 5 - TRIPLE_12_RIGHT = 9 - TRIPLE_13_DOWN = 2 - TRIPLE_13_UP = 21 - TRIPLE_23_UP = 20 - TRIPLE_23_DOWN = 14 - TRIPLE0_12_LEFT = 32 - TRIPLE0_12_RIGHT = 33 - TRIPLE0_13_DOWN = 4 - TRIPLE0_13_Up = 27 - TRIPLE0_23_DOWN = 13 - TRIPLE0_23_UP = 26 - - - BOUNDARY_12 = 3 - BOUNDARY_13 = 24 - BOUNDARY_23 = 19 - - TRIPLE_CURVE_1_DOWN = 15 - TRIPLE_CURVE_1_UP = 23 - TRIPLE_CURVE_2_DOWN = 8 - TRIPLE_CURVE_2_UP = 22 - TRIPLE_CURVE0_1_UP = 17 - TRIPLE_CURVE0_1_DOWN = 31 - TRIPLE_CURVE0_2_DOWN = 10 - TRIPLE_CURVE0_2_UP = 16 - - SURFACE_REGULAR = 25 + QUADRUPLE0_RIGHT = 8 + QUADRUPLE0_UP = 9 + + TRIPLE_12_LEFT = 10 + TRIPLE_12_RIGHT = 11 + TRIPLE_13_DOWN = 12 + TRIPLE_13_UP = 13 + TRIPLE_23_UP = 14 + TRIPLE_23_DOWN = 15 + TRIPLE0_12_LEFT = 16 + TRIPLE0_12_RIGHT = 17 + TRIPLE0_13_DOWN = 18 + TRIPLE0_13_Up = 19 + TRIPLE0_23_DOWN = 20 + TRIPLE0_23_UP = 21 + + BOUNDARY_12_LEFT = 22 + BOUNDARY_12_RIGHT = 23 + BOUNDARY_13_DOWN = 24 + BOUNDARY_13_UP = 25 + BOUNDARY_23_UP = 26 + BOUNDARY_23_DOWN = 27 + + TRIPLE_CURVE_1_DOWN = 28 + TRIPLE_CURVE_1_UP = 29 + TRIPLE_CURVE_2_DOWN = 30 + TRIPLE_CURVE_2_UP = 31 + TRIPLE_CURVE_3_LEFT = 32 + TRIPLE_CURVE_3_RIGHT = 33 + TRIPLE_CURVE0_1_UP = 34 + TRIPLE_CURVE0_1_DOWN = 35 + TRIPLE_CURVE0_2_DOWN = 36 + TRIPLE_CURVE0_2_UP = 37 + TRIPLE_CURVE0_3_LEFT = 38 + TRIPLE_CURVE0_3_RIGHT = 39 + + SURFACE_REGULAR_DOWN_LEFT = 40 + SURFACE_REGULAR_DOWN_RIGHT = 41 + SURFACE_REGULAR_UP = 42 + REGULAR = 43 def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): """ @@ -378,6 +407,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes e2z = self.elementsCountAcross[0] - 1 # e2y = e2z - 1 # e2x = e2z - 2 + e3z = self.elementsCountAcross[2] - 1 + e3y = e3z - 1 for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): @@ -387,12 +418,16 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3 + 1][e2][e1], self.nodeId[e3 + 1][e2 + 1][e1], self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3 + 1][e2][e1 + 1], self.nodeId[e3 + 1][e2 + 1][e1 + 1]] - element_regular = (e3 == 0 and e2 > e2a and e1 < e1z) - element_quadruple_down_left = (e3 == 0 and e2 == 0 and e1 == e1y) - element_quadruple_down_right = (e3 == 0 and e2 >= e2b and e1 == e1z) - element_quadruple_up_left = (e3 == 1 and e2 >= e2b and e1 == e1y) - element_quadruple_down = (e3 == 0 and e2 == 0 and e1 < e1y) - element_quadruple_up = (e3 == 1 and e2 >= e2b and e1 < e1y) + element_regular = (e3 <= e3y and e2 > e2a and e1 < e1z) + element_quadruple_down_left = (e3 == e3y and e2 == 0 and e1 == e1y) + element_quadruple_down_right = (e3 == e3y and e2 >= e2b and e1 == e1z) + element_quadruple_up_left = (e3 == e3z and e2 >= e2b and e1 == e1y) + element_quadruple_down = (e3 == e3y and e2 == 0 and e1 < e1y) + element_quadruple_up = (e3 == e3z and e2 >= e2b and e1 < e1y) + element_quadruple_left = (e3 < e3y and e2 == 0 and e1 == e1y) + element_quadruple_right = (e3 < e3y and e2 == e2b and e1 == e1z) + element_down_right = (e3 < e3y and e2 > e2b and e1 == e1z) + element_down_left = (e3 < e3y and e2 == 0 and e1 < e1y) if element_regular: pass @@ -412,11 +447,14 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if e1y == 0: self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_13_DOWN) - self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + if e3y == 0: + self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + else: + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_13_DOWN) self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_DOWN) else: self.remap_eft_node_value_label(eft1, [4], self.TRIPLE_CURVE0_2_DOWN) - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12) + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_DOWN) elif element_quadruple_down: @@ -427,16 +465,27 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_13_DOWN) - self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12) self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_2_DOWN) self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_CURVE0_2_DOWN) if e1 == 0: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_DOWN) + if e3y == 0: + self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_LEFT) + else: + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_13_DOWN) + self.remap_eft_node_value_label(eft1, [5], self.SURFACE_REGULAR_DOWN_LEFT) else: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_DOWN) + if e3y == 0: + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_LEFT) + else: + self.remap_eft_node_value_label(eft1, [1, 5], self.SURFACE_REGULAR_DOWN_LEFT) + + elif element_quadruple_down_right: if e2 == 1: @@ -460,10 +509,21 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if e2b == e2z: self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_DOWN) + if e3y == 0: + self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + else: + self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_23_DOWN) + else: + self.remap_eft_node_value_label(eft1, [4], self.TRIPLE_CURVE0_1_DOWN) + self.remap_eft_node_value_label(eft1, [6], self.SURFACE_REGULAR_DOWN_RIGHT) elif e2 == e2z: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE0_1_DOWN) self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_DOWN) + if e3y == 0: + self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + else: + self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_23_DOWN) elif element_quadruple_up_left: if e2 == 1: @@ -480,23 +540,24 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if e2 == e2b: self.remap_eft_node_value_label(eft1, [1], self.TRIPLE_CURVE0_2_UP) - self.remap_eft_node_value_label(eft1, [6], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [7], self.QUADRUPLE_UP) if e2b == e2z: - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_23_UP) self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_UP) if e1y == 0: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) else: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) else: + self.remap_eft_node_value_label(eft1, [6], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_CURVE_1_UP) if e1y == 0: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13_UP) else: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) - self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR) + self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR_UP) elif e2 == e2z: self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_UP) @@ -505,15 +566,19 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_1_UP) if e1y == 0: self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) - self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13) + self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_UP) else: - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) - self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_UP) else: if e1y == 0: - self.remap_eft_node_value_label(eft1, [3, 4], self.BOUNDARY_13) + self.remap_eft_node_value_label(eft1, [3, 4], self.BOUNDARY_13_UP) self.remap_eft_node_value_label(eft1, [5, 6], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_UP) + else: + self.remap_eft_node_value_label(eft1, [3, 4], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [5, 6], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_2_UP) elif element_quadruple_up: if e2 == e2b: @@ -536,31 +601,137 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_CURVE0_2_UP) self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_2_UP) if e2b == e2z: - self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23) + self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_UP) if e1 == 0: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) else: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) else: if e1 == 0: self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13_UP) else: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE0_2_UP) - self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR) - self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR) + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR_UP) elif e2 == e2z: if e1 == 0: - self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13) + self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_UP) self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) else: - self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23) - self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR) - self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23) + self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_UP) + else: + if e1 == 0: + self.remap_eft_node_value_label(eft1, [3, 4], self.BOUNDARY_13_UP) + self.remap_eft_node_value_label(eft1, [7, 8], self.SURFACE_REGULAR_UP) + else: + self.remap_eft_node_value_label(eft1, [3, 4, 7, 8], self.SURFACE_REGULAR_UP) + + elif element_quadruple_left: + nids[4] = self.nodeId[e3][e2][e1+2] + nids[6] = self.nodeId[e3+1][e2][e1+2] + + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_12_LEFT) + self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_12_LEFT) + self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_3_LEFT) + self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_CURVE0_3_LEFT) + + if e1y == 0: + self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_DOWN) + if e3 == 0: + self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + else: + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_13_DOWN) + else: + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_DOWN_LEFT) + + elif element_quadruple_right: + nids[4] = self.nodeId[e3][e2-1][e1+1] + nids[6] = self.nodeId[e3+1][e2-1][e1+1] + + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE0_3_RIGHT) + self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_3_RIGHT) + if e3y == 0: + self.remap_eft_node_value_label(eft1, [1], self.TRIPLE0_12_RIGHT) + self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_12_RIGHT) + else: + self.remap_eft_node_value_label(eft1, [1], self.TRIPLE_CURVE0_3_RIGHT) + self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_CURVE_3_RIGHT) + if e2b == e2z: + self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_DOWN) + if e3 == 0: + self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + else: + self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_23_DOWN) + else: + self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR_DOWN_RIGHT) + + elif element_down_right: + if e3 == 0: + if e2 == e2z: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_DOWN) + else: + self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR_DOWN_RIGHT) + else: + + self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [5], self.SURFACE_REGULAR_DOWN_RIGHT) + if e2 == e2z: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + self.remap_eft_node_value_label(eft1, [6, 8], self.BOUNDARY_23_DOWN) + else: + self.remap_eft_node_value_label(eft1, [6, 8], self.SURFACE_REGULAR_DOWN_RIGHT) + + elif element_down_left: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + if e3 == 0: + self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_LEFT) + if e1 == 0: + self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_DOWN) + else: + self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_DOWN_LEFT) + else: + self.remap_eft_node_value_label(eft1, [5, 7], self.SURFACE_REGULAR_DOWN_LEFT) + if e1 == 0: + self.remap_eft_node_value_label(eft1, [1, 3], self.BOUNDARY_13_DOWN) + else: + self.remap_eft_node_value_label(eft1, [1, 3], self.SURFACE_REGULAR_DOWN_LEFT) + + else: continue @@ -657,15 +828,24 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) - elif NODE_TYPE == self.BOUNDARY_12: + elif NODE_TYPE == self.BOUNDARY_12_LEFT: remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) - elif NODE_TYPE == self.BOUNDARY_13: + elif NODE_TYPE == self.BOUNDARY_12_RIGHT: + pass + elif NODE_TYPE == self.BOUNDARY_13_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + elif NODE_TYPE == self.BOUNDARY_13_UP: remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps - elif NODE_TYPE == self.BOUNDARY_23: + elif NODE_TYPE == self.BOUNDARY_23_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + elif NODE_TYPE == self.BOUNDARY_23_UP: remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) @@ -683,6 +863,11 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): elif NODE_TYPE == self.TRIPLE_CURVE_2_UP: remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.TRIPLE_CURVE_3_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + elif NODE_TYPE == self.TRIPLE_CURVE_3_RIGHT: + pass elif NODE_TYPE == self.TRIPLE_CURVE0_1_UP: remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) @@ -695,9 +880,21 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): elif NODE_TYPE == self.TRIPLE_CURVE0_2_UP: remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elif NODE_TYPE == self.SURFACE_REGULAR: + elif NODE_TYPE == self.TRIPLE_CURVE0_3_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) + elif NODE_TYPE == self.TRIPLE_CURVE0_3_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + + elif NODE_TYPE == self.SURFACE_REGULAR_DOWN_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + elif NODE_TYPE == self.SURFACE_REGULAR_DOWN_RIGHT: + pass + elif NODE_TYPE == self.SURFACE_REGULAR_UP: remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + elif NODE_TYPE == self.REGULAR: + pass else: raise ValueError("Remapping for derivatives of this 'node type' is not implemented") diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index ce0582e1..28e3d9e8 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -3,16 +3,14 @@ """ from enum import Enum -from scaffoldmaker.utils import vector, geometry +from scaffoldmaker.utils import vector import math from opencmiss.zinc.field import Field from opencmiss.utils.zinc.finiteelement import getMaximumNodeIdentifier, getMaximumElementIdentifier -from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D, ShieldRimDerivativeMode +from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, interpolateSampleCubicHermite, \ smoothCubicHermiteDerivativesLine, interpolateSampleLinear, interpolateCubicHermite -from opencmiss.zinc.node import Node from scaffoldmaker.utils.mirror import Mirror -from scaffoldmaker.meshtypes.meshtype_1d_path1 import extractPathParametersFromRegion from scaffoldmaker.utils.cylindermesh import Ellipse2D, EllipseShape @@ -21,6 +19,7 @@ class SphereShape(Enum): SPHERE_SHAPE_HALF_NNP = 2 # NNP is a3>=3 SPHERESHIELD_SHAPE_OCTANT_PPP = 3 + class SphereMesh: """ Sphere mesh generator. @@ -98,11 +97,11 @@ def createSphereMesh3d(self, fieldModule, coordinates): self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode) - self.calculateBoundaryElipses() + self.calculateBoundaryEllipses() self.generateNodes(nodes, fieldModule, coordinates) self.generateElements(mesh, fieldModule, coordinates) - def calculateBoundaryElipses(self): + def calculateBoundaryEllipses(self): """ :return: @@ -232,7 +231,7 @@ def createAdditionalPointsForIncreasingElementsCount(self): self.calculate_surface_quadruple_point() self.sample_triple_curves() self._shield3D.getQuadruplePoint2() - self.fixD2DerivativesOnTheEllipses() + # self.fixD2DerivativesOnTheEllipses() n3z = self._elementsCount[2] self._shield3D.smoothDerivativesToSurfaceQuadruple(n3z) self.smoothDerivativesToSurface() @@ -249,7 +248,9 @@ def calculate_surface_quadruple_point(self): btd3 = self._shield3D.pd3 n1z = self._elementsCount[1] + n1y = n1z - 1 n3z = self._elementsCount[2] + n3y = n3z - 1 radius = self._radius[0] # TODO need to be changed for spheroid @@ -260,20 +261,38 @@ def calculate_surface_quadruple_point(self): radiansAroundEllipse13 = math.pi / 2 radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 - for n in range(min(self._elementsCount[0], self._elementsCount[1]) - 1): - theta_2 = (n+1) * radiansPerElementAroundEllipse13 - theta_3 = (self._elementsCount[1] - 1) * radiansPerElementAroundEllipse12 - phi_3 = calculate_azimuth(theta_3, theta_2) - # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - x = spherical_to_cartesian(radius, theta_3, phi_3) - - a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - n1 = self._elementsCount[1] - n if n == 0 else self._elementsCount[1] - n - 1 - n2 = n if n == 0 else n+1 - btx[n3z][n2][n1] = x - btd1[n3z][n2][n1] = a1 # initialise - btd2[n3z][n2][n1] = a2 # initialise - btd3[n3z][n2][n1] = a3 + # for n in range(min(self._elementsCount[0], self._elementsCount[1]) - 1): + # theta_2 = (n+1) * radiansPerElementAroundEllipse13 + # theta_3 = (self._elementsCount[1] - 1) * radiansPerElementAroundEllipse12 + # phi_3 = calculate_azimuth(theta_3, theta_2) + # # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead + # x = spherical_to_cartesian(radius, theta_3, phi_3) + # + # a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) + # n1 = self._elementsCount[1] - n if n == 0 else self._elementsCount[1] - n - 1 + # n2 = n if n == 0 else n+1 + # btx[n3z][n2][n1] = x + # btd1[n3z][n2][n1] = a1 # initialise + # btd2[n3z][n2][n1] = a2 # initialise + # btd3[n3z][n2][n1] = a3 + + + + theta_2 = n3y * radiansPerElementAroundEllipse13 + theta_3 = n1y * radiansPerElementAroundEllipse12 + phi_3 = calculate_azimuth(theta_3, theta_2) + # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead + x = spherical_to_cartesian(radius, theta_3, phi_3) + + x = [x[0]*self._axes[0][c] + x[1]*self._axes[1][c] + x[2]*self._axes[2][c] for c in range(3)] + + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) + n1 = n1z + n2 = 0 + btx[n3z][n2][n1] = x + btd1[n3z][n2][n1] = a1 # initialise + btd2[n3z][n2][n1] = a2 # initialise + btd3[n3z][n2][n1] = a3 def sample_triple_curves(self): """ @@ -302,6 +321,130 @@ def sample_triple_curves(self): btx[n3z][nc + 1][n1z] = nx[nc] btd1[n3z][nc + 1][n1z] = nd1[nc] + + + # WHY DO WE NEED THIS????????? + if self._elementsCount[1] >= 0 and self._elementsCount[0] >= 0: + n3 = n3z + for n2 in range(2, self._elementsCount[0]): + nx, nd1 = sample_curves_sphere(btx[n3][n2][0], btx[n3][n2][n1z], n1z - 1) + for n1 in range(self._elementsCount[1]+1): + if n1 == 0: + btd2[n3][n2][0] = nd1[0] + elif n1 == n1z: + btd2[n3][n2][n1] = vector.scaleVector(nd1[-1], -1) + elif n1 == n1z - 1: + continue + else: + btx[n3][n2][n1] = nx[n1] + btd2[n3][n2][n1] = vector.scaleVector(nd1[n1], -1) + a1, a2, a3 = local_orthogonal_unit_vectors(nx[n1], self._axes[2]) + btd1[n3z][n2][n1] = a1 # initialise + btd3[n3z][n2][n1] = a3 + + # Regular curves from bottom to top (on triple curves) + for n2 in range(2, self._elementsCount[0]): + nx, nd1 = sample_curves_sphere(btx[0][n2][n1z], btx[n3z][n2][n1z], self._elementsCount[2] - 1) + for n3 in range(self._elementsCount[2] - 1): + if n3 == 0: + btd2[n3][n2][n1z] = nd1[0] + else: + btx[n3][n2][n1z] = nx[n3] + btd2[n3][n2][n1z] = nd1[n3] + a1, a2, a3 = local_orthogonal_unit_vectors(nx[n3], self._axes[2]) + btd1[n3][n2][n1z] = a1 # initialise + btd3[n3][n2][n1z] = a3 + + + + # smooth d2 curve + # for n2 in range(n2a + 1, n2z): + # a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][n2][n1z], self._axes[2]) + # btd3[n3z][n2][n1z] = a3 + # tx = [] + # td2 = [] + # for n1 in range(self._elementsCount[1] - 1): + # tx.append(btx[n3z][n2][n1]) + # td2.append(btd2[n3z][n2][n1]) + # tx.append(btx[n3z][n2][n1z]) + # td2.append(vector.crossproduct3(btd3[n3z][n2][n1z],btd1[n3z][n2][n1z])) + # for n3 in range(self._elementsCount[2] - 2, -1, -1): + # tx.append(btx[n3][n2][n1z]) + # td2.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) + # + # td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDirection=True) + # + # btd2[n3z][n2][0] = td2[0] + # for n1 in range(1, self._elementsCount[1] - 1): + # btd2[n3z][n2][n1] = vector.scaleVector(td2[n1], -1) + # btd2[n3z][n2][n1z] = vector.scaleVector(td2[self._elementsCount[1] - 1], -1) + # for n3 in range(self._elementsCount[2] - 2, -1, -1): + # btd2[n3][n2][n1z] = vector.scaleVector(td2[-1 - n3], -1) + + # curve 2 + nx, nd1 = sample_curves_sphere(btx[n3z][0][0], btx[n3z][0][n1z], self._elementsCount[1] - 1) + for n1 in range(self._elementsCount[1]+1): + if n1 == n1z-1: + continue + if n1 == 0: + btd2[n3z][0][0] = nd1[0] + elif n1 == n1z: + btd2[n3z][0][n1z] = vector.scaleVector(nd1[-1], -1) + else: + btx[n3z][0][n1] = nx[n1] + btd2[n3z][0][n1] = vector.scaleVector(nd1[n1], -1) + + + + + if self._elementsCount[0] >= 3 and self._elementsCount[1] >= 3: + n3 = n3z + n2 = 2 + n1 = 1 + nx, nd1 = sample_curves_sphere(btx[n3][n2][n1], btx[n3][n2z][n1], n2z - 2) + for n2 in range(2, self._elementsCount[0] + 1): + if n2 == 2: + btd1[n3][n2][n1] = nd1[0] + if n2 == n2z: + btd2[n3][n2][n1] = vector.scaleVector(nd1[-1], -1) + else: + btx[n3][n2][n1] = nx[n2 - 2] + btd1[n3][n2][n1] = nd1[n2 - 2] + a1, a2, a3 = local_orthogonal_unit_vectors(nx[n2 - 2], self._axes[2]) + btd2[n3z][n2][n1] = a2 # initialise + btd3[n3z][n2][n1] = a3 + + if self._elementsCount[0] >= 2: + # Regular curves from bottom to top (on triple curves, curve 2) + for n1 in range(1, self._elementsCount[1] - 1): + nx, nd1 = sample_curves_sphere(btx[0][0][n1], btx[n3z][0][n1], self._elementsCount[2] - 1) + for n3 in range(self._elementsCount[2] - 1): + if n3 == 0: + btd2[n3][0][n1] = nd1[0] + else: + btx[n3][0][n1] = nx[n3] + btd2[n3][0][n1] = nd1[n3] + a1, a2, a3 = local_orthogonal_unit_vectors(nx[n3], self._axes[2]) + btd1[n3][0][n1] = a1 # initialise + btd3[n3][0][n1] = a3 + + + # sample on curve 3 of the triple curves and smooth the end derivatives. + # arcLength = calculate_arc_length(btx[0][0][n1z], btx[n3z][0][n1z]) + # btd2[0][0][n1z] = vector.setMagnitude(btd2[0][0][n1z], arcLength) + nx, nd1 = sample_curves_sphere(btx[0][0][n1z], btx[n3z][0][n1z], self._elementsCount[2] - 1) + for n3 in range(self._elementsCount[2] - 1): # Last one use combination of d2 and d1 + if n3 == 0: + btd2[n3][0][n1z] = nd1[n3] + else: + btx[n3][0][n1z] = nx[n3] + btd2[n3][0][n1z] = nd1[n3] + a1, a2, a3 = local_orthogonal_unit_vectors(nx[n3], self._axes[2]) + btd1[n3][0][n1z] = a1 # initialise + btd3[n3][0][n1z] = a3 + + + # smooth d2 curve for n2 in range(n2a + 1, n2z): a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][n2][n1z], self._axes[2]) @@ -326,18 +469,8 @@ def sample_triple_curves(self): for n3 in range(self._elementsCount[2] - 2, -1, -1): btd2[n3][n2][n1z] = vector.scaleVector(td2[-1 - n3], -1) - # curve 2 - nx, nd1 = sample_curves_sphere(btx[n3z][0][0], btx[n3z][0][n1z], self._elementsCount[1] - 1) - for n1 in range(self._elementsCount[1]+1): - if n1 == n1z-1: - continue - if n1 == 0: - btd2[n3z][0][0] = nd1[0] - elif n1 == n1z: - btd2[n3z][0][n1z] = vector.scaleVector(nd1[-1], -1) - else: - btx[n3z][0][n1] = nx[n1] - btd2[n3z][0][n1] = vector.scaleVector(nd1[n1], -1) + + # smooth d1 curve for n1 in range(1, n1z - 1): @@ -387,11 +520,70 @@ def sample_triple_curves(self): + # smooth derivatives on horizontal curves below the triple curves. + for n3 in range(1, self._elementsCount[2] - 1): + tx = [] + td1 = [] + for n1 in range(self._elementsCount[1] + 1): + if n1 == n1z - 1: + continue + elif n1 == 0: + tx.append(btx[n3][0][n1]) + td1.append(btd2[n3][0][n1]) + else: + tx.append(btx[n3][0][n1]) + td1.append(btd1[n3][0][n1]) + for n2 in range(2, self._elementsCount[0] + 1): + tx.append(btx[n3][n2][n1z]) + if n2 == n2z: + td1.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) + else: + td1.append(btd1[n3][n2][n1z]) + + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) + for n1 in range(self._elementsCount[1] + 1): + if n1 == n1z - 1: + continue + elif n1 == 0: + btd2[n3][0][n1] = td1[0] + elif n1 == n1z: + btd1[n3][0][n1] = td1[n1-1] + else: + btd1[n3][0][n1] = td1[n1] + + for n2 in range(2, self._elementsCount[0] + 1): + if n2 == n2z: + btd2[n3][n2][n1z] = vector.scaleVector(td1[-1], -1) + else: + btd1[n3][n2][n1z] = td1[self._elementsCount[1] + n2 - 2] + + + + + + # sample on curve 1 of the triple curves and smooth the end derivatives. - # sample on curve 3 of the triple curves and smooth the end derivatives. - arcLength = calculate_arc_length(btx[0][0][n1z], btx[n3z][0][n1z]) - btd2[0][0][n1z] = vector.setMagnitude(btd2[0][0][n1z], arcLength) + + + # WHY DO WE NEED THIS????????? + # if self._elementsCount[1] >= 3 and self._elementsCount[0] >= 3: + # n3 = n3z + # for n2 in range(2, self._elementsCount[0]): + # nx, nd1 = sample_curves_sphere(btx[n3][n2][0], btx[n3][n2][n1z], n1z - 1) + # for n1 in range(self._elementsCount[1]): + # if n1 == 0: + # btd2[n3][n2][0] = nd1[0] + # elif n1 == n1z: + # btd2[n3][n2][n1] = vector.scaleVector(nd1[-1], -1) + # elif n1 == n1z - 1: + # continue + # else: + # btx[n3][n2][n1] = nx[n1] + # btd2[n3][n2][n1] = vector.scaleVector(nd1[n1], -1) + # a1, a2, a3 = local_orthogonal_unit_vectors(nx[n1], self._axes[2]) + # btd1[n3z][n2][n1] = a1 # initialise + # btd3[n3z][n2][n1] = a3 def fixD2DerivativesOnTheEllipses(self): """ @@ -421,13 +613,7 @@ def smoothDerivativesToSurface(self): Smooth derivatives leading to quadruple point where 3 hex elements merge. :param n3: Index of through-wall coordinates to use. ''' - n3a = 0 n3z = self._elementsCount[2] - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) n1z = self._elementsCount[1] btx = self._shield3D.px @@ -435,58 +621,43 @@ def smoothDerivativesToSurface(self): btd2 = self._shield3D.pd2 btd3 = self._shield3D.pd3 - for n2 in range(self._elementsCount[0]): - for n1 in range(1, self._elementsCount[1]+1): - if btx[n3z][n2][n1]: - tx = [] - td3 = [] - if n2 == 0: - if n1 == n1z: - n2r = n2 + 1 - n1r = n1 - 1 - co = [-1, 1, 1] - else: - n2r = n2 + 1 - n1r = n1 - co = [-1, 1, 0] - else: - if n1 == n1z: - n2r = n2 - n1r = n1 - 1 - co = [0, 1, 1] - else: - n2r = n2 - n1r = n1 - co = [0, 1, 0] - - tx.append(btx[n3z-1][n2r][n1r]) - td3.append( - [(co[0]*btd1[n3z-1][n2r][n1r][c] + co[1]*btd2[n3z-1][n2r][n1r][c] + co[2]*btd3[n3z-1][n2r][n1r][c]) for c in range(3)]) - for n3 in range(n3z, n3z + 1): + for n3 in range(1, self._elementsCount[2] + 1): + for n2 in range(self._elementsCount[0]): + for n1 in range(1, self._elementsCount[1]+1): + if self.on_sphere(n3, n2, n1): + # find indices of the neighbour node inside and contribution of its derivatives. + n3r = n3 - 1 if n3 == n3z else n3 + n2r = n2 + 1 if n2 == 0 else n2 + n1r = n1 - 1 if n1 == n1z else n1 + co = [-1, 1, 1] + co[0] = -1 if n2 == 0 else 0 + co[1] = 1 if n3 == n3z else 0 + co[2] = 1 if n1 == n1z else 0 + + tx = [] + td3 = [] + tx.append(btx[n3r][n2r][n1r]) + td3.append( + [(co[0]*btd1[n3r][n2r][n1r][c] + co[1]*btd2[n3r][n2r][n1r][c] + co[2]*btd3[n3r][n2r][n1r][c]) for c in range(3)]) + tx.append(btx[n3][n2][n1]) td3.append(btd3[n3][n2][n1]) - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - for n3 in range(n3z, n3z + 1): - btd3[n3][n2][n1] = td3[n3 - n3z + 1] - - # for n2 in range(self._elementsCount[0] + 1): - # if 1 < n2 < self._elementsCount[0]: - # tx = [] - # td3 = [] - # for n3 in range(n3b, n3b+2): - # n1 = self._elementsCount[1] - 2 + n3 - # tx.append(btx[n3][n2][n1]) - # if n3 == n3b: - # td3.append(vector.addVectors(btd2[n3][n2][n1], btd3[n3][n2][n1])) - # else: - # td3.append(btd3[n3][n2][n1]) - # - # td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - # - # for nc3 in range(1, self._elementsCountAcrossShell + self._elementsCountAcrossTransition + 1): - # n3 = nc3 + n3b - # n1 = n3 - # btd3[n3][n2][n1] = td3[nc3] + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + btd3[n3][n2][n1] = td3[1] + + def on_sphere(self, n3, n2, n1): + """ + Check if the given point is on the sphere. + :param n3, n2, n1: node indexes in data structure [n3][n2][n1] + :return: True, if it is on the sphere. + """ + n3z = self._elementsCount[2] + n1z = self._elementsCount[1] + + btx = self._shield3D.px + + return (n3 == n3z or n2 == 0 or n1 == n1z) and btx[n3][n2][n1] def generateNodes(self, nodes, fieldModule, coordinates): """ From 69223c9870fdf372d37f16d72a9ce9f27a038bf7 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 22 Sep 2021 17:02:06 +1200 Subject: [PATCH 15/37] Make elements consistent for all of the octants --- .../meshtypes/meshtype_3d_solidsphere2.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index dfbdd115..53df5184 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -191,12 +191,12 @@ def generateBaseMesh(region, options): elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) - axis1 = [0.0, -1.0, 0.0] if (hemisphere or full) and not octant: + axis1 = [0.0, -1.0, 0.0] axis2 = [1.0, 0.0, 0.0] axis3 = [0.0, 0.0, 1.0] axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) @@ -214,7 +214,7 @@ def generateBaseMesh(region, options): axis2 = [-1.0, 0.0, 0.0] axis3 = [0.0, 0.0, 1.0] axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) @@ -224,7 +224,7 @@ def generateBaseMesh(region, options): axis2 = [1.0, 0.0, 0.0] axis3 = [0.0, 0.0, -1.0] axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, @@ -243,7 +243,7 @@ def generateBaseMesh(region, options): axis1 = [0.0, -1.0, 0.0] axis3 = [0.0, 0.0, -1.0] axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) From beff565419c0a0bae23fe3bd84d6e79d66311423 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 22 Sep 2021 17:02:58 +1200 Subject: [PATCH 16/37] Make addVectors work for any number of input vectors. --- src/scaffoldmaker/utils/vector.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/scaffoldmaker/utils/vector.py b/src/scaffoldmaker/utils/vector.py index c19e2a12..510e3b58 100644 --- a/src/scaffoldmaker/utils/vector.py +++ b/src/scaffoldmaker/utils/vector.py @@ -36,12 +36,20 @@ def setMagnitude(v, mag): scale = mag/math.sqrt(sum(c*c for c in v)) return [ c*scale for c in v ] -def addVectors(v1,v2,s1=1.0,s2=1.0): +def addVectors(vectors, scalars = None): ''' - returns s1*v1+s2*v2 where s1 and s2 are scalars. - :return: Vector s1*v1+s2*v2 + returns s1*v1+s2*v2+... where scalars = [s1, s2, ...] and vectors=[v1, v2, ...]. + :return: Resultant vector ''' - return [(s1 * v1[c] + s2 * v2[c]) for c in range(len(v1))] + if not scalars: + scalars = [1]*len(vectors) + else: + assert len(vectors) == len(scalars) + + resultant = [0, 0, 0] + for i in range(len(vectors)): + resultant = [resultant[c] + scalars[i] * vectors[i][c] for c in range(3)] + return resultant def scalarProjection(v1, v2): @@ -66,7 +74,7 @@ def vectorRejection(v1, v2): :return: A rejection vector. """ v1p = vectorProjection(v1, v2) - return addVectors(v1, v1p, 1.0, -1.0) + return addVectors([v1, v1p], [1.0, -1.0]) def scaleVector(v, s): @@ -103,6 +111,6 @@ def rotateVectorAroundVector(v, k, a): :return: rotated vector. """ k = normalise(k) - vperp = addVectors(v, crossproduct3(k, v), math.cos(a), math.sin(a)) + vperp = addVectors([v, crossproduct3(k, v)], [math.cos(a), math.sin(a)]) vparal = scaleVector(k, dotproduct(k, v)*(1 - math.cos(a))) - return addVectors(vperp, vparal) + return addVectors([vperp, vparal]) From 194f2be800820d81d05a9852a23fc4e7f5486a9b Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 22 Sep 2021 17:06:24 +1200 Subject: [PATCH 17/37] Make some utility functions for sphere. Make sampling and smoothing for the sphere surface curves more generic. --- src/scaffoldmaker/utils/shieldmesh.py | 38 +- src/scaffoldmaker/utils/spheremesh.py | 531 ++++++++++++-------------- 2 files changed, 267 insertions(+), 302 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 58781d32..1a557d15 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -38,9 +38,25 @@ class ShieldMesh3D: def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP): - ''' - Parameters - ''' + """ + 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the centre. + The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a special node on the + surface where the elements merge. 'Triple curves' meet at the quadruple point and a fourth curve that connects + to another quadruple point which is inside. + The structure is like a elementsCountAcross[0] X elementsCountAcross[1] X elementsCountAcross[2] box where + some nodes does not exist and stored as None. The quadruple point is stored at [n3z][0][n1z] (top, front and right most node) + where n3z is top most and n1z is the right most indexes. + Triple curves and surfaces connecting to the quadruple point, divides the surface and interior into 3 regions + (top, left and right). Triple curve 1 connects the quadruple point to the plane 2-3. Similarly triple curves 2 and 3 + connect the quadruple point to the planes 1-3 and 1-2, respectively. It is the same for the inside quadruple. + Any point on region left has n2 = 0. Similarly on region right -> n1 = n1z and on top -> n3 = n3z. + There is a gap between node indexes of a node on the triple curve and the next node on the surface. + + + :param elementsCountAcross: + :param elementsCountRim: + :param shieldMode: + """ assert elementsCountRim >= 0 # assert elementsCountAlong >= 1 # assert elementsCountAcross >= (elementsCountRim + 4) @@ -90,7 +106,7 @@ def getQuadruplePoint2(self): n3r0, n2r0, n1r0 = n3y, n2z, n1y n3r, n2r, n1r = n3z, n2z, n1z - ts = vector.magnitude(vector.addVectors(self.px[n3r0][n2r0][n1r0], self.px[n3r][n2r][n1r], 1, -1)) + ts = vector.magnitude(vector.addVectors([self.px[n3r0][n2r0][n1r0], self.px[n3r][n2r][n1r]], [1, -1])) ra = vector.magnitude(self.px[n3z][0][n1z]) x = vector.scaleVector(self.px[n3z][0][n1z], (1 - ts/ra)) self.px[n3y][1][n1y] = x @@ -127,8 +143,8 @@ def getQuadruplePoint2(self): self.pd1[n3y][n2][n1] = [self.px[n3y][1][n1][0] - self.px[n3z][0][n1][0], 0.0, 0.0] self.pd2[n3y][n2][n1] = [0.0, 0.0, -self.px[n3y][1][n1][2] + self.px[n3z][0][n1][2]] else: - self.pd1[n3y][n2][n1] = vector.addVectors(self.px[n3y][n2][n1], self.px[n3y][n2+1][n1], -1, 1) - self.pd2[n3y][n2][n1] = vector.addVectors(self.px[n3y][n2][n1], self.px[0][n2][n1], 1, -1) + self.pd1[n3y][n2][n1] = vector.addVectors([self.px[n3y][n2][n1], self.px[n3y][n2+1][n1]], [-1, 1]) + self.pd2[n3y][n2][n1] = vector.addVectors([self.px[n3y][n2][n1], self.px[0][n2][n1]], [1, -1]) @@ -150,8 +166,8 @@ def getQuadruplePoint2(self): self.pd1[n3][n2][n1] = [self.px[n3][n2][n1][0] - self.px[n3][n2-1][n1+1][0], 0.0, 0.0] self.pd3[n3][n2][n1] = [0.0, self.px[n3][n2-1][n1+1][1] - self.px[n3][n2][n1][1], 0.0] else: - self.pd1[n3][n2][n1] = vector.addVectors(self.px[n3][n2+1][n1], self.px[n3][n2][n1], 1, -1) - self.pd3[n3][n2][n1] = vector.addVectors(self.px[n3][n2][n1+1], self.px[n3][n2][n1], 1, -1) + self.pd1[n3][n2][n1] = vector.addVectors([self.px[n3][n2+1][n1], self.px[n3][n2][n1]], [1, -1]) + self.pd3[n3][n2][n1] = vector.addVectors([self.px[n3][n2][n1+1], self.px[n3][n2][n1]], [1, -1]) # smooth d1 in regular 1 @@ -169,7 +185,7 @@ def getQuadruplePoint2(self): else: for n3 in range(1, self.elementsCountAcross[2]): for n1 in range(1, self.elementsCountAcross[1]): - self.pd1[n3][1][n1] = vector.addVectors(self.px[n3][2][n1], self.px[n3][1][n1], 1, -1) + self.pd1[n3][1][n1] = vector.addVectors([self.px[n3][2][n1], self.px[n3][1][n1]], [1, -1]) self.pd1[n3][2][n1] = vector.setMagnitude(self.pd1[n3][2][n1], vector.magnitude(self.pd1[n3][1][n1])) # smooth d3 in regular @@ -189,7 +205,7 @@ def getQuadruplePoint2(self): else: for n3 in range(1, self.elementsCountAcross[2]): for n2 in range(1, self.elementsCountAcross[0]): - self.pd3[n3][n2][1] = vector.addVectors(self.px[n3][n2][1], self.px[n3][n2][0], 1, -1) + self.pd3[n3][n2][1] = vector.addVectors([self.px[n3][n2][1], self.px[n3][n2][0]], [1, -1]) self.pd3[n3][n2][0] = vector.setMagnitude(self.pd3[n3][n2][0], vector.magnitude(self.pd3[n3][n2][1])) @@ -206,7 +222,7 @@ def getQuadruplePoint2(self): for n3 in range(self.elementsCountAcross[2]): self.pd2[n3][n2][n1] = td2[n3] else: - self.pd2[1][n2][n1] = vector.addVectors(self.px[1][n2][n1], self.px[0][n2][n1], 1, -1) + self.pd2[1][n2][n1] = vector.addVectors([self.px[1][n2][n1], self.px[0][n2][n1]], [1, -1]) self.pd2[0][n2][n1] = vector.setMagnitude(self.pd2[0][n2][n1], vector.magnitude(self.pd2[1][n2][n1])) diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 28e3d9e8..0065c6ec 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -229,16 +229,16 @@ def createAdditionalPointsForIncreasingElementsCount(self): """ self.calculate_surface_quadruple_point() - self.sample_triple_curves() + self.sample_triple_curves_on_sphere() + self.sample_regular_curves_on_sphere() self._shield3D.getQuadruplePoint2() - # self.fixD2DerivativesOnTheEllipses() n3z = self._elementsCount[2] self._shield3D.smoothDerivativesToSurfaceQuadruple(n3z) self.smoothDerivativesToSurface() def calculate_surface_quadruple_point(self): """ - Calculate coordinates and derivatives of points where 3 hex elements merge. + Calculate coordinates and derivatives of the quadruple point on the surface, where 3 hex elements merge. :return: """ @@ -249,6 +249,7 @@ def calculate_surface_quadruple_point(self): n1z = self._elementsCount[1] n1y = n1z - 1 + n2z = self._elementsCount[0] n3z = self._elementsCount[2] n3y = n3z - 1 @@ -261,30 +262,16 @@ def calculate_surface_quadruple_point(self): radiansAroundEllipse13 = math.pi / 2 radiansPerElementAroundEllipse13 = radiansAroundEllipse13 / elementsAroundEllipse13 - # for n in range(min(self._elementsCount[0], self._elementsCount[1]) - 1): - # theta_2 = (n+1) * radiansPerElementAroundEllipse13 - # theta_3 = (self._elementsCount[1] - 1) * radiansPerElementAroundEllipse12 - # phi_3 = calculate_azimuth(theta_3, theta_2) - # # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - # x = spherical_to_cartesian(radius, theta_3, phi_3) - # - # a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - # n1 = self._elementsCount[1] - n if n == 0 else self._elementsCount[1] - n - 1 - # n2 = n if n == 0 else n+1 - # btx[n3z][n2][n1] = x - # btd1[n3z][n2][n1] = a1 # initialise - # btd2[n3z][n2][n1] = a2 # initialise - # btd3[n3z][n2][n1] = a3 - - - theta_2 = n3y * radiansPerElementAroundEllipse13 theta_3 = n1y * radiansPerElementAroundEllipse12 phi_3 = calculate_azimuth(theta_3, theta_2) # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead - x = spherical_to_cartesian(radius, theta_3, phi_3) + # ratio = -0.1 * (min(self._elementsCount) - 2) + 1 if self._elementsCount[0] <= 2 else 0.2 + ratio = 1 + # local_x = intersection_of_two_great_circles_on_sphere(btx[0][0][n1y-1], btx[n3z][n2z][n1z], btx[0][2][n1z], btx[n3z][0][0]) + local_x = spherical_to_cartesian(radius, theta_3, ratio * phi_3 + (1-ratio)*math.pi/2) - x = [x[0]*self._axes[0][c] + x[1]*self._axes[1][c] + x[2]*self._axes[2][c] for c in range(3)] + x = local_to_global_coordinates(local_x, self._axes, self._centre) a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) n1 = n1z @@ -294,296 +281,215 @@ def calculate_surface_quadruple_point(self): btd2[n3z][n2][n1] = a2 # initialise btd3[n3z][n2][n1] = a3 - def sample_triple_curves(self): + def sample_triple_curves_on_sphere(self): """ - Sample points on the triple curves of quadruple point on the sphere surface. + Sample points on the triple curves of the 'quadruple point' on the sphere surface. :return: """ - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n3a = 0 n1z = self._elementsCount[1] n2z = self._elementsCount[0] n3z = self._elementsCount[2] # sample on curve 1 of the triple curves and smooth the end derivatives. - nx, nd1 = sample_curves_sphere(btx[n3z][0][n1z], btx[n3z][n2z][n1z], self._elementsCount[0] - 1) - for nc in range(self._elementsCount[0]): - if nc == 0: - btd1[n3z][0][n1z] = nd1[0] - elif nc == n2z - 1: - btd2[n3z][n2z][n1z] = vector.scaleVector(nd1[-1], -1) - else: - btx[n3z][nc + 1][n1z] = nx[nc] - btd1[n3z][nc + 1][n1z] = nd1[nc] - - - - # WHY DO WE NEED THIS????????? - if self._elementsCount[1] >= 0 and self._elementsCount[0] >= 0: - n3 = n3z - for n2 in range(2, self._elementsCount[0]): - nx, nd1 = sample_curves_sphere(btx[n3][n2][0], btx[n3][n2][n1z], n1z - 1) - for n1 in range(self._elementsCount[1]+1): - if n1 == 0: - btd2[n3][n2][0] = nd1[0] - elif n1 == n1z: - btd2[n3][n2][n1] = vector.scaleVector(nd1[-1], -1) - elif n1 == n1z - 1: - continue - else: - btx[n3][n2][n1] = nx[n1] - btd2[n3][n2][n1] = vector.scaleVector(nd1[n1], -1) - a1, a2, a3 = local_orthogonal_unit_vectors(nx[n1], self._axes[2]) - btd1[n3z][n2][n1] = a1 # initialise - btd3[n3z][n2][n1] = a3 - - # Regular curves from bottom to top (on triple curves) - for n2 in range(2, self._elementsCount[0]): - nx, nd1 = sample_curves_sphere(btx[0][n2][n1z], btx[n3z][n2][n1z], self._elementsCount[2] - 1) - for n3 in range(self._elementsCount[2] - 1): - if n3 == 0: - btd2[n3][n2][n1z] = nd1[0] - else: - btx[n3][n2][n1z] = nx[n3] - btd2[n3][n2][n1z] = nd1[n3] - a1, a2, a3 = local_orthogonal_unit_vectors(nx[n3], self._axes[2]) - btd1[n3][n2][n1z] = a1 # initialise - btd3[n3][n2][n1z] = a3 - - - - # smooth d2 curve - # for n2 in range(n2a + 1, n2z): - # a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][n2][n1z], self._axes[2]) - # btd3[n3z][n2][n1z] = a3 - # tx = [] - # td2 = [] - # for n1 in range(self._elementsCount[1] - 1): - # tx.append(btx[n3z][n2][n1]) - # td2.append(btd2[n3z][n2][n1]) - # tx.append(btx[n3z][n2][n1z]) - # td2.append(vector.crossproduct3(btd3[n3z][n2][n1z],btd1[n3z][n2][n1z])) - # for n3 in range(self._elementsCount[2] - 2, -1, -1): - # tx.append(btx[n3][n2][n1z]) - # td2.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) - # - # td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDirection=True) - # - # btd2[n3z][n2][0] = td2[0] - # for n1 in range(1, self._elementsCount[1] - 1): - # btd2[n3z][n2][n1] = vector.scaleVector(td2[n1], -1) - # btd2[n3z][n2][n1z] = vector.scaleVector(td2[self._elementsCount[1] - 1], -1) - # for n3 in range(self._elementsCount[2] - 2, -1, -1): - # btd2[n3][n2][n1z] = vector.scaleVector(td2[-1 - n3], -1) - + self.sample_curves_between_two_nodes_on_sphere([n3z, 0, n1z], [n3z, n2z, n1z], self._elementsCount[0] - 1, + [1, None], [1], [-2]) # curve 2 - nx, nd1 = sample_curves_sphere(btx[n3z][0][0], btx[n3z][0][n1z], self._elementsCount[1] - 1) - for n1 in range(self._elementsCount[1]+1): - if n1 == n1z-1: - continue - if n1 == 0: - btd2[n3z][0][0] = nd1[0] - elif n1 == n1z: - btd2[n3z][0][n1z] = vector.scaleVector(nd1[-1], -1) - else: - btx[n3z][0][n1] = nx[n1] - btd2[n3z][0][n1] = vector.scaleVector(nd1[n1], -1) - - - - - if self._elementsCount[0] >= 3 and self._elementsCount[1] >= 3: - n3 = n3z - n2 = 2 - n1 = 1 - nx, nd1 = sample_curves_sphere(btx[n3][n2][n1], btx[n3][n2z][n1], n2z - 2) - for n2 in range(2, self._elementsCount[0] + 1): - if n2 == 2: - btd1[n3][n2][n1] = nd1[0] - if n2 == n2z: - btd2[n3][n2][n1] = vector.scaleVector(nd1[-1], -1) - else: - btx[n3][n2][n1] = nx[n2 - 2] - btd1[n3][n2][n1] = nd1[n2 - 2] - a1, a2, a3 = local_orthogonal_unit_vectors(nx[n2 - 2], self._axes[2]) - btd2[n3z][n2][n1] = a2 # initialise - btd3[n3z][n2][n1] = a3 - - if self._elementsCount[0] >= 2: - # Regular curves from bottom to top (on triple curves, curve 2) - for n1 in range(1, self._elementsCount[1] - 1): - nx, nd1 = sample_curves_sphere(btx[0][0][n1], btx[n3z][0][n1], self._elementsCount[2] - 1) - for n3 in range(self._elementsCount[2] - 1): - if n3 == 0: - btd2[n3][0][n1] = nd1[0] - else: - btx[n3][0][n1] = nx[n3] - btd2[n3][0][n1] = nd1[n3] - a1, a2, a3 = local_orthogonal_unit_vectors(nx[n3], self._axes[2]) - btd1[n3][0][n1] = a1 # initialise - btd3[n3][0][n1] = a3 - - - # sample on curve 3 of the triple curves and smooth the end derivatives. - # arcLength = calculate_arc_length(btx[0][0][n1z], btx[n3z][0][n1z]) - # btd2[0][0][n1z] = vector.setMagnitude(btd2[0][0][n1z], arcLength) - nx, nd1 = sample_curves_sphere(btx[0][0][n1z], btx[n3z][0][n1z], self._elementsCount[2] - 1) - for n3 in range(self._elementsCount[2] - 1): # Last one use combination of d2 and d1 - if n3 == 0: - btd2[n3][0][n1z] = nd1[n3] - else: - btx[n3][0][n1z] = nx[n3] - btd2[n3][0][n1z] = nd1[n3] - a1, a2, a3 = local_orthogonal_unit_vectors(nx[n3], self._axes[2]) - btd1[n3][0][n1z] = a1 # initialise - btd3[n3][0][n1z] = a3 - + self.sample_curves_between_two_nodes_on_sphere([n3z, 0, 0], [n3z, 0, n1z], self._elementsCount[1] - 1, + [2], [-2], [None, -2]) + # curve 3. + self.sample_curves_between_two_nodes_on_sphere([0, 0, n1z], [n3z, 0, n1z], self._elementsCount[2] - 1, + [2], [2], [None, None]) + def sample_regular_curves_on_sphere(self): + """ + Create all other nodes on the sphere except the nodes on the triple curves and ellipses. + :return: + """ + n2a = 1 + n1z = self._elementsCount[1] + n2z = self._elementsCount[0] + n3z = self._elementsCount[2] - # smooth d2 curve + # regular curves crossing curve 1 + for n2 in range(2, self._elementsCount[0]): + # bottom right + self.sample_curves_between_two_nodes_on_sphere([0, n2, n1z], [n3z, n2, n1z], self._elementsCount[2] - 1, + [2], [2], [None, None]) + # top + self.sample_curves_between_two_nodes_on_sphere([n3z, n2, 0], [n3z, n2, n1z], self._elementsCount[1] - 1, + [2], [-2], [None, -2]) + + # regular curves crossing curve 2 + for n1 in range(1, self._elementsCount[1] - 1): + # bottom left. Top is done before. + self.sample_curves_between_two_nodes_on_sphere([0, 0, n1], [n3z, 0, n1], self._elementsCount[2] - 1, + [2], [2], [None, None]) + + # smooth regular curves crossing curve 1 for n2 in range(n2a + 1, n2z): - a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][n2][n1z], self._axes[2]) - btd3[n3z][n2][n1z] = a3 - tx = [] - td2 = [] - for n1 in range(self._elementsCount[1] - 1): - tx.append(btx[n3z][n2][n1]) - td2.append(btd2[n3z][n2][n1]) - tx.append(btx[n3z][n2][n1z]) - td2.append(vector.crossproduct3(btd3[n3z][n2][n1z],btd1[n3z][n2][n1z])) - for n3 in range(self._elementsCount[2] - 2, -1, -1): - tx.append(btx[n3][n2][n1z]) - td2.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) - - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True, fixEndDirection=True) + self.smooth_derivatives_regular_surface_curve(2, n2, [[2], [None, None]], [[-2], [-2]], [[None, -2], [-2]]) - btd2[n3z][n2][0] = td2[0] - for n1 in range(1, self._elementsCount[1] - 1): - btd2[n3z][n2][n1] = vector.scaleVector(td2[n1], -1) - btd2[n3z][n2][n1z] = vector.scaleVector(td2[self._elementsCount[1] - 1], -1) - for n3 in range(self._elementsCount[2] - 2, -1, -1): - btd2[n3][n2][n1z] = vector.scaleVector(td2[-1 - n3], -1) - - - - - # smooth d1 curve + # smooth regular curves crossing curve 2 for n1 in range(1, n1z - 1): - a1, a2, a3 = local_orthogonal_unit_vectors(btx[n3z][0][n1], self._axes[2]) - btd3[n3z][0][n1] = a3 - tx = [] - td1 = [] - tx.append(btx[0][0][n1]) - td1.append(btd2[0][0][n1]) - for n3 in range(1, self._elementsCount[2] - 1): - tx.append(btx[n3][0][n1]) - td1.append(btd1[n3][0][n1]) - tx.append(btx[n3z][0][n1]) - td1.append(vector.crossproduct3(btd2[n3z][0][n1], btd3[n3z][0][n1])) - for n2 in range(2, self._elementsCount[0]): - tx.append(btx[n3z][n2][n1]) - td1.append(btd1[n3z][n2][n1]) - tx.append(btx[n3z][n2z][n1]) - td1.append(vector.scaleVector(btd2[n3z][n2z][n1], -1)) - - # for n2 in range(self._elementsCount[1] - 1): - # tx.append(btx[n3z][n2][n1]) - # td1.append(btd2[n3z][n2][n1]) - # tx.append(btx[n3z][n2][n1z]) - # td1.append(vector.crossproduct3(btd3[n3z][n2][n1z],btd1[n3z][n2][n1z])) - # for n3 in range(self._elementsCount[2] - 2, -1, -1): - # tx.append(btx[n3][n2][n1z]) - # td1.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) - - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) - btd2[0][0][n1] = td1[0] - for n3 in range(1, self._elementsCount[2] - 1): - btd1[n3][0][n1] = td1[n3] - btd1[n3z][0][n1] = td1[self._elementsCount[2] - 1] - for n2 in range(2, self._elementsCount[0]): - btd1[n3z][n2][n1] = td1[self._elementsCount[2] + n2-2] - btd2[n3z][n2z][n1] = vector.scaleVector(td1[-1], -1) - - - - # btd2[n3z][n2][0] = td1[0] - # for n1 in range(1, self._elementsCount[1] - 1): - # btd2[n3z][n2][n1] = td1[n1] - # btd2[n3z][n2][n1z] = vector.scaleVector(td1[1], -1) - # for n3 in range(self._elementsCount[2] - 2, -1, -1): - # btd2[n3][n2][n1z] = vector.scaleVector(td1[-1 - n3], -1) - - - - # smooth derivatives on horizontal curves below the triple curves. - for n3 in range(1, self._elementsCount[2] - 1): - tx = [] - td1 = [] - for n1 in range(self._elementsCount[1] + 1): - if n1 == n1z - 1: - continue - elif n1 == 0: - tx.append(btx[n3][0][n1]) - td1.append(btd2[n3][0][n1]) - else: - tx.append(btx[n3][0][n1]) - td1.append(btd1[n3][0][n1]) - for n2 in range(2, self._elementsCount[0] + 1): - tx.append(btx[n3][n2][n1z]) - if n2 == n2z: - td1.append(vector.scaleVector(btd2[n3][n2][n1z], -1)) - else: - td1.append(btd1[n3][n2][n1z]) - - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) - - for n1 in range(self._elementsCount[1] + 1): - if n1 == n1z - 1: - continue - elif n1 == 0: - btd2[n3][0][n1] = td1[0] - elif n1 == n1z: - btd1[n3][0][n1] = td1[n1-1] - else: - btd1[n3][0][n1] = td1[n1] + self.smooth_derivatives_regular_surface_curve(1, n1, [[2], [None, None]], [[2], [1]], [[None, 1], [-2]]) - for n2 in range(2, self._elementsCount[0] + 1): - if n2 == n2z: - btd2[n3][n2][n1z] = vector.scaleVector(td1[-1], -1) - else: - btd1[n3][n2][n1z] = td1[self._elementsCount[1] + n2 - 2] + # smooth regular curves crossing curve 3 + for n3 in range(1, self._elementsCount[2] - 1): + self.smooth_derivatives_regular_surface_curve(3, n3, [[2], [None, None]], [[1], [1]], [[None, 1], [-2]]) + def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStart, dbetween, dEnd): + """ + samples curves on the sphere surface between two points given by their indexes. + :param id1, id2: [n3,n2,n1] for the first and second points. + :param dStart, dBetween, dEnd: Specifies the derivatives that are used for this curve at the beginning, end and + in between. e.g. dStart=[2, -1, None] means d2 for the first node, -1 for the second node and skip the third one. + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + # Find what index is constant + if id1[0] != id2[0]: + constant_index = 3 + elementsCount = self._elementsCount[2] + elif id1[1] != id2[1]: + constant_index = 2 + elementsCount = self._elementsCount[0] + elif id1[2] != id2[2]: + constant_index = 1 + elementsCount = self._elementsCount[1] + + else: + raise ValueError("None of n1, n2, or n3 is constant. Only on the constant curves.") + + btd = {1: btd1, 2: btd2, 3: btd3} + idi = {0: id1[0], 1: id1[1], 2: id1[2]} + + nx, nd1 = sample_curves_on_sphere(btx[id1[0]][id1[1]][id1[2]], btx[id2[0]][id2[1]][id2[2]], elementsOut) + + nit = 0 + for ni in range(elementsCount + 1): + idi[3 - constant_index] = ni + + if ni < len(dStart): + if dStart[ni]: + btd[dStart[ni]][idi[0]][idi[1]][idi[2]] = nd1[nit] if dStart[ni] > 0 else vector.scaleVector( + nd1[nit], -1) + nit += 1 + elif ni > elementsCount - len(dEnd): + nie = ni - elementsCount + len(dEnd) - 1 + if dEnd[nie]: + btd[abs(dEnd[nie])][idi[0]][idi[1]][idi[2]] = nd1[nit] if dEnd[nie] > 0 else vector.scaleVector( + nd1[nit], -1) + nit += 1 + else: + btx[idi[0]][idi[1]][idi[2]] = nx[nit] + a1, a2, a3 = local_orthogonal_unit_vectors(nx[nit], self._axes[2]) + btd1[idi[0]][idi[1]][idi[2]] = a1 # initialise + btd2[idi[0]][idi[1]][idi[2]] = a2 # initialise + btd3[idi[0]][idi[1]][idi[2]] = a3 # initialise + btd[abs(dbetween[0])][idi[0]][idi[1]][idi[2]] = nd1[nit] if dbetween[0] > 0 else vector.scaleVector( + nd1[nit], -1) + nit += 1 - # sample on curve 1 of the triple curves and smooth the end derivatives. + def smooth_derivatives_regular_surface_curve(self, constant_index, nc, dStart, dBetween, dEnd): + """ + Smooth derivatives for each constant index curve. e.g. n2 = 3 + :param constant_index: Specifies n1, n2 or n3 is constant. + :param nc: Index that is constant across the curve. + :param dStart, dBetween, dEnd: See sample_curves_between_two_nodes_on_sphere. The difference here is + the values are given for two curves that connect one end to the other end of the sphere surface. + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + n1z = self._elementsCount[1] + n2z = self._elementsCount[0] + n3z = self._elementsCount[2] - # WHY DO WE NEED THIS????????? - # if self._elementsCount[1] >= 3 and self._elementsCount[0] >= 3: - # n3 = n3z - # for n2 in range(2, self._elementsCount[0]): - # nx, nd1 = sample_curves_sphere(btx[n3][n2][0], btx[n3][n2][n1z], n1z - 1) - # for n1 in range(self._elementsCount[1]): - # if n1 == 0: - # btd2[n3][n2][0] = nd1[0] - # elif n1 == n1z: - # btd2[n3][n2][n1] = vector.scaleVector(nd1[-1], -1) - # elif n1 == n1z - 1: - # continue - # else: - # btx[n3][n2][n1] = nx[n1] - # btd2[n3][n2][n1] = vector.scaleVector(nd1[n1], -1) - # a1, a2, a3 = local_orthogonal_unit_vectors(nx[n1], self._axes[2]) - # btd1[n3z][n2][n1] = a1 # initialise - # btd3[n3z][n2][n1] = a3 + if constant_index == 1: + elementsCount = [self._elementsCount[2], self._elementsCount[0]] + elif constant_index == 2: + elementsCount = [self._elementsCount[1], self._elementsCount[2]] + elif constant_index == 3: + elementsCount = [self._elementsCount[1], self._elementsCount[0]] + + btd = {1: btd1, 2: btd2, 3: btd3} + + tx = [] + td = [] + for se in range(2): + for ni in range(elementsCount[se] + 1): + if constant_index == 1: + ids = [ni, 0, nc] if se == 0 else [n3z, ni, nc] + elif constant_index == 2: + ids = [n3z, nc, ni] if se == 0 else [elementsCount[se] - ni, nc, n1z] + elif constant_index == 3: + ids = [nc, 0, ni] if se == 0 else [nc, ni, n1z] + + if ni < len(dStart[se]): + if dStart[se][ni]: + tx.append(btx[ids[0]][ids[1]][ids[2]]) + if dStart[0][ni] > 0: + td.append(btd[abs(dStart[se][ni])][ids[0]][ids[1]][ids[2]]) + else: + td.append(vector.scaleVector(btd[abs(dStart[se][ni])][ids[0]][ids[1]][ids[2]], -1)) + elif ni > elementsCount[se] - len(dEnd[se]): + nie = ni - elementsCount[se] + len(dEnd[se]) - 1 + if dEnd[se][nie]: + tx.append(btx[ids[0]][ids[1]][ids[2]]) + if dEnd[se][nie] > 0: + td.append(btd[abs(dEnd[se][nie])][ids[0]][ids[1]][ids[2]]) + else: + td.append(vector.scaleVector(btd[abs(dEnd[se][nie])][ids[0]][ids[1]][ids[2]], -1)) + else: + tx.append(btx[ids[0]][ids[1]][ids[2]]) + if dBetween[se][0] > 0: + td.append(btd[abs(dBetween[se][0])][ids[0]][ids[1]][ids[2]]) + else: + td.append(vector.scaleVector(btd[abs(dBetween[se][0])][ids[0]][ids[1]][ids[2]], -1)) + + td = smoothCubicHermiteDerivativesLine(tx, td, fixStartDirection=True, fixEndDirection=True) + + nit = 0 + for se in range(2): + for ni in range(elementsCount[se] + 1): + if constant_index == 1: + ids = [ni, 0, nc] if se == 0 else [n3z, ni, nc] + elif constant_index == 2: + ids = [n3z, nc, ni] if se == 0 else [elementsCount[se] - ni, nc, n1z] + elif constant_index == 3: + ids = [nc, 0, ni] if se == 0 else [nc, ni, n1z] + + if ni < len(dStart[se]): + if dStart[se][ni]: + if dStart[0][ni] > 0: + btd[abs(dStart[se][ni])][ids[0]][ids[1]][ids[2]] = td[nit] + else: + btd[abs(dStart[se][ni])][ids[0]][ids[1]][ids[2]] = vector.scaleVector(td[nit], -1) + nit += 1 + elif ni > elementsCount[se] - len(dEnd[se]): + nie = ni - elementsCount[se] + len(dEnd[se]) - 1 + if dEnd[se][nie]: + if dEnd[se][nie] > 0: + btd[abs(dEnd[se][nie])][ids[0]][ids[1]][ids[2]] = td[nit] + else: + btd[abs(dEnd[se][nie])][ids[0]][ids[1]][ids[2]] = vector.scaleVector(td[nit], -1) + nit += 1 + else: + if dBetween[se][0] > 0: + btd[abs(dBetween[se][0])][ids[0]][ids[1]][ids[2]] = td[nit] + else: + btd[abs(dBetween[se][0])][ids[0]][ids[1]][ids[2]] = vector.scaleVector(td[nit], -1) + nit += 1 def fixD2DerivativesOnTheEllipses(self): """ @@ -721,14 +627,14 @@ def calculate_arc_length(x1, x2): return radius * angle -def sample_curves_sphere(x1, x2, elementsOut): +def sample_curves_on_sphere(x1, x2, elementsOut): """ :param x1, x2: points coordinates. :param elementsOut: :return: """ - deltax = vector.addVectors(x1, x2, -1, 1) + deltax = vector.addVectors([x1, x2], [-1, 1]) normal = vector.crossproduct3(x1, deltax) angle = vector.angleBetweenVectors(x1, x2) anglePerElement = angle/elementsOut @@ -766,3 +672,46 @@ def cartesian_to_spherical(x): return r, theta, phi +def local_to_global_coordinates(local_x, local_axes, local_origin=None): + """ + Get global coordinates of a point with local coordinates x = [x1, x2, x3] and axes of local coordinate system. + :param local_x: Coordinates in local coordinates system as a list of 3 components. + :param local_origin: Origin of local coordinates system specified as a list of 3 components wrt global coordinates system. + :param local_axes: Axes of local coordinates system, specified as a list of list 3X3 with respect to global coordinates system. + :return: Global coordinate system. + """ + if local_origin is None: + local_origin = [0.0, 0.0, 0.0] + return vector.addVectors([vector.addVectors(local_axes, local_x), local_origin]) + + +def intersection_of_two_great_circles_on_sphere(p1, q1, p2, q2): + """ + Find the intersection between arcs P1Q1 and P2Q2 on sphere. + :param p1, q1, p2, q2: arcs extremities coordinates. + :return: Point Sx, intersection between the arcs. + """ + normal_to_plane_OP1Q1 = vector.crossproduct3(p1, q1) + normal_to_plane_OP2Q2 = vector.crossproduct3(p2, q2) + + planes_intersection_vector = vector.crossproduct3(normal_to_plane_OP1Q1, normal_to_plane_OP2Q2) + if vector.magnitude(planes_intersection_vector) == 0: + sx = None + else: + sx = vector.setMagnitude(planes_intersection_vector, vector.magnitude(p1)) + p1q1_angle = vector.angleBetweenVectors(p1, q1) + p1s_angle = vector.angleBetweenVectors(p1, sx) + p2s_angle = vector.angleBetweenVectors(p2, sx) + if p1s_angle > p1q1_angle or p2s_angle > p1q1_angle: + sx = vector.scaleVector(sx, -1) + + return sx + + +def point_projection_on_sphere(p1, radius): + """ + Find closest point to p1 on the sphere. + :param p1: point. + :return: + """ + return vector.setMagnitude(p1, radius) From c90d7956c63c72c68680b95ab4435f13579e2def Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Thu, 23 Sep 2021 11:55:10 +1200 Subject: [PATCH 18/37] Fix remapping issue and not used scale factors problem. --- src/scaffoldmaker/utils/shieldmesh.py | 224 ++------------------------ 1 file changed, 10 insertions(+), 214 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 1a557d15..8bfd61d7 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -85,217 +85,6 @@ def __init__(self, elementsCountAcross, elementsCountRim, self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] - def getQuadruplePoint2(self): - """ - - :return: - """ - n1z = self.elementsCountAcross[1] - n1y = n1z - 1 - n3z = self.elementsCountAcross[2] - n3y = n3z - 1 - n2z = self.elementsCountAcross[0] - - if self.elementsCountAcross[2] == min(self.elementsCountAcross): - n3r0, n2r0, n1r0 = 0, 1, n1y - n3r, n2r, n1r = 0, 0, n1z - elif self.elementsCountAcross[1] == min(self.elementsCountAcross): - n3r0, n2r0, n1r0 = n3y, 1, 0 - n3r, n2r, n1r = n3z, 0, 0 - else: - n3r0, n2r0, n1r0 = n3y, n2z, n1y - n3r, n2r, n1r = n3z, n2z, n1z - - ts = vector.magnitude(vector.addVectors([self.px[n3r0][n2r0][n1r0], self.px[n3r][n2r][n1r]], [1, -1])) - ra = vector.magnitude(self.px[n3z][0][n1z]) - x = vector.scaleVector(self.px[n3z][0][n1z], (1 - ts/ra)) - self.px[n3y][1][n1y] = x - n2r = 0 - self.pd1[n3y][1][n1y] = [-(self.px[n3y + 1][n2r][n1y + 1][0] - self.px[n3y][1][n1y][0]), 0.0, 0.0] - self.pd2[n3y][1][n1y] = [0.0, 0.0, (self.px[n3y + 1][n2r][n1y + 1][2] - self.px[n3y][1][n1y][2])] - self.pd3[n3y][1][n1y] = [0.0, (self.px[n3y + 1][n2r][n1y + 1][1] - self.px[n3y][1][n1y][1]), 0.0] - - - - # curve 1 - tx, td1 = sampleCubicHermiteCurves([self.px[n3z-1][1][n1y], self.px[n3z-1][n2z][n1y]], - [self.pd1[0][1][n1y], self.pd1[0][n2z][n1y]], self.elementsCountAcross[0] - 1)[:2] - - for n2 in range(2, self.elementsCountAcross[0]): - self.px[n3z-1][n2][n1y] = tx[n2-1] - self.pd1[n3z-1][n2][n1y] = td1[n2-1] - self.pd2[n3z-1][n2][n1y] = [0.0, 0.0, (self.px[n3z][n2][n1z][2] - self.px[n3z-1][n2][n1y][2])] - self.pd3[n3z-1][n2][n1y] = [0.0, (self.px[n3z][n2][n1z][1] - self.px[n3z-1][n2][n1y][1]), 0.0] - - - # curve 2 and parallel curves TODO change all [1] to n3y. - for n2 in range(1, self.elementsCountAcross[0]): - tx, td3 = sampleCubicHermiteCurves([self.px[n3y][n2][0], self.px[n3y][n2][n1y]], - [self.pd3[0][n2][0], self.pd3[0][n2][n1y]], self.elementsCountAcross[1] - 1)[:2] - - for n1 in range(1, self.elementsCountAcross[1] - 1): - self.px[n3y][n2][n1] = tx[n1] - self.pd3[n3y][n2][n1] = td3[n1] - - for n2 in range(1, self.elementsCountAcross[0]): - for n1 in range(1, self.elementsCountAcross[1] - 1): - if n2 == 1: - self.pd1[n3y][n2][n1] = [self.px[n3y][1][n1][0] - self.px[n3z][0][n1][0], 0.0, 0.0] - self.pd2[n3y][n2][n1] = [0.0, 0.0, -self.px[n3y][1][n1][2] + self.px[n3z][0][n1][2]] - else: - self.pd1[n3y][n2][n1] = vector.addVectors([self.px[n3y][n2][n1], self.px[n3y][n2+1][n1]], [-1, 1]) - self.pd2[n3y][n2][n1] = vector.addVectors([self.px[n3y][n2][n1], self.px[0][n2][n1]], [1, -1]) - - - - - # sample along curve0_3 - for n2 in range(1, self.elementsCountAcross[0]): - for n1 in range(1, self.elementsCountAcross[1]): - tx, td2 = sampleCubicHermiteCurves([self.px[0][n2][n1], self.px[n3y][n2][n1]], - [self.pd2[0][n2][0], self.pd2[n3y][n2][0]], self.elementsCountAcross[2]-1)[:2] - - for n3 in range(1, self.elementsCountAcross[2] - 1): - self.px[n3][n2][n1] = tx[n3] - self.pd2[n3][n2][n1] = td2[n3] - - for n3 in range(1, self.elementsCountAcross[2] - 1): - for n2 in range(1, self.elementsCountAcross[0]): - for n1 in range(1, self.elementsCountAcross[1]): - if n2 == 1 and n1 == n1y: - self.pd1[n3][n2][n1] = [self.px[n3][n2][n1][0] - self.px[n3][n2-1][n1+1][0], 0.0, 0.0] - self.pd3[n3][n2][n1] = [0.0, self.px[n3][n2-1][n1+1][1] - self.px[n3][n2][n1][1], 0.0] - else: - self.pd1[n3][n2][n1] = vector.addVectors([self.px[n3][n2+1][n1], self.px[n3][n2][n1]], [1, -1]) - self.pd3[n3][n2][n1] = vector.addVectors([self.px[n3][n2][n1+1], self.px[n3][n2][n1]], [1, -1]) - - - # smooth d1 in regular 1 - if self.elementsCountAcross[0] >= 3: - for n3 in range(1, self.elementsCountAcross[2]): - for n1 in range(1, self.elementsCountAcross[1]): - tx = [] - td1 = [] - for n2 in range(1, self.elementsCountAcross[0]+1): - tx.append(self.px[n3][n2][n1]) - td1.append(self.pd1[n3][n2][n1]) - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) - for n2 in range(1, self.elementsCountAcross[0]+1): - self.pd1[n3][n2][n1] = td1[n2-1] - else: - for n3 in range(1, self.elementsCountAcross[2]): - for n1 in range(1, self.elementsCountAcross[1]): - self.pd1[n3][1][n1] = vector.addVectors([self.px[n3][2][n1], self.px[n3][1][n1]], [1, -1]) - self.pd1[n3][2][n1] = vector.setMagnitude(self.pd1[n3][2][n1], vector.magnitude(self.pd1[n3][1][n1])) - - # smooth d3 in regular - if self.elementsCountAcross[1] >= 3: - for n3 in range(1, self.elementsCountAcross[2]): - for n2 in range(1, self.elementsCountAcross[0]): - tx = [] - td3 = [] - for n1 in range(self.elementsCountAcross[1]): - tx.append(self.px[n3][n2][n1]) - td3.append(self.pd3[n3][n2][n1]) - - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True) - - for n1 in range(self.elementsCountAcross[1]): - self.pd3[n3][n2][n1] = td3[n1] - else: - for n3 in range(1, self.elementsCountAcross[2]): - for n2 in range(1, self.elementsCountAcross[0]): - self.pd3[n3][n2][1] = vector.addVectors([self.px[n3][n2][1], self.px[n3][n2][0]], [1, -1]) - self.pd3[n3][n2][0] = vector.setMagnitude(self.pd3[n3][n2][0], vector.magnitude(self.pd3[n3][n2][1])) - - - # regular curves d2 - for n2 in range(1, self.elementsCountAcross[0]): - for n1 in range(1, self.elementsCountAcross[1]): - if self.elementsCountAcross[2] >= 3: - tx = [] - td2 = [] - for n3 in range(self.elementsCountAcross[2]): - tx.append(self.px[n3][n2][n1]) - td2.append(self.pd2[n3][n2][n1]) - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True) - for n3 in range(self.elementsCountAcross[2]): - self.pd2[n3][n2][n1] = td2[n3] - else: - self.pd2[1][n2][n1] = vector.addVectors([self.px[1][n2][n1], self.px[0][n2][n1]], [1, -1]) - self.pd2[0][n2][n1] = vector.setMagnitude(self.pd2[0][n2][n1], vector.magnitude(self.pd2[1][n2][n1])) - - - - - # smooth d3 on the surface of regular ones. - # for n2 in range(self.elementsCountAcross[0]): - # for n1 in range(1, self.elementsCountAcross[1]+1): - # if self.px[n3z][n2][n1]: - # if n2 == 0: - # if n1 == n1z: - # xin = self.px[n3z-1][n2+1][n1-1] - # else: - # xin = self.px[n3z - 1][n2 + 1][n1] - # else: - # xin = self.px[n3z - 1][n2][n1 - 1] - # - # self.pd3[n3z][n2][n1] = vector.setMagnitude(self.pd3[n3z][n2][n1], mag) - - - - - - - def getQuadruplePoint(self): - """ - - :return: - """ - n1a = 1 - n2a = 1 - n3a = 1 - # n2b = self.elementsCountAcross[0] - for n2 in range(self.elementsCountAcross[0]): - if n2 > 0: - x = [self.px[0][n2][n1a][0], self.px[0][n2][n1a][1],self.px[n3a][n2][0][2]] - self.px[n3a][n2][n1a] = x - self.pd1[n3a][n2][n1a] = self.pd1[0][n2][n1a] - self.pd2[n3a][n2][n1a] = self.pd2[0][n2][n1a] - self.pd3[n3a][n2][n1a] = self.pd3[0][n2][n1a] - # self.pd1[n3a][n2a][n1a] = [(self.px[n3a][n2a+1][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] - # self.pd2[n3a][n2a][n1a] = [-(self.px[0][n2a][n1a][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] - # self.pd3[n3a][n2a][n1a] = [-(self.px[n3a][n2a][0][c] - self.px[n3a][n2a][n1a][c]) for c in range(3)] - - def smoothDerivativesToSurfaceQuadruple(self, n3, fixAllDirections=False): - ''' - Smooth derivatives leading to quadruple point where 3 hex elements merge. - :param n3: Index of through-wall coordinates to use. - ''' - n1b = self.elementsCountAcross[1] - (self.elementsCountRim + 1) - # n1z = self.elementsCountAcross[] - self.elementsCountRim - # n1y = n1z - 1 - # m1a = self.elementsCountAcross - self.elementsCountRim - # m1b = m1a - 1 - n2a = self.elementsCountRim - n2b = n2a + 1 - n2c = n2a + 2 - - tx = [] - td3 = [] - for n2 in range(n2c): - if n2 < n2b: - tx.append(self.px[n3][n2][n1b + 1]) - td3.append([-self.pd3[n3][n2][n1b+1][c] for c in range(3)]) - else: - tx.append(self.px[n3-1][n2][n1b]) - td3.append([(self.pd1[n3-1][n2b][n1b][c] - self.pd2[n3-1][n2b][n1b][c] - self.pd3[n3-1][n2b][n1b][c]) for c in range(3)] ) - - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - - for n2 in range(n2b): - self.pd3[n3][n2][n1b+1] = [-td3[n2][c] for c in range(3)] - def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlane=None): """ Create shield nodes from coordinates. @@ -513,8 +302,9 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes nids[6] = self.nodeId[e3+2][e2r][e1+1] nids[7] = self.nodeId[e3+2][e2+1][e1+1] + # if e2 == e2b or e2 == e2z: + eft1 = tricubichermite.createEftNoCrossDerivatives() if e2 == e2b or e2 == e2z: - eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] @@ -537,9 +327,15 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_DOWN) if e3y == 0: + self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_RIGHT) self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) else: + self.remap_eft_node_value_label(eft1, [5], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_23_DOWN) + else: + self.remap_eft_node_value_label(eft1, [3, 4], self.TRIPLE_CURVE0_1_DOWN) + self.remap_eft_node_value_label(eft1, [5, 6], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_DOWN) elif element_quadruple_up_left: if e2 == 1: @@ -593,8 +389,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_UP) else: self.remap_eft_node_value_label(eft1, [3, 4], self.SURFACE_REGULAR_UP) - self.remap_eft_node_value_label(eft1, [5, 6], self.TRIPLE_CURVE0_2_UP) - self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [5, 6], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_UP) elif element_quadruple_up: if e2 == e2b: From 95a54753bc0182d11426ea9b7762eaf61b6f0f88 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Thu, 23 Sep 2021 12:00:38 +1200 Subject: [PATCH 19/37] Tidy up the code. Add a function to find index and node parameters of the triple curves --- src/scaffoldmaker/utils/spheremesh.py | 290 +++++++++++++++++++++++--- 1 file changed, 260 insertions(+), 30 deletions(-) diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 0065c6ec..9a6e2930 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -231,10 +231,8 @@ def createAdditionalPointsForIncreasingElementsCount(self): self.calculate_surface_quadruple_point() self.sample_triple_curves_on_sphere() self.sample_regular_curves_on_sphere() - self._shield3D.getQuadruplePoint2() - n3z = self._elementsCount[2] - self._shield3D.smoothDerivativesToSurfaceQuadruple(n3z) - self.smoothDerivativesToSurface() + self.create_interior_nodes() + self.smooth_derivatives_to_surface() def calculate_surface_quadruple_point(self): """ @@ -274,12 +272,11 @@ def calculate_surface_quadruple_point(self): x = local_to_global_coordinates(local_x, self._axes, self._centre) a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) - n1 = n1z - n2 = 0 - btx[n3z][n2][n1] = x - btd1[n3z][n2][n1] = a1 # initialise - btd2[n3z][n2][n1] = a2 # initialise - btd3[n3z][n2][n1] = a3 + n3r, n2r, n1r = self.get_triple_curves_end_node_parameters(1, index_output=True) + btx[n3r][n2r][n1r] = x + btd1[n3r][n2r][n1r] = a1 # initialise + btd2[n3r][n2r][n1r] = a2 # initialise + btd3[n3r][n2r][n1r] = a3 def sample_triple_curves_on_sphere(self): """ @@ -291,13 +288,19 @@ def sample_triple_curves_on_sphere(self): n3z = self._elementsCount[2] # sample on curve 1 of the triple curves and smooth the end derivatives. - self.sample_curves_between_two_nodes_on_sphere([n3z, 0, n1z], [n3z, n2z, n1z], self._elementsCount[0] - 1, + n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, index_output=True) + n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, cx=1, index_output=True) + self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[0] - 1, [1, None], [1], [-2]) # curve 2 - self.sample_curves_between_two_nodes_on_sphere([n3z, 0, 0], [n3z, 0, n1z], self._elementsCount[1] - 1, + n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, cx=2, index_output=True) + n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, index_output=True) + self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[1] - 1, [2], [-2], [None, -2]) # curve 3. - self.sample_curves_between_two_nodes_on_sphere([0, 0, n1z], [n3z, 0, n1z], self._elementsCount[2] - 1, + n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, cx=3, index_output=True) + n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, index_output=True) + self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[2] - 1, [2], [2], [None, None]) def sample_regular_curves_on_sphere(self): @@ -337,6 +340,16 @@ def sample_regular_curves_on_sphere(self): for n3 in range(1, self._elementsCount[2] - 1): self.smooth_derivatives_regular_surface_curve(3, n3, [[2], [None, None]], [[1], [1]], [[None, 1], [-2]]) + def create_interior_nodes(self): + """ + + :return: + """ + + self.calculate_interior_quadruple_point() + self.sample_interior_curves() + self.smooth_regular_interior_curves() + def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStart, dbetween, dEnd): """ samples curves on the sphere surface between two points given by their indexes. @@ -352,13 +365,13 @@ def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStar # Find what index is constant if id1[0] != id2[0]: - constant_index = 3 + varying_index = 3 elementsCount = self._elementsCount[2] elif id1[1] != id2[1]: - constant_index = 2 + varying_index = 2 elementsCount = self._elementsCount[0] elif id1[2] != id2[2]: - constant_index = 1 + varying_index = 1 elementsCount = self._elementsCount[1] else: @@ -371,7 +384,7 @@ def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStar nit = 0 for ni in range(elementsCount + 1): - idi[3 - constant_index] = ni + idi[3 - varying_index] = ni if ni < len(dStart): if dStart[ni]: @@ -491,30 +504,247 @@ def smooth_derivatives_regular_surface_curve(self, constant_index, nc, dStart, d btd[abs(dBetween[se][0])][ids[0]][ids[1]][ids[2]] = vector.scaleVector(td[nit], -1) nit += 1 - def fixD2DerivativesOnTheEllipses(self): + def calculate_interior_quadruple_point(self): """ :return: """ - n3a = 0 - n3b = self._elementsCount[2] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2a = (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) - n2b = self._elementsCount[0] - n1a = 0 - n1b = self._elementsCount[1] - (self._elementsCountAcrossShell + self._elementsCountAcrossTransition) + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + n1z = self._elementsCount[1] + n1y = n1z - 1 + n3z = self._elementsCount[2] + n3y = n3z - 1 + n2z = self._elementsCount[0] + + if self._elementsCount[2] == min(self._elementsCount): + cx = 3 + elif self._elementsCount[1] == min(self._elementsCount): + cx = 2 + else: + cx = 1 + n3r0, n2r0, n1r0 = self.get_triple_curves_end_node_parameters(0, cx=cx, index_output=True) + n3r, n2r, n1r = self.get_triple_curves_end_node_parameters(1, cx=cx, index_output=True) + + ts = vector.magnitude(vector.addVectors([btx[n3r0][n2r0][n1r0], btx[n3r][n2r][n1r]], [1, -1])) + ra = vector.magnitude(btx[n3z][0][n1z]) + x = vector.scaleVector(btx[n3z][0][n1z], (1 - ts/ra)) + n3r0, n2r0, n1r0 = self.get_triple_curves_end_node_parameters(0, index_output=True) + n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, index_output=True) + btx[n3r0][n2r0][n1r0] = x + btd1[n3r0][n2r0][n1r0] = [-(btx[n3r1][n2r1][n1r1][0] - btx[n3r0][n2r0][n1r0][0]), 0.0, 0.0] + btd2[n3r0][n2r0][n1r0] = [0.0, 0.0, (btx[n3r1][n2r1][n1r1][2] - btx[n3r0][n2r0][n1r0][2])] + btd3[n3r0][n2r0][n1r0] = [0.0, (btx[n3r1][n2r1][n1r1][1] - btx[n3r0][n2r0][n1r0][1]), 0.0] + + def sample_interior_curves(self): + """ + + :return: + """ btx = self._shield3D.px btd1 = self._shield3D.pd1 btd2 = self._shield3D.pd2 btd3 = self._shield3D.pd3 - n1 = self._elementsCount[1] - 1 - for n2 in range(self._elementsCount[0] + 1): - if n2a <= n2 < self._elementsCount[0]: - btd3[n3b][n2][n1a] = [btx[n3b][n2][n1b][c] - btx[n3b][n2][n1a][c] for c in range(3)] - btd2[0][n2][n1] = [btx[1][n2][n1][c] - btx[0][n2][n1][c] for c in range(3)] + n1z = self._elementsCount[1] + n1y = n1z - 1 + n3z = self._elementsCount[2] + n3y = n3z - 1 + n2z = self._elementsCount[0] + + # btd = {1: btd1, 2: btd2, 3: btd3} + + + # + # n3s = [[n3y, n3y, 0, 0], [n3y, n3y, 0, 0], [0, n3y, 0, n3y]] + # n2s = [[1, 1, 1, 1], [1, n2z, 1, n2z], [1, 1, 1, 1]] + # n1s = [[0, n1y, 0, n1y], [n1y, n1y, n1y, n1y], [n1y, n1y, 0, 0]] + # + # n3x2 = n3y + # n3d1 = 0 + # n2x1 = 1 + # n2d1 = 1 + # n1x2 = n1y + # for nic in range(3): + # n3x1 = 0 if nic == 2 else n3y + # n3d2 = n3y if nic == 2 else 0 + # n2x2 = n2z if nic == 1 else 1 + # n2d2 = n2z if nic == 1 else 1 + # n1x1 = 0 if nic == 1 else n1y + # n1d1 = n1y if nic == 1 else 0 + # n1d2 = 0 if nic == 2 else n1y + # + # tx, td = sampleCubicHermiteCurves([btx[n3x1][n2x1][n1x1], btx[n3x2][n2x2][n1x2]], + # [btd[nic][n3d1][n2d1][n1d1], btd[nic][n3d2][n2d2][n1d2]], self._elementsCount[nic] - 1)[:2] + # + # for ni in range(ni0, self._elementsCount[nic] - 1 + ni0) + + tx, td1 = sampleCubicHermiteCurves([btx[n3y][1][n1y], btx[n3y][n2z][n1y]], + [btd1[0][1][n1y], btd1[0][n2z][n1y]], self._elementsCount[0] - 1)[:2] + + for n2 in range(2, self._elementsCount[0]): + btx[n3y][n2][n1y] = tx[n2-1] + btd1[n3y][n2][n1y] = td1[n2-1] + btd2[n3y][n2][n1y] = [0.0, 0.0, (btx[n3z][n2][n1z][2] - btx[n3y][n2][n1y][2])] + btd3[n3y][n2][n1y] = [0.0, (btx[n3z][n2][n1z][1] - btx[n3y][n2][n1y][1]), 0.0] + + # curve 2 and parallel curves TODO change all [1] to n3y. + for n2 in range(1, self._elementsCount[0]): + tx, td3 = sampleCubicHermiteCurves([btx[n3y][n2][0], btx[n3y][n2][n1y]], + [btd3[0][n2][0], btd3[0][n2][n1y]], self._elementsCount[1] - 1)[:2] + + for n1 in range(1, self._elementsCount[1] - 1): + btx[n3y][n2][n1] = tx[n1] + btd3[n3y][n2][n1] = td3[n1] + + for n2 in range(1, self._elementsCount[0]): + for n1 in range(1, self._elementsCount[1] - 1): + if n2 == 1: + btd1[n3y][n2][n1] = [btx[n3y][1][n1][0] - btx[n3z][0][n1][0], 0.0, 0.0] + btd2[n3y][n2][n1] = [0.0, 0.0, -btx[n3y][1][n1][2] + btx[n3z][0][n1][2]] + else: + btd1[n3y][n2][n1] = vector.addVectors([btx[n3y][n2][n1], btx[n3y][n2+1][n1]], [-1, 1]) + btd2[n3y][n2][n1] = vector.addVectors([btx[n3y][n2][n1], btx[0][n2][n1]], [1, -1]) + + + + + # sample along curve0_3 + for n2 in range(1, self._elementsCount[0]): + for n1 in range(1, self._elementsCount[1]): + tx, td2 = sampleCubicHermiteCurves([btx[0][n2][n1], btx[n3y][n2][n1]], + [btd2[0][n2][0], btd2[n3y][n2][0]], self._elementsCount[2]-1)[:2] + + for n3 in range(1, self._elementsCount[2] - 1): + btx[n3][n2][n1] = tx[n3] + btd2[n3][n2][n1] = td2[n3] + + for n3 in range(1, self._elementsCount[2] - 1): + for n2 in range(1, self._elementsCount[0]): + for n1 in range(1, self._elementsCount[1]): + if n2 == 1 and n1 == n1y: + btd1[n3][n2][n1] = [btx[n3][n2][n1][0] - btx[n3][n2-1][n1+1][0], 0.0, 0.0] + btd3[n3][n2][n1] = [0.0, btx[n3][n2-1][n1+1][1] - btx[n3][n2][n1][1], 0.0] + else: + btd1[n3][n2][n1] = vector.addVectors([btx[n3][n2+1][n1], btx[n3][n2][n1]], [1, -1]) + btd3[n3][n2][n1] = vector.addVectors([btx[n3][n2][n1+1], btx[n3][n2][n1]], [1, -1]) + + def smooth_regular_interior_curves(self): + """ + + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + n1z = self._elementsCount[1] + n1y = n1z - 1 + n3z = self._elementsCount[2] + n3y = n3z - 1 + n2z = self._elementsCount[0] + + # smooth d1 in regular 1 + if self._elementsCount[0] >= 3: + for n3 in range(1, self._elementsCount[2]): + for n1 in range(1, self._elementsCount[1]): + tx = [] + td1 = [] + for n2 in range(1, self._elementsCount[0]+1): + tx.append(btx[n3][n2][n1]) + td1.append(btd1[n3][n2][n1]) + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixEndDirection=True) + for n2 in range(1, self._elementsCount[0]+1): + btd1[n3][n2][n1] = td1[n2-1] + else: + for n3 in range(1, self._elementsCount[2]): + for n1 in range(1, self._elementsCount[1]): + btd1[n3][1][n1] = vector.addVectors([btx[n3][2][n1], btx[n3][1][n1]], [1, -1]) + btd1[n3][2][n1] = vector.setMagnitude(btd1[n3][2][n1], vector.magnitude(btd1[n3][1][n1])) + + # smooth d3 in regular + if self._elementsCount[1] >= 3: + for n3 in range(1, self._elementsCount[2]): + for n2 in range(1, self._elementsCount[0]): + tx = [] + td3 = [] + for n1 in range(self._elementsCount[1]): + tx.append(btx[n3][n2][n1]) + td3.append(btd3[n3][n2][n1]) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True) + + for n1 in range(self._elementsCount[1]): + btd3[n3][n2][n1] = td3[n1] + else: + for n3 in range(1, self._elementsCount[2]): + for n2 in range(1, self._elementsCount[0]): + btd3[n3][n2][1] = vector.addVectors([btx[n3][n2][1], btx[n3][n2][0]], [1, -1]) + btd3[n3][n2][0] = vector.setMagnitude(btd3[n3][n2][0], vector.magnitude(btd3[n3][n2][1])) + + # regular curves d2 + for n2 in range(1, self._elementsCount[0]): + for n1 in range(1, self._elementsCount[1]): + if self._elementsCount[2] >= 3: + tx = [] + td2 = [] + for n3 in range(self._elementsCount[2]): + tx.append(btx[n3][n2][n1]) + td2.append(btd2[n3][n2][n1]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixStartDirection=True) + for n3 in range(self._elementsCount[2]): + btd2[n3][n2][n1] = td2[n3] + else: + btd2[1][n2][n1] = vector.addVectors([btx[1][n2][n1], btx[0][n2][n1]], [1, -1]) + btd2[0][n2][n1] = vector.setMagnitude(btd2[0][n2][n1], vector.magnitude(btd2[1][n2][n1])) + + def get_triple_curves_end_node_parameters(self, rx, cx=None, index_output=False): + """ + :param cx: + :param rx: + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + n3z = self._elementsCount[2] + n2z = self._elementsCount[0] + n1z = self._elementsCount[1] + n3y = n3z - 1 + n1y = n1z - 1 + + if not cx: + n3r = n3y + rx + n2r = 1 - rx + n1r = n1y + rx + else: + if cx == 1: + n3r = n3y + rx + n2r = n2z + n1r = n1y + rx + elif cx == 2: + n3r = n3y + rx + n2r = 1 - rx + n1r = 0 + elif cx == 3: + n3r = 0 + n2r = 1 - rx + n1r = n1y + rx + else: + raise ValueError("curve index must be 1,2 or 3.") + + if index_output: + return n3r, n2r, n1r + else: + return btx[n3r][n2r][n1r], btd1[n3r][n2r][n1r], btd2[n3r][n2r][n1r], btd3[n3r][n2r][n1r] - def smoothDerivativesToSurface(self): + def smooth_derivatives_to_surface(self): ''' Smooth derivatives leading to quadruple point where 3 hex elements merge. :param n3: Index of through-wall coordinates to use. From 60295c3fc20b07d865b2d477bcac3843ab9b76af Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 29 Sep 2021 11:31:42 +1300 Subject: [PATCH 20/37] Make derivatives in the box configurable. --- .../meshtypes/meshtype_3d_solidsphere2.py | 43 +- src/scaffoldmaker/utils/shieldmesh.py | 851 ++++++++++++------ src/scaffoldmaker/utils/spheremesh.py | 18 +- 3 files changed, 637 insertions(+), 275 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 53df5184..547862f5 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -61,6 +61,8 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements across shell': 0, 'Number of elements across transition': 1, # 'Number of elements along': 1, + 'Derivatives configuration1': True, + 'Derivatives configuration2': False, 'Shell element thickness proportion': 1.0, 'Octant': True, 'Hemisphere': False, @@ -81,6 +83,8 @@ def getOrderedOptionNames(): 'Number of elements across shell', 'Number of elements across transition', # 'Number of elements along', + 'Derivatives configuration1', + 'Derivatives configuration2', 'Shell element thickness proportion', 'Octant', 'Hemisphere', @@ -175,6 +179,12 @@ def generateBaseMesh(region, options): # elementsCountAlong = options['Number of elements along'] shellProportion = options['Shell element thickness proportion'] useCrossDerivatives = options['Use cross derivatives'] + first = options['Derivatives configuration1'] + second = options['Derivatives configuration2'] + if first: + boxMapping = [1, 3, 2] + if second and not first: + boxMapping = [-1, 2, 3] fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) @@ -189,7 +199,7 @@ def generateBaseMesh(region, options): sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) if (hemisphere or full) and not octant: axis1 = [0.0, -1.0, 0.0] @@ -197,27 +207,30 @@ def generateBaseMesh(region, options): axis3 = [0.0, 0.0, 1.0] axes = [axis1, axis2, axis3] elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] + boxMapping = [3, -1, 2] sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) axis1 = [-1.0, 0.0, 0.0] axis2 = [0.0, -1.0, 0.0] axis3 = [0.0, 0.0, 1.0] axes = [axis1, axis2, axis3] elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + boxMapping = [-1, -3, 2] sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) axis1 = [0.0, 1.0, 0.0] axis2 = [-1.0, 0.0, 0.0] axis3 = [0.0, 0.0, 1.0] axes = [axis1, axis2, axis3] elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] + boxMapping = [-3, 1, 2] sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) if full and not octant and not hemisphere: axis1 = [0.0, 1.0, 0.0] @@ -225,37 +238,40 @@ def generateBaseMesh(region, options): axis3 = [0.0, 0.0, -1.0] axes = [axis1, axis2, axis3] elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - - sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + boxMapping = [-3, -1, -2] + sphere5 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) axis2 = [0.0, -1.0, 0.0] axis1 = [1.0, 0.0, 0.0] axis3 = [0.0, 0.0, -1.0] axes = [axis1, axis2, axis3] elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + boxMapping = [1, -3, -2] + sphere6 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) axis2 = [-1.0, 0.0, 0.0] axis1 = [0.0, -1.0, 0.0] axis3 = [0.0, 0.0, -1.0] axes = [axis1, axis2, axis3] elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + boxMapping = [3, 1, -2] + sphere7 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) axis2 = [0.0, 1.0, 0.0] axis1 = [-1.0, 0.0, 0.0] axis3 = [0.0, 0.0, -1.0] axes = [axis1, axis2, axis3] elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + boxMapping = [-1, 3, -2] + sphere8 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) annotationGroup = [] return annotationGroup @@ -269,5 +285,4 @@ def refineMesh(cls, meshRefinement, options): """ assert isinstance(meshRefinement, MeshRefinement) refineElementsCountAcross = options['Refine number of elements across'] - # refineElementsCountAlong = options['Refine number of elements along'] meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcross, refineElementsCountAcross, refineElementsCountAcross) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 8bfd61d7..e3927213 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -37,7 +37,7 @@ class ShieldMesh3D: ''' def __init__(self, elementsCountAcross, elementsCountRim, - shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP): + shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP, boxMapping=None): """ 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the centre. The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a special node on the @@ -72,6 +72,7 @@ def __init__(self, elementsCountAcross, elementsCountRim, # elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim self._mode = shieldMode + self._boxMapping = boxMapping self.px = [ [] for _ in range(elementsCountAcross[2] + 1) ] self.pd1 = [ [] for _ in range(elementsCountAcross[2] + 1) ] @@ -85,6 +86,67 @@ def __init__(self, elementsCountAcross, elementsCountRim, self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] + def remap_derivatives(self, boxMapping, circleMapping=None, sphereMapping=None): + """ + It remaps the derivatives as indicated by squareMapping and circleMapping. Limited to SHIELD_RIM_DERIVATIVE_MODE_AROUND. + :param squareMapping: List[up, right]. Determines what derivatives should be in the up and right directions in the + square part. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. + The negative sign reverses the direction. e.g. [-3,2] means d3 is down and d2 is right. The third derivative + is determined by the other two. RH rule applied. Assumes [1,3] initially. + :param circleMapping: List[circumferential, radial]. Determines what derivatives should be used for + circumferential and radial directions around the circle. + [-1, 3] means d1 -> clockwise and around. d3 -> outward and radial. Assumes [1,3] initially. + :return: + """ + # [+3,-1, +2] or [back, right, up] -> default = [1,3,2] Now let's get it for [-1, 2, 3] which is natural. + self._boxMapping = boxMapping + + dct = {1: self.pd1, 2: self.pd2, 3: self.pd3} + perm = {(1, 2): -3, (2, 3): -1, (3, 1): -2, (3, 2): 1, (1, 3): 2, (2, 1): 3} + + # square = True + # tripleRow = [self.elementsCountRim + 1, self.elementsCountUpFull - (self.elementsCountRim + 1)] + # ellipseMapping = [boxMapping, circleMapping] + sphereMapping = [boxMapping] + for mapping in sphereMapping: + if mapping: + signs = [] + for c in mapping: + sign = 1 if c > 0 else -1 + signs.append(sign) + # derv = (abs(mapping[0]), abs(mapping[1])) + # sign = 1 if perm[derv] > 0 else -1 + # signs.append(signs[0] * signs[1] * sign) + dervMapping = (abs(mapping[0]), abs(mapping[1]), abs(mapping[2])) + # dervMapping = (derv[0], derv[1], abs(perm[derv])) + + temp1 = copy.deepcopy(self.pd3) + temp2 = copy.deepcopy(self.pd2) + for n3 in range(self.elementsCountAcross[2] + 1): + for n2 in range(self.elementsCountAcross[0] + 1): + for n1 in range(self.elementsCountAcross[1] + 1): + if self.px[n3][n2][n1]: + # is_on_square = ((self.px[n3][n2][0] and self.px[n3][0][n1]) or n2 in tripleRow) + # if (is_on_square and square) or (not is_on_square and not square): + if self.is_interior_regular_nodes(n3, n2, n1): + dct[dervMapping[0]][n3][n2][n1] = [signs[0] * c for c in self.pd1[n3][n2][n1]] + dct[dervMapping[1]][n3][n2][n1] = [signs[1] * c for c in temp1[n3][n2][n1]] + dct[dervMapping[2]][n3][n2][n1] = [signs[2] * c for c in temp2[n3][n2][n1]] + # square = False + + def is_interior_regular_nodes(self, n3, n2, n1): + """ + + :return: + """ + n3z = self.elementsCountAcross[2] + n1z = self.elementsCountAcross[1] + n2z = self.elementsCountAcross[0] + n3y = n3z - 1 + n1y = n1z - 1 + + return n3 <= n3y and n2 >= 1 and n1 <= n1y + def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlane=None): """ Create shield nodes from coordinates. @@ -103,6 +165,8 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) cache = fieldmodule.createFieldcache() #for n2 in range(self.elementsCountUp, -1, -1): @@ -179,6 +243,131 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan SURFACE_REGULAR_UP = 42 REGULAR = 43 + def local_node_mapping(self): + """ + + :return: + """ + # How to determine new curve labels? from mapping [c1, c3, c2] -> [3, -1, 2] neglect sign + # so c1_label = abs(self._boxMapping[0]), c2_label = abs(self._boxMapping[0]), c3_label = abs(self._boxMapping[0]). + # Note that generally, c1 is not any of d1, d2, d3 but its label is said to be d1, d2, d3 and it means the element axes or xi directions. + # and not nodal d1, d2, d3. So actually fromLabel or curveLabel is an element thing that for each node it is constructed differently. + + # now when we have remap(eft, ln, curveLabel, [(m1, [a1]), (m2, [a2]), (m3, [a3])]). Then this can be used for curve + # again if we find new ln, curvelabel and ms and as which describes the same curve again. + # so for a node, if we know mapping curveLabel = label[lm[c1]]. Note that we indirectly do this, i.e. first use + # a second derivative so the values of the derivatives don't get overwritten. + + # from nids orders, we should say if the curve direction is changed or not. e.g. if we want the nids follow the same + # order given by boxMapping then for [3, -1, 2] the sign of the c3 has changed to negative, so all the as should be multiplied by -1. + # for all the nodes and their curves that direction is negative. So if we are talking about changes applied to all interior nodes on the box, + # then this means for all of the such nodes, as for c3 should be multiplied by -1. Because nids are consistent, then we do this for all of the nodes not + # just the interior nodes. Note that nids orders and curves directions are applied for all the nodes and elements. + # Now label[lm[c1]] is gonna do this for all of the mappings. I need to store nid_order, so now here we have nid_order_signs = [1, 1, -1] + # i.e. we sf[a1*nid_order_sings[0]], ... + # Now, this was only the effect of changing nids. This is unneccessary and we could ignore this step and always use the same nids. + # However, because we want the second octant be consistent with the first octant, then element axes also should be consistent then we need + # to change the order of nodes to achieve that. the order of node is always the same as boxMapping. + # Note that if you want to see what order is used in an element, turn on element axes in scaffoldmaker. + # Now, if ms change as well, like here, [m1, m3, m2] -> [3, -1, 2] which means m1 = expressionLabel[1], where expressionLabel = {m1:d3, m3:d1, m2:d2} + # derivative_signs as well if derivative gets negative, for this case derivative_signs = {m1:1, m2:1, m3:-1}. Which then I multiply only a3 by -1. + # This mapping is done only for the nodes on the box, so for such nodes we have expressionLabel and a3X-1. + #[1, 3, 2] -> [-1, 2, 3] + + # Ok, now how to obtain nids from given boxMapping? + # + boxMapping_default = [1, 3, 2] + + signs = [] + xi_map = {'xi1': abs(self._boxMapping[0]), 'xi3': abs(self._boxMapping[1]), 'xi2': abs(self._boxMapping[2])} + for di in range(3): + sign = 1 if self._boxMapping[di]*boxMapping_default[di] > 0 else -1 + signs.append(sign) + xi_sign_change = [signs[0], signs[2], signs[1]] + + xi_node_map = {(0, 0, 0): 1, (1, 0, 0): 2, (0, 1, 0): 3, (1, 1, 0): 4, + (0, 0, 1): 5, (1, 0, 1): 6, (0, 1, 1): 7, (1, 1, 1): 8} + node_xi_map = {1: (0, 0, 0), 2: (1, 0, 0), 3: (0, 1, 0), 4: (1, 1, 0), + 5: (0, 0, 1), 6: (1, 0, 1), 7: (0, 1, 1), 8: (1, 1, 1)} + + lnm = {} + for ln in range(1, 9): + xi_l = [] + xi = [node_xi_map[ln][xi_map['xi1'] - 1], node_xi_map[ln][xi_map['xi2'] - 1], node_xi_map[ln][xi_map['xi3'] - 1]] + signs = [xi_sign_change[xi_map['xi1'] - 1], xi_sign_change[xi_map['xi2'] - 1], xi_sign_change[xi_map['xi3'] - 1]] + for i in range(3): + if signs[i] > 0: + xi_l.append(xi[i]) + else: + xi_l.append(1 - xi[i]) + lnm[ln] = xi_node_map[tuple(xi_l)] + + signs = [] + deriv_map = {'xi1': abs(self._boxMapping[0]), 'xi3': abs(self._boxMapping[1]), 'xi2': abs(self._boxMapping[2])} + for di in range(3): + sign = 1 if self._boxMapping[di]*boxMapping_default[di] > 0 else -1 + signs.append(sign) + deriv_sign_change = [signs[0], signs[2], signs[1]] + + self._xi_mapping = {1: xi_map['xi1'], 2: xi_map['xi2'], 3: xi_map['xi3']} + self._xi_signs = {1: xi_sign_change[0], 2: xi_sign_change[1], 3: xi_sign_change[2]} + self._deriv_mapping = {1: deriv_map['xi1'], 2: deriv_map['xi2'], 3: deriv_map['xi3']} + self._deriv_signs = {1: deriv_sign_change[0], 2: deriv_sign_change[1], 3: deriv_sign_change[2]} + self._local_node_mapping = lnm + + # nids_default = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3 + 1][e2][e1], self.nodeId[e3 + 1][e2 + 1][e1], + # self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3 + 1][e2][e1 + 1], self.nodeId[e3 + 1][e2 + 1][e1 + 1]] + # nids = [None] * 8 + # for i in range(1, 9): + # nids[lnm[i]-1] = (nids_default[i - 1]) + + + # lnm = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8} + # if self._boxMapping == [-1, 2, 3]: + # lnm = {1: 2, 2: 1, 3: 6, 4: 5, 5: 4, 6: 3, 7: 8, 8: 7} + # if self._boxMapping == [3, -1, 2]: + # lnm = {1: 2, 2: 6, 3: 4, 4: 8, 5: 1, 6: 5, 7: 3, 8: 7} + + # px_default = [self.px[e3][e2][e1], self.px[e3][e2 + 1][e1], self.px[e3 + 1][e2][e1], self.px[e3 + 1][e2 + 1][e1], + # self.px[e3][e2][e1 + 1], self.px[e3][e2 + 1][e1 + 1], self.px[e3 + 1][e2][e1 + 1], self.px[e3 + 1][e2 + 1][e1 + 1]] + # pd1_default = [self.pd1[e3][e2][e1], self.pd1[e3][e2 + 1][e1], self.pd1[e3 + 1][e2][e1], self.pd1[e3 + 1][e2 + 1][e1], + # self.pd1[e3][e2][e1 + 1], self.pd1[e3][e2 + 1][e1 + 1], self.pd1[e3 + 1][e2][e1 + 1], self.pd1[e3 + 1][e2 + 1][e1 + 1]] + # pd2_default = [self.pd2[e3][e2][e1], self.pd2[e3][e2 + 1][e1], self.pd2[e3 + 1][e2][e1], self.pd2[e3 + 1][e2 + 1][e1], + # self.pd2[e3][e2][e1 + 1], self.pd2[e3][e2 + 1][e1 + 1], self.pd2[e3 + 1][e2][e1 + 1], self.pd2[e3 + 1][e2 + 1][e1 + 1]] + # pd3_default = [self.pd3[e3][e2][e1], self.pd3[e3][e2 + 1][e1], self.pd3[e3 + 1][e2][e1], self.pd3[e3 + 1][e2 + 1][e1], + # self.pd3[e3][e2][e1 + 1], self.pd3[e3][e2 + 1][e1 + 1], self.pd3[e3 + 1][e2][e1 + 1], self.pd3[e3 + 1][e2 + 1][e1 + 1]] + + # px = [] + # pd1 = [] + # pd2 = [] + # pd3 = [] + + # px.append(px_default[lnm[i] - 1]) + # pd1.append(pd1_default[lnm[i] - 1]) + # pd2.append(pd2_default[lnm[i] - 1]) + # pd3.append(pd3_default[lnm[i] - 1]) + + # npd1 = [] + # for ln in range(0, 8, 2): + # npd1.append(vector.addVectors([px[ln+1], px[ln]], [1, -1])) + # npd1.append(vector.addVectors([px[ln+1], px[ln]], [1, -1])) + # + # npd2 = [] + # for ln in range(8): + # lne = ln % 2 + (ln//4)*4 + # npd2.append(vector.addVectors([px[lne + 2], px[lne]], [1, -1])) + # + # npd3 = [] + # for ln in range(8): + # lne = ln % 4 + # npd3.append(vector.addVectors([px[lne + 4], px[lne]], [1, -1])) + # + # #TODO if any np.nd1 <0 scale factor is needed + # for ln in range(8): + # s1 = vector.dotproduct(npd1[ln], pd1[ln]) + + return lnm + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): """ Create shield elements from nodes. @@ -215,13 +404,21 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes e3z = self.elementsCountAcross[2] - 1 e3y = e3z - 1 + lnm = self.local_node_mapping() + for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): for e1 in range(self.elementsCountAcross[1]): eft1 = eft scalefactors = None - nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3 + 1][e2][e1], self.nodeId[e3 + 1][e2 + 1][e1], - self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3 + 1][e2][e1 + 1], self.nodeId[e3 + 1][e2 + 1][e1 + 1]] + # [1, 3, 2] -> [-1, 2, 3] + + # lnm, nids = self.local_node_mapping(e3, e2, e1) + nids_default = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3 + 1][e2][e1], self.nodeId[e3 + 1][e2 + 1][e1], + self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3 + 1][e2][e1 + 1], self.nodeId[e3 + 1][e2 + 1][e1 + 1]] + nids = [None] * 8 + for i in range(1, 9): + nids[lnm[i] - 1] = nids_default[i - 1] element_regular = (e3 <= e3y and e2 > e2a and e1 < e1z) element_quadruple_down_left = (e3 == e3y and e2 == 0 and e1 == e1y) @@ -237,58 +434,58 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if element_regular: pass elif element_quadruple_down_left: - nids[2] = self.nodeId[e3+2][e2][e1] - nids[4] = self.nodeId[e3][e2][e1+2] - nids[6] = self.nodeId[e3+2][e2][e1+2] + nids[lnm[2 + 1] - 1] = self.nodeId[e3+2][e2][e1] + nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2][e1+2] + nids[lnm[6 + 1] - 1] = self.nodeId[e3+2][e2][e1+2] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_12_LEFT) - self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_12_LEFT) - self.remap_eft_node_value_label(eft1, [7], self.QUADRUPLE_DOWN_LEFT) - self.remap_eft_node_value_label(eft1, [8], self.QUADRUPLE0_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.QUADRUPLE0_DOWN_LEFT) if e1y == 0: - self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_13_DOWN) if e3y == 0: - self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) else: - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_13_DOWN) - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) else: - self.remap_eft_node_value_label(eft1, [4], self.TRIPLE_CURVE0_2_DOWN) - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_2_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) elif element_quadruple_down: - nids[2] = self.nodeId[e3+2][e2][e1] - nids[6] = self.nodeId[e3+2][e2][e1+1] + nids[lnm[2 + 1] - 1] = self.nodeId[e3+2][e2][e1] + nids[lnm[6 + 1] - 1] = self.nodeId[e3+2][e2][e1+1] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_13_DOWN) - self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_2_DOWN) - self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_CURVE0_2_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_2_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_2_DOWN) if e1 == 0: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) if e3y == 0: - self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) - self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) else: - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_13_DOWN) - self.remap_eft_node_value_label(eft1, [5], self.SURFACE_REGULAR_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) else: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) if e3y == 0: - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) - self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) else: - self.remap_eft_node_value_label(eft1, [1, 5], self.SURFACE_REGULAR_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1], lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -298,99 +495,107 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes else: e2r = e2 - nids[4] = self.nodeId[e3][e2r][e1+1] - nids[6] = self.nodeId[e3+2][e2r][e1+1] - nids[7] = self.nodeId[e3+2][e2+1][e1+1] + nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2r][e1+1] + nids[lnm[6 + 1] - 1] = self.nodeId[e3+2][e2r][e1+1] + nids[lnm[7 + 1] - 1] = self.nodeId[e3+2][e2+1][e1+1] - # if e2 == e2b or e2 == e2z: eft1 = tricubichermite.createEftNoCrossDerivatives() if e2 == e2b or e2 == e2z: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] + if self._boxMapping == [-1, 2, 3] or self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2] or self._boxMapping == [-3, 1, 2]\ + or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + + if e2 == e2b: - self.remap_eft_node_value_label(eft1, [1], self.TRIPLE0_12_RIGHT) - self.remap_eft_node_value_label(eft1, [3], self.QUADRUPLE0_RIGHT) - self.remap_eft_node_value_label(eft1, [7], self.QUADRUPLE_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.QUADRUPLE0_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_RIGHT) if e2b == e2z: - self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_23_DOWN) - self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) if e3y == 0: - self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) else: - self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: - self.remap_eft_node_value_label(eft1, [4], self.TRIPLE_CURVE0_1_DOWN) - self.remap_eft_node_value_label(eft1, [6], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_1_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE_1_DOWN) elif e2 == e2z: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE0_1_DOWN) - self.remap_eft_node_value_label(eft1, [4], self.TRIPLE0_23_DOWN) - self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE0_1_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_1_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) if e3y == 0: - self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_RIGHT) - self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) else: - self.remap_eft_node_value_label(eft1, [5], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: - self.remap_eft_node_value_label(eft1, [3, 4], self.TRIPLE_CURVE0_1_DOWN) - self.remap_eft_node_value_label(eft1, [5, 6], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.TRIPLE_CURVE0_1_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_DOWN) elif element_quadruple_up_left: if e2 == 1: e2r = e2 - 1 else: e2r = e2 - nids[2] = self.nodeId[e3+1][e2r][e1] - nids[6] = self.nodeId[e3+1][e2r][e1+2] - nids[7] = self.nodeId[e3+1][e2+1][e1+2] + nids[lnm[2 + 1] - 1] = self.nodeId[e3+1][e2r][e1] + nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2r][e1+2] + nids[lnm[7 + 1] - 1] = self.nodeId[e3+1][e2+1][e1+2] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] if e2 == e2b: - self.remap_eft_node_value_label(eft1, [1], self.TRIPLE_CURVE0_2_UP) - self.remap_eft_node_value_label(eft1, [7], self.QUADRUPLE_UP) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_UP) if e2b == e2z: - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) - self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_23_UP) - self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_UP) if e1y == 0: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) else: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) else: - self.remap_eft_node_value_label(eft1, [6], self.TRIPLE_CURVE0_1_UP) - self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_CURVE_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE_1_UP) if e1y == 0: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_13_UP) else: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) - self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.SURFACE_REGULAR_UP) elif e2 == e2z: - self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_23_UP) - self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_CURVE0_1_UP) - self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_23_UP) - self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_1_UP) if e1y == 0: - self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) - self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_UP) else: - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) - self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_UP) else: if e1y == 0: - self.remap_eft_node_value_label(eft1, [3, 4], self.BOUNDARY_13_UP) - self.remap_eft_node_value_label(eft1, [5, 6], self.TRIPLE_CURVE0_1_UP) - self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.BOUNDARY_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_UP) else: - self.remap_eft_node_value_label(eft1, [3, 4], self.SURFACE_REGULAR_UP) - self.remap_eft_node_value_label(eft1, [5, 6], self.TRIPLE_CURVE0_1_UP) - self.remap_eft_node_value_label(eft1, [7, 8], self.TRIPLE_CURVE_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.TRIPLE_CURVE0_1_UP) + self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_UP) elif element_quadruple_up: if e2 == e2b: @@ -398,101 +603,110 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes else: e2r = e2 - nids[2] = self.nodeId[e3+1][e2r][e1] - nids[6] = self.nodeId[e3+1][e2r][e1+1] + nids[lnm[2 + 1] - 1] = self.nodeId[e3+1][e2r][e1] + nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2r][e1+1] eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - if e2 == e2b: + + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] if e1 == 0: - self.remap_eft_node_value_label(eft1, [1], self.TRIPLE0_13_Up) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_13_Up) else: - self.remap_eft_node_value_label(eft1, [1], self.TRIPLE_CURVE0_2_UP) - self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_CURVE0_2_UP) - self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_2_UP) if e2b == e2z: - self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_UP) if e1 == 0: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) - self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3) else: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) else: if e1 == 0: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_13_UP) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_13_UP) else: - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE_2_UP) - self.remap_eft_node_value_label(eft1, [4], self.SURFACE_REGULAR_UP) - self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_UP) elif e2 == e2z: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] if e1 == 0: - self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_UP) - self.remap_eft_node_value_label(eft1, [4], self.CORNER_3) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3) else: - self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_UP) - self.remap_eft_node_value_label(eft1, [4], self.BOUNDARY_23_UP) - self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_UP) - self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_UP) else: if e1 == 0: - self.remap_eft_node_value_label(eft1, [3, 4], self.BOUNDARY_13_UP) - self.remap_eft_node_value_label(eft1, [7, 8], self.SURFACE_REGULAR_UP) + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.BOUNDARY_13_UP) + self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) else: - self.remap_eft_node_value_label(eft1, [3, 4, 7, 8], self.SURFACE_REGULAR_UP) + if self._boxMapping == [1, 3, 2] or self._boxMapping == [-1, 2, 3] or self._boxMapping == [-1, -3, 2] \ + or self._boxMapping == [-3, 1, 2] or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2]: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4], lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) elif element_quadruple_left: - nids[4] = self.nodeId[e3][e2][e1+2] - nids[6] = self.nodeId[e3+1][e2][e1+2] + nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2][e1+2] + nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2][e1+2] eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] + if not self._boxMapping == [-1, 2, 3] and not self._boxMapping == [-3, 1, 2]: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_12_LEFT) - self.remap_eft_node_value_label(eft1, [6], self.TRIPLE0_12_LEFT) - self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_3_LEFT) - self.remap_eft_node_value_label(eft1, [8], self.TRIPLE_CURVE0_3_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_3_LEFT) if e1y == 0: - self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) if e3 == 0: - self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) else: - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) else: - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) - self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) elif element_quadruple_right: - nids[4] = self.nodeId[e3][e2-1][e1+1] - nids[6] = self.nodeId[e3+1][e2-1][e1+1] + nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2-1][e1+1] + nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2-1][e1+1] eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [3], self.TRIPLE_CURVE0_3_RIGHT) - self.remap_eft_node_value_label(eft1, [7], self.TRIPLE_CURVE_3_RIGHT) - if e3y == 0: - self.remap_eft_node_value_label(eft1, [1], self.TRIPLE0_12_RIGHT) - self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE0_3_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_RIGHT) + if e3 == 0: + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT) else: - self.remap_eft_node_value_label(eft1, [1], self.TRIPLE_CURVE0_3_RIGHT) - self.remap_eft_node_value_label(eft1, [5], self.TRIPLE_CURVE_3_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_3_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) if e2b == e2z: - self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) if e3 == 0: - self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) else: - self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: - self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) - self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) elif element_down_right: if e3 == 0: @@ -501,47 +715,62 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_RIGHT) - self.remap_eft_node_value_label(eft1, [6], self.CORNER_2) - self.remap_eft_node_value_label(eft1, [8], self.BOUNDARY_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) else: - self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_RIGHT) - self.remap_eft_node_value_label(eft1, [6], self.BOUNDARY_12_RIGHT) - self.remap_eft_node_value_label(eft1, [8], self.SURFACE_REGULAR_DOWN_RIGHT) + if self._boxMapping == [-1, 2, 3] or self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2]\ + or self._boxMapping == [-3, 1, 2] or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2]\ + or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) else: - - self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [5], self.SURFACE_REGULAR_DOWN_RIGHT) - if e2 == e2z: - eft1 = tricubichermite.createEftNoCrossDerivatives() + eft1 = tricubichermite.createEftNoCrossDerivatives() + if self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2] or self._boxMapping == [-3, 1, 2] or e2 == e2z\ + or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [6, 8], self.BOUNDARY_23_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_RIGHT) + if e2 == e2z: + self.remap_eft_node_value_label(eft1, [lnm[6], lnm[8]], self.BOUNDARY_23_DOWN) else: - self.remap_eft_node_value_label(eft1, [6, 8], self.SURFACE_REGULAR_DOWN_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[6], lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) elif element_down_left: eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] + if e3 == 0: - self.remap_eft_node_value_label(eft1, [5], self.BOUNDARY_12_LEFT) - self.remap_eft_node_value_label(eft1, [7], self.SURFACE_REGULAR_DOWN_LEFT) + if self._boxMapping == [1, 3, 2] or self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2] or\ + self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) if e1 == 0: - self.remap_eft_node_value_label(eft1, [1], self.CORNER_1) - self.remap_eft_node_value_label(eft1, [3], self.BOUNDARY_13_DOWN) + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) else: - self.remap_eft_node_value_label(eft1, [1], self.BOUNDARY_12_LEFT) - self.remap_eft_node_value_label(eft1, [3], self.SURFACE_REGULAR_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) else: - self.remap_eft_node_value_label(eft1, [5, 7], self.SURFACE_REGULAR_DOWN_LEFT) + if e1 == 0 or not self._boxMapping == [-3, 1, 2]: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + self.remap_eft_node_value_label(eft1, [lnm[5], lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) if e1 == 0: - self.remap_eft_node_value_label(eft1, [1, 3], self.BOUNDARY_13_DOWN) + self.remap_eft_node_value_label(eft1, [lnm[1], lnm[3]], self.BOUNDARY_13_DOWN) else: - self.remap_eft_node_value_label(eft1, [1, 3], self.SURFACE_REGULAR_DOWN_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1], lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -565,148 +794,262 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes return elementIdentifier + def label_map(self): + """ + + :return: + """ + + # [1, 3, 2] -> [-1, 2, 3] + signs = [] + label_mapping = {'xi1': abs(self._boxMapping[0]), 'xi3': abs(self._boxMapping[1]), 'xi2': abs(self._boxMapping[2])} + for c in self._boxMapping: + sign = 1 if c > 0 else -1 + signs.append(sign) + local_nodes_order_signs = {'xi1': signs[0], 'xi3': signs[1], 'xi2': signs[2]} + xi_mapping = {'xi1': []} + + # How to determine new curve labels? from mapping [c1, c3, c2] -> [3, -1, 2] neglect sign + # so c1_label = abs(self._boxMapping[0]), c2_label = abs(self._boxMapping[0]), c3_label = abs(self._boxMapping[0]). + # Note that generally, c1 is not any of d1, d2, d3 but its label is said to be d1, d2, d3 and it means the element axes or xi directions. + # and not nodal d1, d2, d3. So actually fromLabel or curveLabel is an element thing that for each node it is constructed differently. + # now when we have remap(eft, ln, curveLabel, [(m1, [a1]), (m2, [a2]), (m3, [a3])]). Then this can be used for curve + # again if we find new ln, curvelabel and ms and as which describes the same curve again. + # so for a node, if we know mapping curveLabel = label[lm[c1]]. Note that we indirectly do this, i.e. first use + # a second derivative so the values of the derivatives don't get overwritten. + # from nids orders, we should say if the curve direction is changed or not. e.g. if we want the nids follow the same + # order given by boxMapping then for [3, -1, 2] the sign of the c3 has changed to negative, so all the as should be multiplied by -1. + # for all the nodes and their curves that direction is negative. So if we are talking about changes applied to all interior nodes on the box, + # then this means for all of the such nodes, as for c3 should be multiplied by -1. Because nids are consistent, then we do this for all of the nodes not + # just the interior nodes. Note that nids orders and curves directions are applied for all the nodes and elements. + # Now label[lm[c1]] is gonna do this for all of the mappings. I need to store nid_order, so now here we have nid_order_signs = [1, 1, -1] + # i.e. we sf[a1*nid_order_sings[0]], ... + # Now, this was only the effect of changing nids. This is unneccessary and we could ignore this step and always use the same nids. + # Note that if you want to see what order is used in an element, turn on element axes in scaffoldmaker. + # Now, if ms change as well, like here, [m1, m3, m2] -> [3, -1, 2] which means m1 = expressionLabel[1], where expressionLabel = {m1:d3, m3:d1, m2:d2} + # derivative_signs as well if derivative gets negative, for this case derivative_signs = {m1:1, m2:1, m3:-1}. Which then I multiply only a3 by -1. + # This mapping is done only for the nodes on the box, so for such nodes we have expressionLabel and a3X-1. + + + return label_mapping, signs + def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): """ remaps derivatives for common types of nodes. :return: """ + label = {1: Node.VALUE_LABEL_D2_DS2DS3, 2: Node.VALUE_LABEL_D2_DS1DS3, 3: Node.VALUE_LABEL_D2_DS1DS2} + expressionLabel = {1: Node.VALUE_LABEL_D_DS1, 2: Node.VALUE_LABEL_D_DS2, 3: Node.VALUE_LABEL_D_DS3} + sf = {1: [], -1: [1]} + # lm, signs = self.label_map() + xim = self._xi_mapping + xis = self._xi_signs + dm = self._deriv_mapping + ds = self._deriv_signs + + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D2_DS1DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS1DS2, [])]) + if NODE_TYPE == self.CORNER_1: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.CORNER_2: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.CORNER_3: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.QUADRUPLE_DOWN_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) elif NODE_TYPE == self.QUADRUPLE_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) elif NODE_TYPE == self.QUADRUPLE_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.QUADRUPLE0_DOWN_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1]), (Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif NODE_TYPE == self.QUADRUPLE0_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.QUADRUPLE0_UP: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif NODE_TYPE == self.TRIPLE_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_12_RIGHT: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_13_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_13_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[1]])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap elif NODE_TYPE == self.TRIPLE_23_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.TRIPLE0_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif NODE_TYPE == self.TRIPLE0_12_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.TRIPLE0_13_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) elif NODE_TYPE == self.TRIPLE0_13_Up: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) elif NODE_TYPE == self.TRIPLE0_23_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.TRIPLE0_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif NODE_TYPE == self.BOUNDARY_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.BOUNDARY_12_RIGHT: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.BOUNDARY_13_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) elif NODE_TYPE == self.BOUNDARY_13_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[1]])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, [])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) elif NODE_TYPE == self.BOUNDARY_23_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) elif NODE_TYPE == self.BOUNDARY_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.TRIPLE_CURVE_1_DOWN: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_CURVE_1_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.TRIPLE_CURVE_2_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_CURVE_2_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.TRIPLE_CURVE_3_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_CURVE_3_RIGHT: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_CURVE0_1_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif NODE_TYPE == self.TRIPLE_CURVE0_1_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, - [(Node.VALUE_LABEL_D_DS2, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.TRIPLE_CURVE0_2_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) elif NODE_TYPE == self.TRIPLE_CURVE0_2_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) elif NODE_TYPE == self.TRIPLE_CURVE0_3_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif NODE_TYPE == self.TRIPLE_CURVE0_3_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.SURFACE_REGULAR_DOWN_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.SURFACE_REGULAR_DOWN_RIGHT: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.SURFACE_REGULAR_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.REGULAR: - pass + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) else: raise ValueError("Remapping for derivatives of this 'node type' is not implemented") diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 9a6e2930..879f9e1b 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -25,9 +25,10 @@ class SphereMesh: Sphere mesh generator. """ + def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False): + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. @@ -63,6 +64,8 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, self._centre = centre + self._boxMapping = boxMapping if boxMapping else [1, 3, 2] + for i in range(3): elementsAxis = elementsCountAcross[i] - elementsCountAcrossShell * (1 - shellProportion) self._coreRadius.append( @@ -97,11 +100,13 @@ def createSphereMesh3d(self, fieldModule, coordinates): self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode) - self.calculateBoundaryEllipses() + self.create_boundary_ellipses_nodes() + self.create_surface_and_interior_nodes() + self._shield3D.remap_derivatives(self._boxMapping, circleMapping=None, sphereMapping=None) self.generateNodes(nodes, fieldModule, coordinates) self.generateElements(mesh, fieldModule, coordinates) - def calculateBoundaryEllipses(self): + def create_boundary_ellipses_nodes(self): """ :return: @@ -137,10 +142,9 @@ def calculateBoundaryEllipses(self): elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) - self.copyEllipsesNodesToShieldNodes(ellipse, i) - self.createAdditionalPointsForIncreasingElementsCount() + self.copy_ellipses_nodes_to_shield_nodes(ellipse, i) - def copyEllipsesNodesToShieldNodes(self, ellipse, ellipsenumber): + def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): """ Copy coordinates and derivatives of ellipse to shield. :param n3: the index number of ellipse along the central path. @@ -222,7 +226,7 @@ def copyEllipsesNodesToShieldNodes(self, ellipse, ellipsenumber): else: btd1[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - def createAdditionalPointsForIncreasingElementsCount(self): + def create_surface_and_interior_nodes(self): """ :return: From a94916eb68ac849433bbdf42d33f60a5796d0e2a Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Sun, 3 Oct 2021 20:38:13 +1300 Subject: [PATCH 21/37] Fix hemisphere bugs. --- .../meshtypes/meshtype_3d_solidsphere2.py | 209 +++--- src/scaffoldmaker/utils/shieldmesh.py | 643 +++++++++--------- src/scaffoldmaker/utils/spheremesh.py | 376 ++++++++-- 3 files changed, 772 insertions(+), 456 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 547862f5..892bb5bf 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -60,9 +60,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements across axis 3': 2, 'Number of elements across shell': 0, 'Number of elements across transition': 1, - # 'Number of elements along': 1, - 'Derivatives configuration1': True, - 'Derivatives configuration2': False, 'Shell element thickness proportion': 1.0, 'Octant': True, 'Hemisphere': False, @@ -82,9 +79,6 @@ def getOrderedOptionNames(): 'Number of elements across axis 3', 'Number of elements across shell', 'Number of elements across transition', - # 'Number of elements along', - 'Derivatives configuration1', - 'Derivatives configuration2', 'Shell element thickness proportion', 'Octant', 'Hemisphere', @@ -130,17 +124,32 @@ def checkOptions(cls, options): # options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) dependentChanges = False - # if options['Number of elements across major'] < 4: - # options['Number of elements across major'] = 4 - # if options['Number of elements across major'] % 2: - # options['Number of elements across major'] += 1 - # - # if options['Number of elements across minor'] < 4: - # options['Number of elements across minor'] = 4 - # if options['Number of elements across minor'] % 2: - # options['Number of elements across minor'] += 1 - # if options['Number of elements along'] < 1: - # options['Number of elements along'] = 1 + if options['Octant']: + min1, min2, min3 = 2, 2, 2 + co1, co2, co3 = 0, 0, 0 + elif options['Hemisphere']: + dependentChanges = True + min1, min2, min3 = 4, 4, 2 + co1, co2, co3 = 1, 1, 0 + else: + dependentChanges = True + min1, min2, min3 = 4, 4, 4 + co1, co2, co3 = 1, 1, 1 + + if options['Number of elements across axis 1'] < min1: + options['Number of elements across axis 1'] = min1 + if options['Number of elements across axis 2'] < min2: + options['Number of elements across axis 2'] = min2 + if options['Number of elements across axis 3'] < min3: + options['Number of elements across axis 3'] = min3 + + if options['Number of elements across axis 1'] % 2: + options['Number of elements across axis 1'] += co1 + if options['Number of elements across axis 2'] % 2: + options['Number of elements across axis 2'] += co2 + if options['Number of elements across axis 3'] % 2: + options['Number of elements across axis 3'] += co3 + # if options['Number of elements across transition'] < 1: # options['Number of elements across transition'] = 1 # Rcrit = min(options['Number of elements across major']-4, options['Number of elements across minor']-4)//2 @@ -164,33 +173,25 @@ def generateBaseMesh(region, options): """ # centralPath = options['Central path'] - # full = not options['Lower half'] - octant = options['Octant'] - hemisphere = options['Hemisphere'] - full = options['Full'] elementsCountAcrossAxis1 = options['Number of elements across axis 1'] elementsCountAcrossAxis2 = options['Number of elements across axis 2'] elementsCountAcrossAxis3 = options['Number of elements across axis 3'] - # 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'] - first = options['Derivatives configuration1'] - second = options['Derivatives configuration2'] - if first: - boxMapping = [1, 3, 2] - if second and not first: - boxMapping = [-1, 2, 3] + if options['Octant']: + sphere_shape = SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP + elif options['Hemisphere']: + sphere_shape = SphereShape.SPHERE_SHAPE_HALF_NNP + else: + sphere_shape = SphereShape.SPHERE_SHAPE_FULL fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) centre = [0.0, 0.0, 0.0] - axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] axis3 = [0.0, 0.0, 1.0] @@ -199,79 +200,79 @@ def generateBaseMesh(region, options): sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - - if (hemisphere or full) and not octant: - axis1 = [0.0, -1.0, 0.0] - axis2 = [1.0, 0.0, 0.0] - axis3 = [0.0, 0.0, 1.0] - axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - boxMapping = [3, -1, 2] - sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - - axis1 = [-1.0, 0.0, 0.0] - axis2 = [0.0, -1.0, 0.0] - axis3 = [0.0, 0.0, 1.0] - axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - boxMapping = [-1, -3, 2] - sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - - axis1 = [0.0, 1.0, 0.0] - axis2 = [-1.0, 0.0, 0.0] - axis3 = [0.0, 0.0, 1.0] - axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - boxMapping = [-3, 1, 2] - sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + sphereShape=sphere_shape, useCrossDerivatives=False, boxMapping=[1, 3, 2]) - if full and not octant and not hemisphere: - axis1 = [0.0, 1.0, 0.0] - axis2 = [1.0, 0.0, 0.0] - axis3 = [0.0, 0.0, -1.0] - axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - boxMapping = [-3, -1, -2] - sphere5 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - - axis2 = [0.0, -1.0, 0.0] - axis1 = [1.0, 0.0, 0.0] - axis3 = [0.0, 0.0, -1.0] - axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - boxMapping = [1, -3, -2] - sphere6 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - - axis2 = [-1.0, 0.0, 0.0] - axis1 = [0.0, -1.0, 0.0] - axis3 = [0.0, 0.0, -1.0] - axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - boxMapping = [3, 1, -2] - sphere7 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - - axis2 = [0.0, 1.0, 0.0] - axis1 = [-1.0, 0.0, 0.0] - axis3 = [0.0, 0.0, -1.0] - axes = [axis1, axis2, axis3] - elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - boxMapping = [-1, 3, -2] - sphere8 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + # if (hemisphere or full) and not octant: + # axis1 = [0.0, -1.0, 0.0] + # axis2 = [1.0, 0.0, 0.0] + # axis3 = [0.0, 0.0, 1.0] + # axes = [axis1, axis2, axis3] + # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] + # boxMapping = [3, -1, 2] + # sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + # + # axis1 = [-1.0, 0.0, 0.0] + # axis2 = [0.0, -1.0, 0.0] + # axis3 = [0.0, 0.0, 1.0] + # axes = [axis1, axis2, axis3] + # elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + # boxMapping = [-1, -3, 2] + # # sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + # # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + # # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + # # + # # axis1 = [0.0, 1.0, 0.0] + # # axis2 = [-1.0, 0.0, 0.0] + # # axis3 = [0.0, 0.0, 1.0] + # # axes = [axis1, axis2, axis3] + # # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] + # # boxMapping = [-3, 1, 2] + # # sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + # # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + # # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + # + # if full and not octant and not hemisphere: + # axis1 = [0.0, 1.0, 0.0] + # axis2 = [1.0, 0.0, 0.0] + # axis3 = [0.0, 0.0, -1.0] + # axes = [axis1, axis2, axis3] + # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] + # boxMapping = [-3, -1, -2] + # sphere5 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + # + # axis2 = [0.0, -1.0, 0.0] + # axis1 = [1.0, 0.0, 0.0] + # axis3 = [0.0, 0.0, -1.0] + # axes = [axis1, axis2, axis3] + # elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + # boxMapping = [1, -3, -2] + # sphere6 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + # + # axis2 = [-1.0, 0.0, 0.0] + # axis1 = [0.0, -1.0, 0.0] + # axis3 = [0.0, 0.0, -1.0] + # axes = [axis1, axis2, axis3] + # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] + # boxMapping = [3, 1, -2] + # sphere7 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + # + # axis2 = [0.0, 1.0, 0.0] + # axis1 = [-1.0, 0.0, 0.0] + # axis3 = [0.0, 0.0, -1.0] + # axes = [axis1, axis2, axis3] + # elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + # boxMapping = [-1, 3, -2] + # sphere8 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, + # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) annotationGroup = [] return annotationGroup diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index e3927213..3e9b945a 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -1,8 +1,9 @@ -''' +""" Class for generating a shield-shaped mesh, with a regular flat top but a rounded bottom formed by having two points where 3 square elements merge to form a triangle. -''' +""" + from __future__ import division import copy import math @@ -18,44 +19,46 @@ from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition, calculate_surface_axes from enum import Enum + class ShieldShape2D(Enum): SHIELD_SHAPE_FULL = 1 SHIELD_SHAPE_LOWER_HALF = 2 + class ShieldShape3D(Enum): SHIELD_SHAPE_FULL = 1 SHIELD_SHAPE_HALF_NNP = 2 # NNP is a3>=3 SHIELD_SHAPE_OCTANT_PPP = 3 # in a right hand coordinate system (a1,a2,a3), PPP means a1>=0, a2>=0 and a3>=0 + class ShieldRimDerivativeMode(Enum): SHIELD_RIM_DERIVATIVE_MODE_AROUND = 1 # rim derivatives are d1 anticlockwise around shield, d3 outward SHIELD_RIM_DERIVATIVE_MODE_REGULAR = 2 # rim derivatives d1, d2 match interior nodes for regular elements + class ShieldMesh3D: - ''' - Generates a 3D shield mesh. - ''' + """ + Generates a 3D shield mesh. + """ - def __init__(self, elementsCountAcross, elementsCountRim, - shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP, boxMapping=None): + def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP, box_derivatives=None): """ 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the centre. - The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a special node on the + The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a unique node on the surface where the elements merge. 'Triple curves' meet at the quadruple point and a fourth curve that connects to another quadruple point which is inside. The structure is like a elementsCountAcross[0] X elementsCountAcross[1] X elementsCountAcross[2] box where some nodes does not exist and stored as None. The quadruple point is stored at [n3z][0][n1z] (top, front and right most node) where n3z is top most and n1z is the right most indexes. - Triple curves and surfaces connecting to the quadruple point, divides the surface and interior into 3 regions - (top, left and right). Triple curve 1 connects the quadruple point to the plane 2-3. Similarly triple curves 2 and 3 + Triple curves and surfaces connecting to the quadruple point divide the exterior surface and interior region into 3 regions + (top, left and right). Triple curve 1 connects the quadruple point to the plane 2-3. Similarly, triple curves 2 and 3 connect the quadruple point to the planes 1-3 and 1-2, respectively. It is the same for the inside quadruple. Any point on region left has n2 = 0. Similarly on region right -> n1 = n1z and on top -> n3 = n3z. - There is a gap between node indexes of a node on the triple curve and the next node on the surface. - + There is a gap between node indexes of a node on a triple curve and the next nodes on the surface. - :param elementsCountAcross: + :param elementsCountAcross: number of elements as a list [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] :param elementsCountRim: - :param shieldMode: + :param shieldMode: TODO should it be only Octant_PPP? """ assert elementsCountRim >= 0 # assert elementsCountAlong >= 1 @@ -71,8 +74,8 @@ def __init__(self, elementsCountAcross, elementsCountRim, # self.elementsCountUpRegular = elementsCountUp - 2 - elementsCountRim # elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim - self._mode = shieldMode - self._boxMapping = boxMapping + self._shieldMode = shieldMode + self._boxDerivatives = box_derivatives self.px = [ [] for _ in range(elementsCountAcross[2] + 1) ] self.pd1 = [ [] for _ in range(elementsCountAcross[2] + 1) ] @@ -86,57 +89,42 @@ def __init__(self, elementsCountAcross, elementsCountRim, self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] - def remap_derivatives(self, boxMapping, circleMapping=None, sphereMapping=None): + def set_derivatives(self, box_derivatives): """ - It remaps the derivatives as indicated by squareMapping and circleMapping. Limited to SHIELD_RIM_DERIVATIVE_MODE_AROUND. - :param squareMapping: List[up, right]. Determines what derivatives should be in the up and right directions in the - square part. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. - The negative sign reverses the direction. e.g. [-3,2] means d3 is down and d2 is right. The third derivative - is determined by the other two. RH rule applied. Assumes [1,3] initially. - :param circleMapping: List[circumferential, radial]. Determines what derivatives should be used for - circumferential and radial directions around the circle. - [-1, 3] means d1 -> clockwise and around. d3 -> outward and radial. Assumes [1,3] initially. + Set the derivatives as specified by box_derivatives and circleMapping. + :param box_derivatives: List[d_axis1_negative, d_axis2, d_axis3]. Determines what derivatives should be + for back, right and up directions in the box region. Their values are in [1,2,3] range which 1, 2, 3 means + d1, d2 and d3 respectively. + The negative sign reverses the direction. e.g. [1, -3,2] means for the right direction use -d3. Default is [1,3, 2]. :return: """ - # [+3,-1, +2] or [back, right, up] -> default = [1,3,2] Now let's get it for [-1, 2, 3] which is natural. - self._boxMapping = boxMapping + self._boxMapping = box_derivatives dct = {1: self.pd1, 2: self.pd2, 3: self.pd3} perm = {(1, 2): -3, (2, 3): -1, (3, 1): -2, (3, 2): 1, (1, 3): 2, (2, 1): 3} - # square = True - # tripleRow = [self.elementsCountRim + 1, self.elementsCountUpFull - (self.elementsCountRim + 1)] - # ellipseMapping = [boxMapping, circleMapping] - sphereMapping = [boxMapping] - for mapping in sphereMapping: - if mapping: - signs = [] - for c in mapping: - sign = 1 if c > 0 else -1 - signs.append(sign) - # derv = (abs(mapping[0]), abs(mapping[1])) - # sign = 1 if perm[derv] > 0 else -1 - # signs.append(signs[0] * signs[1] * sign) - dervMapping = (abs(mapping[0]), abs(mapping[1]), abs(mapping[2])) - # dervMapping = (derv[0], derv[1], abs(perm[derv])) + if box_derivatives: + signs = [] + for c in box_derivatives: + sign = 1 if c > 0 else -1 + signs.append(sign) - temp1 = copy.deepcopy(self.pd3) - temp2 = copy.deepcopy(self.pd2) - for n3 in range(self.elementsCountAcross[2] + 1): - for n2 in range(self.elementsCountAcross[0] + 1): - for n1 in range(self.elementsCountAcross[1] + 1): - if self.px[n3][n2][n1]: - # is_on_square = ((self.px[n3][n2][0] and self.px[n3][0][n1]) or n2 in tripleRow) - # if (is_on_square and square) or (not is_on_square and not square): - if self.is_interior_regular_nodes(n3, n2, n1): - dct[dervMapping[0]][n3][n2][n1] = [signs[0] * c for c in self.pd1[n3][n2][n1]] - dct[dervMapping[1]][n3][n2][n1] = [signs[1] * c for c in temp1[n3][n2][n1]] - dct[dervMapping[2]][n3][n2][n1] = [signs[2] * c for c in temp2[n3][n2][n1]] - # square = False + dervMapping = (abs(box_derivatives[0]), abs(box_derivatives[1]), abs(box_derivatives[2])) + + temp1 = copy.deepcopy(self.pd3) + temp2 = copy.deepcopy(self.pd2) + for n3 in range(self.elementsCountAcross[2] + 1): + for n2 in range(self.elementsCountAcross[0] + 1): + for n1 in range(self.elementsCountAcross[1] + 1): + if self.px[n3][n2][n1]: + if self.is_interior_regular_nodes(n3, n2, n1): + dct[dervMapping[0]][n3][n2][n1] = [signs[0] * c for c in self.pd1[n3][n2][n1]] + dct[dervMapping[1]][n3][n2][n1] = [signs[1] * c for c in temp1[n3][n2][n1]] + dct[dervMapping[2]][n3][n2][n1] = [signs[2] * c for c in temp2[n3][n2][n1]] def is_interior_regular_nodes(self, n3, n2, n1): """ - + Determine if a node indicated by [n3,n2,n1], is inside the sphere. :return: """ n3z = self.elementsCountAcross[2] @@ -147,13 +135,12 @@ def is_interior_regular_nodes(self, n3, n2, n1): return n3 <= n3y and n2 >= 1 and n1 <= n1y - def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlane=None): + def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier): """ 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 mirrorPlane: mirror plane ax+by+cz=d in form of [a,b,c,d] :return: next nodeIdentifier. """ nodeIdentifier = startNodeIdentifier @@ -164,20 +151,12 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan 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_D_DS3, 1) + # In case we swap derivatives in the when we use remap function. nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) cache = fieldmodule.createFieldcache() - #for n2 in range(self.elementsCountUp, -1, -1): - # s = "" - # for n1 in range(self.elementsCountAcross + 1): - # s += str(n1) if self.px[1][n2][n1] else " " - # print(n2, s, n2 - self.elementsCountUp - 1) - - # if self._mode == ShieldShape2D.SHIELD_SHAPE_FULL and mirrorPlane: - # self.generateNodesForOtherHalf(mirrorPlane) - for n2 in range(self.elementsCountAcross[0] + 1): for n3 in range(self.elementsCountAcross[2] + 1): for n1 in range(self.elementsCountAcross[1] + 1): @@ -243,7 +222,19 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan SURFACE_REGULAR_UP = 42 REGULAR = 43 - def local_node_mapping(self): + # element types + ELEMENT_REGULAR = 1 + ELEMENT_QUADRUPLE_DOWN_LEFT = 2 + ELEMENT_QUADRUPLE_DOWN_RIGHT = 3 + ELEMENT_QUADRUPLE_UP_LEFT = 4 + ELEMENT_QUADRUPLE_DOWN = 5 + ELEMENT_QUADRUPLE_UP = 6 + ELEMENT_QUADRUPLE_LEFT = 7 + ELEMENT_QUADRUPLE_RIGHT = 8 + ELEMENT_DOWN_RIGHT = 9 + ELEMENT_DOWN_LEFT = 10 + + def local_node_mapping(self, boxMapping): """ :return: @@ -279,9 +270,9 @@ def local_node_mapping(self): boxMapping_default = [1, 3, 2] signs = [] - xi_map = {'xi1': abs(self._boxMapping[0]), 'xi3': abs(self._boxMapping[1]), 'xi2': abs(self._boxMapping[2])} + xi_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} for di in range(3): - sign = 1 if self._boxMapping[di]*boxMapping_default[di] > 0 else -1 + sign = 1 if boxMapping[di]*boxMapping_default[di] > 0 else -1 signs.append(sign) xi_sign_change = [signs[0], signs[2], signs[1]] @@ -303,9 +294,9 @@ def local_node_mapping(self): lnm[ln] = xi_node_map[tuple(xi_l)] signs = [] - deriv_map = {'xi1': abs(self._boxMapping[0]), 'xi3': abs(self._boxMapping[1]), 'xi2': abs(self._boxMapping[2])} + deriv_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} for di in range(3): - sign = 1 if self._boxMapping[di]*boxMapping_default[di] > 0 else -1 + sign = 1 if boxMapping[di]*boxMapping_default[di] > 0 else -1 signs.append(sign) deriv_sign_change = [signs[0], signs[2], signs[1]] @@ -368,6 +359,152 @@ def local_node_mapping(self): return lnm + def get_element_type(self, e3, e2, e1): + """ + + :return: + """ + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + octant_number = 1 + e3o, e2o, e1o = e3, e2, e1 + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[0] - 1 + e1zo = self.elementsCountAcross[1] - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_NNP: + if e2 < self.elementsCountAcross[0]//2: + if e1 >= self.elementsCountAcross[1]//2: + octant_number = 1 + e3o, e2o, e1o = e3, e2, e1 - self.elementsCountAcross[1]//2 + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[0]//2 - 1 + e1zo = self.elementsCountAcross[1]//2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + else: + octant_number = 2 + e3o, e2o, e1o = e3, e1, self.elementsCountAcross[0]//2 - 1 - e2 + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[1]//2 - 1 + e1zo = self.elementsCountAcross[0]//2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + + else: + if e1 < self.elementsCountAcross[1]//2: + octant_number = 3 + e3o, e2o, e1o = e3, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1]//2 - 1 - e1 + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[0]//2 - 1 + e1zo = self.elementsCountAcross[1]//2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + else: + octant_number = 4 + e3o, e2o, e1o = e3, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0]//2 + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[1]//2 - 1 + e1zo = self.elementsCountAcross[0]//2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + + if e3o <= e3yo and e2o >= e2bo and e1o <= e1yo: + # print('regular', e3, e2, e1, e3o, e2o, e1o, e3yo, e2bo, e1zo) + element_type = self.ELEMENT_REGULAR + elif e3o == e3yo and e2o == 0 and e1o == e1yo: + element_type = self.ELEMENT_QUADRUPLE_DOWN_LEFT + elif e3o == e3yo and e2o >= e2bo and e1o == e1zo: + element_type = self.ELEMENT_QUADRUPLE_DOWN_RIGHT + elif e3o == e3zo and e2o >= e2bo and e1o == e1yo: + element_type = self.ELEMENT_QUADRUPLE_UP_LEFT + elif e3o == e3yo and e2o == 0 and e1o < e1yo: + # print('regular', e3, e2, e1, e3o, e2o, e1o, e3yo, e2bo, e1yo) + element_type = self.ELEMENT_QUADRUPLE_DOWN + elif e3o == e3zo and e2o >= e2bo and e1o < e1yo: + element_type = self.ELEMENT_QUADRUPLE_UP + elif e3o < e3yo and e2o == 0 and e1o == e1yo: + element_type = self.ELEMENT_QUADRUPLE_LEFT + elif e3o < e3yo and e2o == e2bo and e1o == e1zo: + element_type = self.ELEMENT_QUADRUPLE_RIGHT + elif e3o < e3yo and e2o > e2bo and e1o == e1zo: + element_type = self.ELEMENT_DOWN_RIGHT + elif e3o < e3yo and e2o == 0 and e1o < e1yo: + element_type = self.ELEMENT_DOWN_LEFT + else: + element_type = 0 + + return octant_number, element_type, e3o, e2o, e1o, e3zo, e2zo, e1zo + + def get_global_node_index(self, octant_number, n3o, n2o, n1o): + """ + + :return: + """ + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + n3, n2, n1 = n3o, n2o, n1o + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_NNP: + if octant_number == 1: + n3, n2, n1 = n3o, n2o, n1o + self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 - n1o, n2o + elif octant_number == 3: + n3, n2, n1 = n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o + elif octant_number == 4: + n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o + + return n3, n2, n1 + + def get_octant_node_index(self, octant_number, n3, n2, n1): + """ + + :return: + """ + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + n3o, n2o, n1o = n3, n2, n1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_NNP: + if octant_number == 1: + n3o, n2o, n1o = n3, n2, n1 - self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3o, n2o, n1o = n3, n1, self.elementsCountAcross[0] // 2 - n2 + elif octant_number == 3: + n3o, n2o, n1o = n3, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 + elif octant_number == 4: + n3o, n2o, n1o = n3, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 + + return n3o, n2o, n1o + + def getNodeId(self, octant_number, n3, n2, n1, n3yo, n1yo, n2zo): + """ + + :return: + """ + n1zo = n1yo + 1 + n3zo = n3yo + 1 + n3o, n2o, n1o = self.get_octant_node_index(octant_number, n3, n2, n1) + if n2o == 0 and n1o == n1yo: + if n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o, n1o+1) + elif n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o + 1) + else: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o, n1o + 1) + elif n2o == 1 and n1o == n1zo: + if n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o-1, n1o) + elif n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o+1) + else: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o) + elif n3o == n3yo and (n2o == 0 or n1o == n1zo): + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o, n1o) + elif n3o == n3zo and n2o == 1 and n1o == n1yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o+1) + elif n3o == n3zo and n2o == 1: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o - 1, n1o) + elif n3o == n3zo and n2o > 1 and n1o == n1yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o, n1o+1) + else: + n3r, n2r, n1r = n3, n2, n1 + + # print(n3r, n2r, n1r, n3, n2, n1, n3o, n2o, n1o) + return self.nodeId[n3r][n2r][n1r] # (1,1,1)->(2,1,1) + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): """ Create shield elements from nodes. @@ -391,53 +528,55 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) # isEven = (self.elementsCountAcross % 2) == 0 - e1a = self.elementsCountRim - e1b = e1a + 1 - e1z = self.elementsCountAcross[1] - 1 - self.elementsCountRim - e1y = e1z - 1 - e2a = self.elementsCountRim - e2b = self.elementsCountRim + 1 - e2c = self.elementsCountRim + 2 - e2z = self.elementsCountAcross[0] - 1 + # e1a = self.elementsCountRim + # e1b = e1a + 1 + # e1z = self.elementsCountAcross[1] - 1 - self.elementsCountRim + # e1y = e1z - 1 + # e2a = self.elementsCountRim + # e2b = self.elementsCountRim + 1 + # e2c = self.elementsCountRim + 2 + # e2z = self.elementsCountAcross[0] - 1 # e2y = e2z - 1 # e2x = e2z - 2 - e3z = self.elementsCountAcross[2] - 1 - e3y = e3z - 1 - - lnm = self.local_node_mapping() for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): for e1 in range(self.elementsCountAcross[1]): eft1 = eft scalefactors = None - # [1, 3, 2] -> [-1, 2, 3] - - # lnm, nids = self.local_node_mapping(e3, e2, e1) - nids_default = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3 + 1][e2][e1], self.nodeId[e3 + 1][e2 + 1][e1], - self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3 + 1][e2][e1 + 1], self.nodeId[e3 + 1][e2 + 1][e1 + 1]] - nids = [None] * 8 - for i in range(1, 9): - nids[lnm[i] - 1] = nids_default[i - 1] - - element_regular = (e3 <= e3y and e2 > e2a and e1 < e1z) - element_quadruple_down_left = (e3 == e3y and e2 == 0 and e1 == e1y) - element_quadruple_down_right = (e3 == e3y and e2 >= e2b and e1 == e1z) - element_quadruple_up_left = (e3 == e3z and e2 >= e2b and e1 == e1y) - element_quadruple_down = (e3 == e3y and e2 == 0 and e1 < e1y) - element_quadruple_up = (e3 == e3z and e2 >= e2b and e1 < e1y) - element_quadruple_left = (e3 < e3y and e2 == 0 and e1 == e1y) - element_quadruple_right = (e3 < e3y and e2 == e2b and e1 == e1z) - element_down_right = (e3 < e3y and e2 > e2b and e1 == e1z) - element_down_left = (e3 < e3y and e2 == 0 and e1 < e1y) - - if element_regular: - pass - elif element_quadruple_down_left: - nids[lnm[2 + 1] - 1] = self.nodeId[e3+2][e2][e1] - nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2][e1+2] - nids[lnm[6 + 1] - 1] = self.nodeId[e3+2][e2][e1+2] + octant_number, element_type, e3o, e2o, e1o, e3zo, e2zo, e1zo = self.get_element_type(e3, e2, e1) + # print(octant_number, element_type, e3, e2, e1) + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + nids = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo, e2zo+1), + self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo, e2zo+1), + self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo, e2zo+1), + self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo, e2zo+1)] + # print(e3, e2, e1, nids) + + if octant_number == 1: + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + lnm = self.local_node_mapping([1, 3, 2]) + corner3derivs = [2, -1, 3] + else: + lnm = self.local_node_mapping([1, 3, 2]) + corner3derivs = [1, 2, 3] + elif octant_number == 2: + lnm = self.local_node_mapping([3, -1, 2]) + corner3derivs = [-2, 1, 3] + elif octant_number == 3: + lnm = self.local_node_mapping([-1, -3, 2]) + corner3derivs = [-1, -2, 3] + elif octant_number == 4: + lnm = self.local_node_mapping([-3, 1, 2]) + corner3derivs = [2, -1, 3] + else: + lnm = self.local_node_mapping([1, 3, 2]) + corner3derivs = [1, 2, 3] + + if element_type == self.ELEMENT_REGULAR: + pass + elif element_type == self.ELEMENT_QUADRUPLE_DOWN_LEFT: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] @@ -446,23 +585,19 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_DOWN_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.QUADRUPLE0_DOWN_LEFT) - - if e1y == 0: + if e1yo == 0: + self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_13_DOWN) - if e3y == 0: + if e3yo == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) - self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_2_DOWN) self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) - elif element_quadruple_down: - nids[lnm[2 + 1] - 1] = self.nodeId[e3+2][e2][e1] - nids[lnm[6 + 1] - 1] = self.nodeId[e3+2][e2][e1+1] - + elif element_type == self.ELEMENT_QUADRUPLE_DOWN: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] @@ -470,10 +605,9 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_13_DOWN) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_2_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_2_DOWN) - - if e1 == 0: + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) - if e3y == 0: + if e3yo == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) else: @@ -481,44 +615,27 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) - if e3y == 0: + if e3yo == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[1], lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) - - - elif element_quadruple_down_right: - if e2 == 1: - e2r = e2 - 1 - else: - e2r = e2 - - nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2r][e1+1] - nids[lnm[6 + 1] - 1] = self.nodeId[e3+2][e2r][e1+1] - nids[lnm[7 + 1] - 1] = self.nodeId[e3+2][e2+1][e1+1] - + elif element_type == self.ELEMENT_QUADRUPLE_DOWN_RIGHT: eft1 = tricubichermite.createEftNoCrossDerivatives() - if e2 == e2b or e2 == e2z: + if e2o == e2bo or octant_number != 1: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - if self._boxMapping == [-1, 2, 3] or self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2] or self._boxMapping == [-3, 1, 2]\ - or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - - - if e2 == e2b: + if e2o == e2bo: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[3]], self.QUADRUPLE0_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_RIGHT) - if e2b == e2z: + if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) - if e3y == 0: + if e3yo == 0: self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) @@ -526,12 +643,12 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_1_DOWN) self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE_1_DOWN) - elif e2 == e2z: + elif e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE0_1_DOWN) self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_1_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) - if e3y == 0: + if e3yo == 0: self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) else: @@ -542,53 +659,46 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_DOWN) - elif element_quadruple_up_left: - if e2 == 1: - e2r = e2 - 1 - else: - e2r = e2 - nids[lnm[2 + 1] - 1] = self.nodeId[e3+1][e2r][e1] - nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2r][e1+2] - nids[lnm[7 + 1] - 1] = self.nodeId[e3+1][e2+1][e1+2] - + elif element_type == self.ELEMENT_QUADRUPLE_UP_LEFT: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - if e2 == e2b: + if e2o == e2bo: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_2_UP) self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_UP) - if e2b == e2z: - self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) + if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_UP) - if e1y == 0: + if e1yo == 0: + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) else: + self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE_1_UP) - if e1y == 0: + if e1yo == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_13_UP) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.SURFACE_REGULAR_UP) - elif e2 == e2z: + elif e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_UP) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_1_UP) - if e1y == 0: - self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3) + if e1yo == 0: + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_UP) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_UP) else: - if e1y == 0: + if e1yo == 0: self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.BOUNDARY_13_UP) self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_UP) @@ -597,73 +707,59 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_UP) - elif element_quadruple_up: - if e2 == e2b: - e2r = e2 - 1 - else: - e2r = e2 - - nids[lnm[2 + 1] - 1] = self.nodeId[e3+1][e2r][e1] - nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2r][e1+1] - + elif element_type == self.ELEMENT_QUADRUPLE_UP: eft1 = tricubichermite.createEftNoCrossDerivatives() - if e2 == e2b: - + if e2o == e2bo: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - if e1 == 0: + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_13_Up) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_2_UP) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE0_2_UP) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_2_UP) - if e2b == e2z: + if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_UP) - if e1 == 0: + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) - self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) else: - if e1 == 0: + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_13_UP) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.SURFACE_REGULAR_UP) self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_UP) - elif e2 == e2z: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - if e1 == 0: + elif e2o == e2zo: + if octant_number != 2 or e1o == 0: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_UP) - self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_UP) self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_UP) else: - if e1 == 0: + if octant_number != 2 or e1o == 0: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.BOUNDARY_13_UP) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) else: - if self._boxMapping == [1, 3, 2] or self._boxMapping == [-1, 2, 3] or self._boxMapping == [-1, -3, 2] \ - or self._boxMapping == [-3, 1, 2] or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2]: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4], lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) - elif element_quadruple_left: - nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2][e1+2] - nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2][e1+2] - + elif element_type == self.ELEMENT_QUADRUPLE_LEFT: eft1 = tricubichermite.createEftNoCrossDerivatives() - if not self._boxMapping == [-1, 2, 3] and not self._boxMapping == [-3, 1, 2]: + if octant_number != 4: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] @@ -671,10 +767,9 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_3_LEFT) - - if e1y == 0: + if e1yo == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) - if e3 == 0: + if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) @@ -682,25 +777,22 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) - elif element_quadruple_right: - nids[lnm[4 + 1] - 1] = self.nodeId[e3][e2-1][e1+1] - nids[lnm[6 + 1] - 1] = self.nodeId[e3+1][e2-1][e1+1] - + elif element_type == self.ELEMENT_QUADRUPLE_RIGHT: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE0_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_RIGHT) - if e3 == 0: + if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) - if e2b == e2z: + if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) - if e3 == 0: + if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) @@ -708,72 +800,51 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) - elif element_down_right: - if e3 == 0: - if e2 == e2z: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - + elif element_type == self.ELEMENT_DOWN_RIGHT: + eft1 = tricubichermite.createEftNoCrossDerivatives() + if octant_number != 1: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + if e3o == 0: + if e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) else: - if self._boxMapping == [-1, 2, 3] or self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2]\ - or self._boxMapping == [-3, 1, 2] or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2]\ - or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) else: - eft1 = tricubichermite.createEftNoCrossDerivatives() - if self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2] or self._boxMapping == [-3, 1, 2] or e2 == e2z\ - or self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_RIGHT) - if e2 == e2z: + if e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[6], lnm[8]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[6], lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) - elif element_down_left: + elif element_type == self.ELEMENT_DOWN_LEFT: eft1 = tricubichermite.createEftNoCrossDerivatives() - - - if e3 == 0: - if self._boxMapping == [1, 3, 2] or self._boxMapping == [3, -1, 2] or self._boxMapping == [-1, -3, 2] or\ - self._boxMapping == [-3, -1, -2] or self._boxMapping == [-1, 3, -2] or self._boxMapping == [3, 1, -2] or self._boxMapping == [1, -3, -2]: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] + if octant_number != 4: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) - if e1 == 0: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) else: - if e1 == 0 or not self._boxMapping == [-3, 1, 2]: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] self.remap_eft_node_value_label(eft1, [lnm[5], lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) - if e1 == 0: + if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[1], lnm[3]], self.BOUNDARY_13_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[1], lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) - - else: continue @@ -794,46 +865,7 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes return elementIdentifier - def label_map(self): - """ - - :return: - """ - - # [1, 3, 2] -> [-1, 2, 3] - signs = [] - label_mapping = {'xi1': abs(self._boxMapping[0]), 'xi3': abs(self._boxMapping[1]), 'xi2': abs(self._boxMapping[2])} - for c in self._boxMapping: - sign = 1 if c > 0 else -1 - signs.append(sign) - local_nodes_order_signs = {'xi1': signs[0], 'xi3': signs[1], 'xi2': signs[2]} - xi_mapping = {'xi1': []} - - # How to determine new curve labels? from mapping [c1, c3, c2] -> [3, -1, 2] neglect sign - # so c1_label = abs(self._boxMapping[0]), c2_label = abs(self._boxMapping[0]), c3_label = abs(self._boxMapping[0]). - # Note that generally, c1 is not any of d1, d2, d3 but its label is said to be d1, d2, d3 and it means the element axes or xi directions. - # and not nodal d1, d2, d3. So actually fromLabel or curveLabel is an element thing that for each node it is constructed differently. - # now when we have remap(eft, ln, curveLabel, [(m1, [a1]), (m2, [a2]), (m3, [a3])]). Then this can be used for curve - # again if we find new ln, curvelabel and ms and as which describes the same curve again. - # so for a node, if we know mapping curveLabel = label[lm[c1]]. Note that we indirectly do this, i.e. first use - # a second derivative so the values of the derivatives don't get overwritten. - # from nids orders, we should say if the curve direction is changed or not. e.g. if we want the nids follow the same - # order given by boxMapping then for [3, -1, 2] the sign of the c3 has changed to negative, so all the as should be multiplied by -1. - # for all the nodes and their curves that direction is negative. So if we are talking about changes applied to all interior nodes on the box, - # then this means for all of the such nodes, as for c3 should be multiplied by -1. Because nids are consistent, then we do this for all of the nodes not - # just the interior nodes. Note that nids orders and curves directions are applied for all the nodes and elements. - # Now label[lm[c1]] is gonna do this for all of the mappings. I need to store nid_order, so now here we have nid_order_signs = [1, 1, -1] - # i.e. we sf[a1*nid_order_sings[0]], ... - # Now, this was only the effect of changing nids. This is unneccessary and we could ignore this step and always use the same nids. - # Note that if you want to see what order is used in an element, turn on element axes in scaffoldmaker. - # Now, if ms change as well, like here, [m1, m3, m2] -> [3, -1, 2] which means m1 = expressionLabel[1], where expressionLabel = {m1:d3, m3:d1, m2:d2} - # derivative_signs as well if derivative gets negative, for this case derivative_signs = {m1:1, m2:1, m3:-1}. Which then I multiply only a3 by -1. - # This mapping is done only for the nodes on the box, so for such nodes we have expressionLabel and a3X-1. - - - return label_mapping, signs - - def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): + def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE, derivatives=None): """ remaps derivatives for common types of nodes. :return: @@ -844,8 +876,13 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): # lm, signs = self.label_map() xim = self._xi_mapping xis = self._xi_signs - dm = self._deriv_mapping - ds = self._deriv_signs + if derivatives: + dm = {1: abs(derivatives[0]), 2: abs(derivatives[1]), 3: abs(derivatives[2])} + signs = [1 if c > 0 else -1 for c in derivatives] + ds = {1: signs[0], 2: signs[1], 3: signs[2]} + else: + dm = self._deriv_mapping + ds = self._deriv_signs remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D2_DS1DS3, [])]) @@ -860,9 +897,9 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.CORNER_3: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif NODE_TYPE == self.QUADRUPLE_DOWN_LEFT: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) @@ -871,7 +908,7 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) elif NODE_TYPE == self.QUADRUPLE_RIGHT: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) elif NODE_TYPE == self.QUADRUPLE_UP: @@ -904,21 +941,21 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_13_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_13_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap elif NODE_TYPE == self.TRIPLE_23_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.TRIPLE_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.TRIPLE0_12_LEFT: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) @@ -961,22 +998,22 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE): remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif NODE_TYPE == self.BOUNDARY_13_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.BOUNDARY_13_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, [])]) # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif NODE_TYPE == self.BOUNDARY_23_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) elif NODE_TYPE == self.BOUNDARY_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif NODE_TYPE == self.TRIPLE_CURVE_1_DOWN: diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 879f9e1b..ecdaf166 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -16,8 +16,15 @@ class SphereShape(Enum): SPHERE_SHAPE_FULL = 1 - SPHERE_SHAPE_HALF_NNP = 2 # NNP is a3>=3 + SPHERE_SHAPE_HALF_NNP = 2 # NNP is a3>=0 SPHERESHIELD_SHAPE_OCTANT_PPP = 3 + SPHERESHIELD_SHAPE_OCTANT_NPP = 4 + SPHERESHIELD_SHAPE_OCTANT_PNP = 5 + SPHERESHIELD_SHAPE_OCTANT_NNP = 6 + SPHERESHIELD_SHAPE_OCTANT_PPN = 7 + SPHERESHIELD_SHAPE_OCTANT_NPN = 8 + SPHERESHIELD_SHAPE_OCTANT_PNN = 9 + SPHERESHIELD_SHAPE_OCTANT_NNN = 10 class SphereMesh: @@ -25,7 +32,6 @@ class SphereMesh: Sphere mesh generator. """ - def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None): @@ -81,30 +87,323 @@ def createSphereMesh3d(self, fieldModule, coordinates): :param coordinates: Coordinate field to define. :return: Final values of nextNodeIdentifier, nextElementIdentifier. """ - for i in range(3): - assert (self._elementsCount[i] > 1), 'createSphereMesh3d: Invalid number of elements' + # for i in range(3): + # assert (self._elementsCount[i] > 1), 'createSphereMesh3d: Invalid number of elements' # assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ # ' is not an even number' - assert (self._sphereShape in [self._sphereShape.SPHERE_SHAPE_FULL, - self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ - 'createSphereMesh3d: Invalid sphere mode.' + # assert (self._sphereShape in [self._sphereShape.SPHERE_SHAPE_FULL, + # self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ + # 'createSphereMesh3d: Invalid sphere mode.' + + elementsCountRim = self._elementsCountAcrossRim + + if self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + shieldMode = ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: + shieldMode = ShieldShape3D.SHIELD_SHAPE_HALF_NNP + elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: + shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL + + self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode, box_derivatives=[1, 3, 2]) nodes = fieldModule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) mesh = fieldModule.findMeshByDimension(3) + elementsCountAcrossShell = self._elementsCountAcrossShell + elementsCountAcrossTransition = self._elementsCountAcrossTransition + shellProportion = self._shellProportion + + if self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) + octant1 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant1, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) + octant1 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant1, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) + + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP) + octant2 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant2, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP) + + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP) + octant3 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant3, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP) + + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP) + octant4 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant4, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP) + + self.generateNodes(nodes, fieldModule, coordinates) + self.generateElements(mesh, fieldModule, coordinates) + + def get_octant_axes_and_elements_count(self, octant_shape): + """ + + :return: + """ + if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + boxMapping = self._boxMapping + axes = self._axes + elementsCountAcross = [c for c in self._elementsCount] + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: + boxMapping = [self._boxMapping[1], -self._boxMapping[0], self._boxMapping[2]] + axes = [vector.scaleVector(self._axes[1], -1), vector.scaleVector(self._axes[0], 1), self._axes[2]] + elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: + boxMapping = [-self._boxMapping[0], -self._boxMapping[1], self._boxMapping[2]] + axes = [vector.scaleVector(self._axes[0], -1), vector.scaleVector(self._axes[1], -1), self._axes[2]] + elementsCountAcross = [c for c in self._elementsCount] + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: + boxMapping = [-self._boxMapping[1], self._boxMapping[0], self._boxMapping[2]] + axes = [vector.scaleVector(self._axes[1], 1), vector.scaleVector(self._axes[0], -1), self._axes[2]] + elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + else: + raise ValueError("Not implemented.") + + if self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: + elementsCountAcross[0] = elementsCountAcross[0]//2 + elementsCountAcross[1] = elementsCountAcross[1]//2 + + return axes, elementsCountAcross, boxMapping + + def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): + """ + + :param octant: + :return: + """ + # self._shield3D.px = octant._shield3D.px + # self._shield3D.pd1 = octant._shield3D.pd1 + # self._shield3D.pd2 = octant._shield3D.pd2 + # self._shield3D.pd3 = octant._shield3D.pd3 + n3a = 0 + n3z = self._elementsCount[2] + n2a = 0 + n2z = self._elementsCount[0] + n1a = 0 + n1z = self._elementsCount[1] + if self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: + if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + n3a = self._elementsCount[2]//2 + n2z = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 + c11, c21 = -n1a, 1 + c12, c22 = 0, 1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: + n3a = self._elementsCount[2]//2 + n2a = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 + c11, c21 = n1z, -1 + c12, c22 = -n2a, 1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: + n3a = self._elementsCount[2]//2 + n2z = self._elementsCount[0]//2 + n1z = self._elementsCount[1]//2 + c11, c21 = -n1a, 1 + c12, c22 = n2z, -1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: + n3a = self._elementsCount[2]//2 + n2a = self._elementsCount[0]//2 + n1z = self._elementsCount[1]//2 + c11, c21 = n1z, -1 + c12, c22 = n2z, -1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: + n3z = self._elementsCount[2]//2 + n2z = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: + n3z = self._elementsCount[2]//2 + n2a = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: + n3z = self._elementsCount[2]//2 + n2z = self._elementsCount[0]//2 + n1z = self._elementsCount[1]//2 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: + n3z = self._elementsCount[2]//2 + n2a = self._elementsCount[0]//2 + n1z = self._elementsCount[1]//2 + else: + raise ValueError("Not implemented.") + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: + if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + n2z = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 + c11, c21 = -n1a, 1 + c12, c22 = 0, 1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: + n2a = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 + c11, c21 = n1z, -1 + c12, c22 = -n2a, 1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: + n2z = self._elementsCount[0]//2 + n1z = self._elementsCount[1]//2 + c11, c21 = -n1a, 1 + c12, c22 = n2z, -1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: + n2a = self._elementsCount[0]//2 + n1z = self._elementsCount[1]//2 + c11, c21 = n1z, -1 + c12, c22 = n2z, -1 + elif self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + c11, c21 = 0, 1 + c12, c22 = 0, 1 + else: + raise ValueError("Not implemented.") + + for n3 in range(n3a, n3z + 1): + for n2 in range(n2a, n2z + 1): + for n1 in range(n1a, n1z + 1): + n3o, n2o, n1o = self.shield_index_mapping(n3 - n3a, c12 + c22*n2, c11 + c21*n1, octant_shape) + self._shield3D.px[n3][n2][n1] = octant._shield3D.px[n3o][n2o][n1o] + self._shield3D.pd1[n3][n2][n1] = octant._shield3D.pd1[n3o][n2o][n1o] + self._shield3D.pd2[n3][n2][n1] = octant._shield3D.pd2[n3o][n2o][n1o] + self._shield3D.pd3[n3][n2][n1] = octant._shield3D.pd3[n3o][n2o][n1o] + + def shield_index_mapping(self, n3r, n2r, n1r, octant_shape): + """ + + :return: + """ + + if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + n3o, n2o, n1o = n3r, n2r, n1r + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: + n3o, n2o, n1o = n3r, n1r, n2r + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: + n3o, n2o, n1o = n3r, n1r, n2r + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: + n3o, n2o, n1o = n3r, n2r, n1r + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: + n3o, n2o, n1o = n3r, n2r, n1r + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: + n3o, n2o, n1o = n3r, n2r, n1r + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: + n3o, n2o, n1o = n3r, n2r, n1r + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: + n3o, n2o, n1o = n3r, n2r, n1r + else: + raise ValueError("Not implemented.") + + return n3o, n2o, n1o + + def generateNodes(self, nodes, fieldModule, coordinates): + """ + Create cylinder nodes from coordinates. + :param nodes: nodes from coordinates. + :param fieldModule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. + :param coordinates: Coordinate field to define. + """ + nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) + self._startNodeIdentifier = nodeIdentifier + nodeIdentifier = self._shield3D.generateNodes(fieldModule, coordinates, nodeIdentifier) + self._endNodeIdentifier = nodeIdentifier + + def generateElements(self, mesh, fieldModule, coordinates): + """ + Create cylinder elements from nodes. + :param mesh: + :param fieldModule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. + :param coordinates: Coordinate field to define. + """ + elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1) + self._startElementIdentifier = elementIdentifier + elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, []) + self._endElementIdentifier = elementIdentifier + + +class OctantMesh: + """ + Sphere mesh generator. + """ + + def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None): + """ + :param fieldModule: Zinc fieldModule to create elements in. + :param coordinates: Coordinate field to define. + :param centre, axes: centre and axes of the sphere. + :param elementsCountAcross: [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] Total number of elements + across the sphere axes. + :param elementsCountAcrossShell, elementsCountAcrossTransition: Total number of elements across each axis + consists of regular elements in the middle cube, transition elements from cube to a sphere (core boundary) + and shell elements around it. Shell nodes and derivatives are similar to the core boundary and don't need + remapping. The topology of the shield structure is extended to 3D with a quadruple points. + :param sphereShape: A value from enum sphereMode specifying. Octant_PPP for example, is the octant in axis1>=0 + axis2>=0 and axis3>=0 + """ + + self._axes = axes + self._radius = [vector.magnitude(axis) for axis in axes] + self._coreRadius = [] + self._shield = None + self._elementsCount = elementsCountAcross + self._elementsCountAcrossShell = elementsCountAcrossShell + self._elementsCountAcrossTransition = elementsCountAcrossTransition + self._elementsCountAcrossRim = self._elementsCountAcrossShell + self._elementsCountAcrossTransition - 1 + self._shellProportion = shellProportion + self._elementsCountAround12 = 2 * (self._elementsCount[0] + self._elementsCount[1] - + 4*(self._elementsCountAcrossRim + 1)) + self._startNodeIdentifier = 1 + self._startElementIdentifier = 1 + self._endNodeIdentifier = 1 + self._endElementIdentifier = 1 + self._sphereShape = sphereShape + + self._useCrossDerivatives = useCrossDerivatives + + self._centre = centre + + self._boxMapping = boxMapping if boxMapping else [1, 3, 2] + + for i in range(3): + elementsAxis = elementsCountAcross[i] - elementsCountAcrossShell * (1 - shellProportion) + self._coreRadius.append( + (1 - shellProportion * elementsCountAcrossShell / elementsAxis) * self._radius[i]) + + # generate the mesh + self.createOctantMesh3d(fieldModule, coordinates) + + def createOctantMesh3d(self, fieldModule, coordinates): + """ + Create a sphere mesh based on the shield topology. + :param fieldModule: Zinc fieldModule to create elements in. + :param coordinates: Coordinate field to define. + :return: Final values of nextNodeIdentifier, nextElementIdentifier. + """ + # for i in range(3): + # assert (self._elementsCount[i] > 1), 'createSphereMesh3d: Invalid number of elements' + # assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ + # ' is not an even number' + + # assert (self._sphereShape in [self._sphereShape.SPHERE_SHAPE_FULL, + # self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ + # 'createSphereMesh3d: Invalid sphere mode.' + elementsCountRim = self._elementsCountAcrossRim - shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL if self._sphereShape is self._sphereShape.SPHERE_SHAPE_FULL \ - else ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP + # shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL if self._sphereShape is self._sphereShape.SPHERE_SHAPE_FULL \ + # else ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP - self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode) + self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP) self.create_boundary_ellipses_nodes() self.create_surface_and_interior_nodes() - self._shield3D.remap_derivatives(self._boxMapping, circleMapping=None, sphereMapping=None) - self.generateNodes(nodes, fieldModule, coordinates) - self.generateElements(mesh, fieldModule, coordinates) + self._shield3D.set_derivatives(self._boxMapping) def create_boundary_ellipses_nodes(self): """ @@ -149,6 +448,9 @@ def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): Copy coordinates and derivatives of ellipse to shield. :param n3: the index number of ellipse along the central path. """ + n1z = self._elementsCount[1] + n2z = self._elementsCount[0] + n3z = self._elementsCount[2] btx = self._shield3D.px btd1 = self._shield3D.pd1 @@ -174,7 +476,7 @@ def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): btd2[0][n2][n1s] = shield.pd2[0][n2][n1e] btd3[0][n2][n1s] = shield.pd3[0][n2][n1e] elif ellipsenumber == 1: - shield.remap_derivatives([2, 3], circleMapping=None) + shield.remap_derivatives([2, 3], circleMapping=[2, 3]) n2s = self._elementsCount[0] for n3 in range(self._elementsCount[2] + 1): for n1 in range(self._elementsCount[1] + 1): @@ -187,7 +489,7 @@ def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): n1e = n1 + self._elementsCount[1] if n3 == 0: if n1 == self._elementsCount[1]: - btd2[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] + btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] else: btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] else: @@ -197,7 +499,7 @@ def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] btd3[n3][n2s][n1s] = [c for c in shield.pd3[0][n2e][n1e]] elif ellipsenumber == 2: - shield.remap_derivatives([1, -2], circleMapping=None) + shield.remap_derivatives([1, -2], circleMapping=[-2, 3]) n1s = 0 for n3 in range(self._elementsCount[2] + 1): for n2 in range(self._elementsCount[0] + 1): @@ -209,7 +511,7 @@ def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): n1e = self._elementsCount[2] - n3 if n3 == 0: if n2 == 0: - btd2[n3][n2][n1s] = [-c for c in shield.pd1[0][n2][n1e]] + btd2[n3][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] elif 0 < n2 < self._elementsCount[0]: btd2[n3][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] else: @@ -222,7 +524,7 @@ def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): btd3[n3s][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] else: if n3 == self._elementsCount[2]: - btd2[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + btd1[n3][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] else: btd1[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] @@ -295,12 +597,12 @@ def sample_triple_curves_on_sphere(self): n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, index_output=True) n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, cx=1, index_output=True) self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[0] - 1, - [1, None], [1], [-2]) + [1, None], [1], [1]) # curve 2 n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, cx=2, index_output=True) n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, index_output=True) self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[1] - 1, - [2], [-2], [None, -2]) + [1], [-2], [None, -2]) # curve 3. n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, cx=3, index_output=True) n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, index_output=True) @@ -324,7 +626,7 @@ def sample_regular_curves_on_sphere(self): [2], [2], [None, None]) # top self.sample_curves_between_two_nodes_on_sphere([n3z, n2, 0], [n3z, n2, n1z], self._elementsCount[1] - 1, - [2], [-2], [None, -2]) + [1], [-2], [None, -2]) # regular curves crossing curve 2 for n1 in range(1, self._elementsCount[1] - 1): @@ -334,15 +636,15 @@ def sample_regular_curves_on_sphere(self): # smooth regular curves crossing curve 1 for n2 in range(n2a + 1, n2z): - self.smooth_derivatives_regular_surface_curve(2, n2, [[2], [None, None]], [[-2], [-2]], [[None, -2], [-2]]) + self.smooth_derivatives_regular_surface_curve(2, n2, [[1], [None, None]], [[-2], [-2]], [[None, -2], [-2]]) # smooth regular curves crossing curve 2 for n1 in range(1, n1z - 1): - self.smooth_derivatives_regular_surface_curve(1, n1, [[2], [None, None]], [[2], [1]], [[None, 1], [-2]]) + self.smooth_derivatives_regular_surface_curve(1, n1, [[2], [None, None]], [[2], [1]], [[None, 1], [1]]) # smooth regular curves crossing curve 3 for n3 in range(1, self._elementsCount[2] - 1): - self.smooth_derivatives_regular_surface_curve(3, n3, [[2], [None, None]], [[1], [1]], [[None, 1], [-2]]) + self.smooth_derivatives_regular_surface_curve(3, n3, [[1], [None, None]], [[1], [1]], [[None, 1], [1]]) def create_interior_nodes(self): """ @@ -359,7 +661,7 @@ def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStar samples curves on the sphere surface between two points given by their indexes. :param id1, id2: [n3,n2,n1] for the first and second points. :param dStart, dBetween, dEnd: Specifies the derivatives that are used for this curve at the beginning, end and - in between. e.g. dStart=[2, -1, None] means d2 for the first node, -1 for the second node and skip the third one. + in between. e.g. dStart=[2, -1, None] means d2 for the first node, -d1 for the second node and skip the third one. :return: """ btx = self._shield3D.px @@ -799,30 +1101,6 @@ def on_sphere(self, n3, n2, n1): return (n3 == n3z or n2 == 0 or n1 == n1z) and btx[n3][n2][n1] - def generateNodes(self, nodes, fieldModule, coordinates): - """ - Create cylinder nodes from coordinates. - :param nodes: nodes from coordinates. - :param fieldModule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. - :param coordinates: Coordinate field to define. - """ - nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) - self._startNodeIdentifier = nodeIdentifier - nodeIdentifier = self._shield3D.generateNodes(fieldModule, coordinates, nodeIdentifier) - self._endNodeIdentifier = nodeIdentifier - - def generateElements(self, mesh, fieldModule, coordinates): - """ - Create cylinder elements from nodes. - :param mesh: - :param fieldModule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. - :param coordinates: Coordinate field to define. - """ - elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1) - self._startElementIdentifier = elementIdentifier - elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, []) - self._endElementIdentifier = elementIdentifier - def calculate_azimuth(theta, theta_p): """ From 7f7b1ab02aa3311ccf34ea8fd2fda303ba90b26d Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Mon, 4 Oct 2021 13:45:50 +1300 Subject: [PATCH 22/37] Fix bugs for full sphere. --- .../meshtypes/meshtype_3d_solidsphere2.py | 72 ----- src/scaffoldmaker/utils/shieldmesh.py | 270 ++++++++++++++---- src/scaffoldmaker/utils/spheremesh.py | 85 +++++- 3 files changed, 292 insertions(+), 135 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 892bb5bf..aed4add2 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -202,78 +202,6 @@ def generateBaseMesh(region, options): elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=sphere_shape, useCrossDerivatives=False, boxMapping=[1, 3, 2]) - # if (hemisphere or full) and not octant: - # axis1 = [0.0, -1.0, 0.0] - # axis2 = [1.0, 0.0, 0.0] - # axis3 = [0.0, 0.0, 1.0] - # axes = [axis1, axis2, axis3] - # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - # boxMapping = [3, -1, 2] - # sphere2 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - # - # axis1 = [-1.0, 0.0, 0.0] - # axis2 = [0.0, -1.0, 0.0] - # axis3 = [0.0, 0.0, 1.0] - # axes = [axis1, axis2, axis3] - # elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - # boxMapping = [-1, -3, 2] - # # sphere3 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - # # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - # # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - # # - # # axis1 = [0.0, 1.0, 0.0] - # # axis2 = [-1.0, 0.0, 0.0] - # # axis3 = [0.0, 0.0, 1.0] - # # axes = [axis1, axis2, axis3] - # # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - # # boxMapping = [-3, 1, 2] - # # sphere4 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - # # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - # # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - # - # if full and not octant and not hemisphere: - # axis1 = [0.0, 1.0, 0.0] - # axis2 = [1.0, 0.0, 0.0] - # axis3 = [0.0, 0.0, -1.0] - # axes = [axis1, axis2, axis3] - # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - # boxMapping = [-3, -1, -2] - # sphere5 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - # - # axis2 = [0.0, -1.0, 0.0] - # axis1 = [1.0, 0.0, 0.0] - # axis3 = [0.0, 0.0, -1.0] - # axes = [axis1, axis2, axis3] - # elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - # boxMapping = [1, -3, -2] - # sphere6 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - # - # axis2 = [-1.0, 0.0, 0.0] - # axis1 = [0.0, -1.0, 0.0] - # axis3 = [0.0, 0.0, -1.0] - # axes = [axis1, axis2, axis3] - # elementsCountAcross = [elementsCountAcrossAxis2, elementsCountAcrossAxis1, elementsCountAcrossAxis3] - # boxMapping = [3, 1, -2] - # sphere7 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - # - # axis2 = [0.0, 1.0, 0.0] - # axis1 = [-1.0, 0.0, 0.0] - # axis3 = [0.0, 0.0, -1.0] - # axes = [axis1, axis2, axis3] - # elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - # boxMapping = [-1, 3, -2] - # sphere8 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - # elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - # sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - annotationGroup = [] return annotationGroup diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 3e9b945a..9e560002 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -404,8 +404,73 @@ def get_element_type(self, e3, e2, e1): e1zo = self.elementsCountAcross[0]//2 - 1 e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if e3 >= self.elementsCountAcross[2] // 2: + if e2 < self.elementsCountAcross[0] // 2: + if e1 >= self.elementsCountAcross[1] // 2: + octant_number = 1 + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e2, e1 - self.elementsCountAcross[1] // 2 + e3zo = self.elementsCountAcross[2]//2 - 1 + e2zo = self.elementsCountAcross[0] // 2 - 1 + e1zo = self.elementsCountAcross[1] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + else: + octant_number = 2 + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e1, self.elementsCountAcross[0] // 2 - 1 - e2 + e3zo = self.elementsCountAcross[2]//2 - 1 + e2zo = self.elementsCountAcross[1] // 2 - 1 + e1zo = self.elementsCountAcross[0] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + + else: + if e1 < self.elementsCountAcross[1] // 2: + octant_number = 3 + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1] // 2 - 1 - e1 + e3zo = self.elementsCountAcross[2]//2 - 1 + e2zo = self.elementsCountAcross[0] // 2 - 1 + e1zo = self.elementsCountAcross[1] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + else: + octant_number = 4 + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0] // 2 + e3zo = self.elementsCountAcross[2]//2 - 1 + e2zo = self.elementsCountAcross[1] // 2 - 1 + e1zo = self.elementsCountAcross[0] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + else: + if e2 < self.elementsCountAcross[0] // 2: + if e1 >= self.elementsCountAcross[1] // 2: + octant_number = 5 + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[1] - 1 - e1, self.elementsCountAcross[0]//2 - 1 - e2 + e3zo = self.elementsCountAcross[2] //2 - 1 + e2zo = self.elementsCountAcross[1] // 2 - 1 + e1zo = self.elementsCountAcross[0] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + else: + octant_number = 6 + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e2, self.elementsCountAcross[1] // 2 - 1 - e1 + e3zo = self.elementsCountAcross[2] //2 - 1 + e2zo = self.elementsCountAcross[0] // 2 - 1 + e1zo = self.elementsCountAcross[1] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + + else: + if e1 < self.elementsCountAcross[1] // 2: + octant_number = 7 + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e1, e2 - self.elementsCountAcross[0]//2 + e3zo = self.elementsCountAcross[2] //2 - 1 + e2zo = self.elementsCountAcross[1] // 2 - 1 + e1zo = self.elementsCountAcross[0] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + else: + octant_number = 8 + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[0] - 1 - e2, e1 - self.elementsCountAcross[1]//2 + e3zo = self.elementsCountAcross[2] //2 - 1 + e2zo = self.elementsCountAcross[0] // 2 - 1 + e1zo = self.elementsCountAcross[1] // 2 - 1 + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + if e3o <= e3yo and e2o >= e2bo and e1o <= e1yo: - # print('regular', e3, e2, e1, e3o, e2o, e1o, e3yo, e2bo, e1zo) element_type = self.ELEMENT_REGULAR elif e3o == e3yo and e2o == 0 and e1o == e1yo: element_type = self.ELEMENT_QUADRUPLE_DOWN_LEFT @@ -414,7 +479,6 @@ def get_element_type(self, e3, e2, e1): elif e3o == e3zo and e2o >= e2bo and e1o == e1yo: element_type = self.ELEMENT_QUADRUPLE_UP_LEFT elif e3o == e3yo and e2o == 0 and e1o < e1yo: - # print('regular', e3, e2, e1, e3o, e2o, e1o, e3yo, e2bo, e1yo) element_type = self.ELEMENT_QUADRUPLE_DOWN elif e3o == e3zo and e2o >= e2bo and e1o < e1yo: element_type = self.ELEMENT_QUADRUPLE_UP @@ -447,6 +511,23 @@ def get_global_node_index(self, octant_number, n3o, n2o, n1o): n3, n2, n1 = n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o elif octant_number == 4: n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if octant_number == 1: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, n2o, n1o + self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 - n1o, n2o + elif octant_number == 3: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o + elif octant_number == 4: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o + elif octant_number == 5: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0]//2 - n1o, self.elementsCountAcross[1] - n2o + elif octant_number == 6: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n2o, self.elementsCountAcross[1]//2 - n1o + elif octant_number == 7: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n1o + self.elementsCountAcross[0]//2, n2o + elif octant_number == 8: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1]//2 + n1o return n3, n2, n1 @@ -466,6 +547,23 @@ def get_octant_node_index(self, octant_number, n3, n2, n1): n3o, n2o, n1o = n3, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 elif octant_number == 4: n3o, n2o, n1o = n3, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if octant_number == 1: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n2, n1 - self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n1, self.elementsCountAcross[0] // 2 - n2 + elif octant_number == 3: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 + elif octant_number == 4: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 + elif octant_number == 5: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[1] - n1, self.elementsCountAcross[0]//2 - n2 + elif octant_number == 6: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n2, self.elementsCountAcross[1]//2 - n1 + elif octant_number == 7: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n1, n2 - self.elementsCountAcross[0]//2 + elif octant_number == 8: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[0] - n2, n1 - self.elementsCountAcross[1]//2 return n3o, n2o, n1o @@ -502,7 +600,6 @@ def getNodeId(self, octant_number, n3, n2, n1, n3yo, n1yo, n2zo): else: n3r, n2r, n1r = n3, n2, n1 - # print(n3r, n2r, n1r, n3, n2, n1, n3o, n2o, n1o) return self.nodeId[n3r][n2r][n1r] # (1,1,1)->(2,1,1) def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): @@ -546,14 +643,18 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes scalefactors = None octant_number, element_type, e3o, e2o, e1o, e3zo, e2zo, e1zo = self.get_element_type(e3, e2, e1) - # print(octant_number, element_type, e3, e2, e1) e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 nids = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo, e2zo+1)] - # print(e3, e2, e1, nids) + corner1derivs = [1, 2, 3] + corner2derivs = [1, 2, 3] + boundary12leftderivs = [1, 2, 3] + boundary12rightderivs = [1, 2, 3] + triple12leftderivs = [1, 2, 3] + triple12rightderivs = [1, 2, 3] if octant_number == 1: if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: lnm = self.local_node_mapping([1, 3, 2]) @@ -570,6 +671,42 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes elif octant_number == 4: lnm = self.local_node_mapping([-3, 1, 2]) corner3derivs = [2, -1, 3] + elif octant_number == 5: + lnm = self.local_node_mapping([-3, -1, -2]) + corner1derivs = [-1, -2, 3] + corner2derivs = [-1, -2, 3] + corner3derivs = [-1, -2, 3] + boundary12leftderivs = [-1, -2, 3] + boundary12rightderivs = [-1, -2, 3] + triple12leftderivs = [-1, -2, 3] + triple12rightderivs = [-1, -2, 3] + elif octant_number == 6: + lnm = self.local_node_mapping([1, -3, -2]) + corner1derivs = [-1, -2, 3] + corner2derivs = [-1, -2, 3] + corner3derivs = [-2, 1, 3] + boundary12leftderivs = [-1, -2, 3] + boundary12rightderivs = [-1, -2, 3] + triple12leftderivs = [-1, -2, 3] + triple12rightderivs = [-1, -2, 3] + elif octant_number == 7: + lnm = self.local_node_mapping([3, 1, -2]) + corner1derivs = [-1, -2, 3] + corner2derivs = [-1, -2, 3] + corner3derivs = [1, 2, 3] + boundary12leftderivs = [-1, -2, 3] + boundary12rightderivs = [-1, -2, 3] + triple12leftderivs = [-1, -2, 3] + triple12rightderivs = [-1, -2, 3] + elif octant_number == 8: + lnm = self.local_node_mapping([-1, 3, -2]) + corner1derivs = [-1, -2, 3] + corner2derivs = [-1, -2, 3] + corner3derivs = [2, -1, 3] + boundary12leftderivs = [-1, -2, 3] + boundary12rightderivs = [-1, -2, 3] + triple12leftderivs = [-1, -2, 3] + triple12rightderivs = [-1, -2, 3] else: lnm = self.local_node_mapping([1, 3, 2]) corner3derivs = [1, 2, 3] @@ -581,21 +718,28 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_DOWN_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.QUADRUPLE0_DOWN_LEFT) + if e3o == 0: + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT, derivatives=triple12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) + else: + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE_CURVE0_3_LEFT) if e1yo == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_13_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_2_DOWN) - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) + if e3o == 0: + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) + else: + self.remap_eft_node_value_label(eft1, [lnm[1]], self.SURFACE_REGULAR_DOWN_LEFT) elif element_type == self.ELEMENT_QUADRUPLE_DOWN: eft1 = tricubichermite.createEftNoCrossDerivatives() @@ -608,16 +752,16 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1], lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -628,35 +772,47 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes scalefactors = [-1.0] if e2o == e2bo: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[3]], self.QUADRUPLE0_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_RIGHT) + if e3o == 0: + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT, derivatives=triple12rightderivs) + else: + self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_3_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) + if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_1_DOWN) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE_1_DOWN) + if e3yo == 0: + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + else: + self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) + elif e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE0_1_DOWN) self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_1_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) else: self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.TRIPLE_CURVE0_1_DOWN) - self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) + if e3yo == 0: + self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + else: + self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_DOWN) elif element_type == self.ELEMENT_QUADRUPLE_UP_LEFT: @@ -763,19 +919,26 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_3_LEFT) + if e3o == 0: + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT, derivatives=triple12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) + else: + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE_CURVE0_3_LEFT) if e1yo == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) else: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) + if e3o == 0: + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) + else: + self.remap_eft_node_value_label(eft1, [lnm[1]], self.SURFACE_REGULAR_DOWN_LEFT) elif element_type == self.ELEMENT_QUADRUPLE_RIGHT: eft1 = tricubichermite.createEftNoCrossDerivatives() @@ -786,19 +949,22 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_RIGHT) if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT, derivatives=triple12rightderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) + if e3o == 0: + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + else: + self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) elif element_type == self.ELEMENT_DOWN_RIGHT: eft1 = tricubichermite.createEftNoCrossDerivatives() @@ -808,13 +974,13 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if e3o == 0: if e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) else: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) @@ -830,13 +996,13 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, derivatives=boundary12rightderivs) self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) if e1o == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) else: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12rightderivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[5], lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -889,13 +1055,13 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE, derivativ remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS1DS2, [])]) if NODE_TYPE == self.CORNER_1: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) elif NODE_TYPE == self.CORNER_2: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.CORNER_3: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) @@ -932,13 +1098,13 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE, derivativ [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif NODE_TYPE == self.TRIPLE_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) elif NODE_TYPE == self.TRIPLE_12_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.TRIPLE_13_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) @@ -989,13 +1155,13 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE, derivativ [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif NODE_TYPE == self.BOUNDARY_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) elif NODE_TYPE == self.BOUNDARY_12_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif NODE_TYPE == self.BOUNDARY_13_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index ecdaf166..2cbdbf05 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -120,7 +120,40 @@ def createSphereMesh3d(self, fieldModule, coordinates): elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) self.copy_octant_nodes_to_sphere_shield(octant1, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) - elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP or self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: + if self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( + self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN) + octant5 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, + boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant5, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN) + + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( + self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN) + octant6 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, + boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant6, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN) + + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( + self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN) + octant7 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, + boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant7, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN) + + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( + self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN) + octant8 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, + boxMapping=boxMapping) + self.copy_octant_nodes_to_sphere_shield(octant8, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN) + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) octant1 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, @@ -169,12 +202,32 @@ def get_octant_axes_and_elements_count(self, octant_shape): boxMapping = [-self._boxMapping[1], self._boxMapping[0], self._boxMapping[2]] axes = [vector.scaleVector(self._axes[1], 1), vector.scaleVector(self._axes[0], -1), self._axes[2]] elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: + boxMapping = [-self._boxMapping[1], -self._boxMapping[0], -self._boxMapping[2]] + axes = [vector.scaleVector(self._axes[1], 1), vector.scaleVector(self._axes[0], 1), vector.scaleVector(self._axes[2], -1)] + elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: + boxMapping = [self._boxMapping[0], -self._boxMapping[1], -self._boxMapping[2]] + axes = [vector.scaleVector(self._axes[0], 1), vector.scaleVector(self._axes[1], -1), vector.scaleVector(self._axes[2], -1)] + elementsCountAcross = [self._elementsCount[0], self._elementsCount[1], self._elementsCount[2]] + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: + boxMapping = [self._boxMapping[1], self._boxMapping[0], -self._boxMapping[2]] + axes = [vector.scaleVector(self._axes[1], -1), vector.scaleVector(self._axes[0], -1), vector.scaleVector(self._axes[2], -1)] + elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: + boxMapping = [-self._boxMapping[0], self._boxMapping[1], -self._boxMapping[2]] + axes = [vector.scaleVector(self._axes[0], -1), vector.scaleVector(self._axes[1], 1), vector.scaleVector(self._axes[2], -1)] + elementsCountAcross = [self._elementsCount[0], self._elementsCount[1], self._elementsCount[2]] else: raise ValueError("Not implemented.") if self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: elementsCountAcross[0] = elementsCountAcross[0]//2 elementsCountAcross[1] = elementsCountAcross[1]//2 + elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: + elementsCountAcross[0] = elementsCountAcross[0] // 2 + elementsCountAcross[1] = elementsCountAcross[1] // 2 + elementsCountAcross[2] = elementsCountAcross[2] // 2 return axes, elementsCountAcross, boxMapping @@ -184,16 +237,13 @@ def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): :param octant: :return: """ - # self._shield3D.px = octant._shield3D.px - # self._shield3D.pd1 = octant._shield3D.pd1 - # self._shield3D.pd2 = octant._shield3D.pd2 - # self._shield3D.pd3 = octant._shield3D.pd3 n3a = 0 n3z = self._elementsCount[2] n2a = 0 n2z = self._elementsCount[0] n1a = 0 n1z = self._elementsCount[1] + c13, c23 = 0, 1 if self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: n3a = self._elementsCount[2]//2 @@ -201,40 +251,56 @@ def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): n1a = self._elementsCount[1]//2 c11, c21 = -n1a, 1 c12, c22 = 0, 1 + c13, c23 = -self._elementsCount[2]//2, 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: n3a = self._elementsCount[2]//2 n2a = self._elementsCount[0]//2 n1a = self._elementsCount[1]//2 c11, c21 = n1z, -1 c12, c22 = -n2a, 1 + c13, c23 = -self._elementsCount[2] // 2, 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: n3a = self._elementsCount[2]//2 n2z = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 c11, c21 = -n1a, 1 c12, c22 = n2z, -1 + c13, c23 = -self._elementsCount[2] // 2, 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: n3a = self._elementsCount[2]//2 n2a = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 c11, c21 = n1z, -1 c12, c22 = n2z, -1 + c13, c23 = -self._elementsCount[2] // 2, 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: n3z = self._elementsCount[2]//2 n2z = self._elementsCount[0]//2 n1a = self._elementsCount[1]//2 + c11, c21 = n1z, -1 + c12, c22 = n2z, -1 + c13, c23 = self._elementsCount[2] // 2, -1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: n3z = self._elementsCount[2]//2 n2a = self._elementsCount[0]//2 n1a = self._elementsCount[1]//2 + c11, c21 = -n1a, 1 + c12, c22 = n2z, -1 + c13, c23 = self._elementsCount[2] // 2, -1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: n3z = self._elementsCount[2]//2 n2z = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 + c11, c21 = n1z, -1 + c12, c22 = -n2a, 1 + c13, c23 = self._elementsCount[2] // 2, -1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: n3z = self._elementsCount[2]//2 n2a = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 + c11, c21 = n1a, 1 + c12, c22 = -n2a, 1 + c13, c23 = self._elementsCount[2] // 2, -1 else: raise ValueError("Not implemented.") elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: @@ -267,7 +333,7 @@ def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): for n3 in range(n3a, n3z + 1): for n2 in range(n2a, n2z + 1): for n1 in range(n1a, n1z + 1): - n3o, n2o, n1o = self.shield_index_mapping(n3 - n3a, c12 + c22*n2, c11 + c21*n1, octant_shape) + n3o, n2o, n1o = self.shield_index_mapping(c13 + c23*n3, c12 + c22*n2, c11 + c21*n1, octant_shape) self._shield3D.px[n3][n2][n1] = octant._shield3D.px[n3o][n2o][n1o] self._shield3D.pd1[n3][n2][n1] = octant._shield3D.pd1[n3o][n2o][n1o] self._shield3D.pd2[n3][n2][n1] = octant._shield3D.pd2[n3o][n2o][n1o] @@ -288,13 +354,13 @@ def shield_index_mapping(self, n3r, n2r, n1r, octant_shape): elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: n3o, n2o, n1o = n3r, n2r, n1r elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: - n3o, n2o, n1o = n3r, n2r, n1r + n3o, n2o, n1o = n3r, n1r, n2r elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: n3o, n2o, n1o = n3r, n2r, n1r elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: n3o, n2o, n1o = n3r, n2r, n1r elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: - n3o, n2o, n1o = n3r, n2r, n1r + n3o, n2o, n1o = n3r, n1r, n2r else: raise ValueError("Not implemented.") @@ -396,9 +462,6 @@ def createOctantMesh3d(self, fieldModule, coordinates): elementsCountRim = self._elementsCountAcrossRim - # shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL if self._sphereShape is self._sphereShape.SPHERE_SHAPE_FULL \ - # else ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP - self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP) self.create_boundary_ellipses_nodes() From e7fb5ba7855724bfe3e13c0108b134a97a8c815d Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Mon, 4 Oct 2021 19:57:30 +1300 Subject: [PATCH 23/37] Fix sphere centre bug. --- .../meshtypes/meshtype_3d_solidsphere2.py | 15 ++++++- src/scaffoldmaker/utils/spheremesh.py | 42 +++++++++++-------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index aed4add2..58256f26 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -61,9 +61,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements across shell': 0, 'Number of elements across transition': 1, 'Shell element thickness proportion': 1.0, - 'Octant': True, + 'Octant': False, 'Hemisphere': False, - 'Full': False, + 'Full': True, 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements across': 1, @@ -124,6 +124,17 @@ def checkOptions(cls, options): # options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) dependentChanges = False + if options['Octant']: + dependentChanges = True + options['Hemisphere'] = False + options['Full'] = False + else: + if options['Hemisphere']: + dependentChanges = True + options['Full'] = False + else: + options['Full'] = True + if options['Octant']: min1, min2, min3 = 2, 2, 2 co1, co2, co3 = 0, 0, 0 diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 2cbdbf05..b983f255 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -640,7 +640,7 @@ def calculate_surface_quadruple_point(self): x = local_to_global_coordinates(local_x, self._axes, self._centre) - a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2]) + a1, a2, a3 = local_orthogonal_unit_vectors(x, self._axes[2], self._centre) n3r, n2r, n1r = self.get_triple_curves_end_node_parameters(1, index_output=True) btx[n3r][n2r][n1r] = x btd1[n3r][n2r][n1r] = a1 # initialise @@ -749,7 +749,7 @@ def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStar btd = {1: btd1, 2: btd2, 3: btd3} idi = {0: id1[0], 1: id1[1], 2: id1[2]} - nx, nd1 = sample_curves_on_sphere(btx[id1[0]][id1[1]][id1[2]], btx[id2[0]][id2[1]][id2[2]], elementsOut) + nx, nd1 = sample_curves_on_sphere(btx[id1[0]][id1[1]][id1[2]], btx[id2[0]][id2[1]][id2[2]], self._centre, elementsOut) nit = 0 for ni in range(elementsCount + 1): @@ -769,7 +769,7 @@ def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStar else: btx[idi[0]][idi[1]][idi[2]] = nx[nit] - a1, a2, a3 = local_orthogonal_unit_vectors(nx[nit], self._axes[2]) + a1, a2, a3 = local_orthogonal_unit_vectors(nx[nit], self._axes[2], self._centre) btd1[idi[0]][idi[1]][idi[2]] = a1 # initialise btd2[idi[0]][idi[1]][idi[2]] = a2 # initialise btd3[idi[0]][idi[1]][idi[2]] = a3 # initialise @@ -899,8 +899,10 @@ def calculate_interior_quadruple_point(self): n3r, n2r, n1r = self.get_triple_curves_end_node_parameters(1, cx=cx, index_output=True) ts = vector.magnitude(vector.addVectors([btx[n3r0][n2r0][n1r0], btx[n3r][n2r][n1r]], [1, -1])) - ra = vector.magnitude(btx[n3z][0][n1z]) - x = vector.scaleVector(btx[n3z][0][n1z], (1 - ts/ra)) + ra = vector.addVectors([btx[n3z][0][n1z], self._centre], [1, -1]) + radius = vector.magnitude(ra) + local_x = vector.scaleVector(ra, (1 - ts/radius)) + x = vector.addVectors([local_x, self._centre], [1, 1]) n3r0, n2r0, n1r0 = self.get_triple_curves_end_node_parameters(0, index_output=True) n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, index_output=True) btx[n3r0][n2r0][n1r0] = x @@ -1176,14 +1178,15 @@ def calculate_azimuth(theta, theta_p): return math.atan(1/(math.tan(theta_p)*math.cos(theta))) -def local_orthogonal_unit_vectors(x, axis3): +def local_orthogonal_unit_vectors(x, axis3, origin): """ Find local orthogonal unit vectors for a point on a sphere :param x: coordinates of the point. :param axis3: The third axis in Cartesian coordinate system (axis1, axis2, axis3) :return: e1, e2, e3. Unit vectors. e3 is normal to the boundary, e2 is in (e3, axis3) plane and e1 normal to them. """ - e3 = vector.normalise(x) + r = vector.addVectors([x, origin], [1, -1]) + e3 = vector.normalise(r) e2 = vector.vectorRejection(axis3, e3) e2 = vector.normalise(e2) e1 = vector.crossproduct3(e2, e3) @@ -1191,36 +1194,41 @@ def local_orthogonal_unit_vectors(x, axis3): return e1, e2, e3 -def calculate_arc_length(x1, x2): +def calculate_arc_length(x1, x2, origin): """ Calculate the arc length between points x1 and x2. :param x1, x2: points coordinates. :return: arc length """ - radius = vector.magnitude(x1) - angle = vector.angleBetweenVectors(x1, x2) + r1 = vector.addVectors([x1, origin], [1, -1]) + r2 = vector.addVectors([x2, origin], [1, -1]) + radius = vector.magnitude(r1) + angle = vector.angleBetweenVectors(r1, r2) return radius * angle -def sample_curves_on_sphere(x1, x2, elementsOut): +def sample_curves_on_sphere(x1, x2, origin, elementsOut): """ :param x1, x2: points coordinates. :param elementsOut: :return: """ - deltax = vector.addVectors([x1, x2], [-1, 1]) - normal = vector.crossproduct3(x1, deltax) - angle = vector.angleBetweenVectors(x1, x2) + r1 = vector.addVectors([x1, origin], [1, -1]) + r2 = vector.addVectors([x2, origin], [1, -1]) + deltax = vector.addVectors([r1, r2], [-1, 1]) + normal = vector.crossproduct3(r1, deltax) + angle = vector.angleBetweenVectors(r1, r2) anglePerElement = angle/elementsOut - arcLengthPerElement = calculate_arc_length(x1, x2)/elementsOut + arcLengthPerElement = calculate_arc_length(x1, x2, origin)/elementsOut nx = [] nd1 = [] for n1 in range(elementsOut + 1): radiansAcross = n1 * anglePerElement - x = vector.rotateVectorAroundVector(x1, normal, radiansAcross) - d1 = vector.setMagnitude(vector.crossproduct3(normal, x), arcLengthPerElement) + r = vector.rotateVectorAroundVector(r1, normal, radiansAcross) + x = vector.addVectors([r, origin], [1, 1]) + d1 = vector.setMagnitude(vector.crossproduct3(normal, r), arcLengthPerElement) nx.append(x) nd1.append(d1) From 02d3fdd8a356f1a68bfdc5cb0d270ff62faddb00 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Tue, 5 Oct 2021 11:18:24 +1300 Subject: [PATCH 24/37] Add radius options for ellipsoid and spheroid --- .../meshtypes/meshtype_3d_solidsphere2.py | 14 ++++++++- src/scaffoldmaker/utils/spheremesh.py | 29 +++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 58256f26..cd444d40 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -18,6 +18,7 @@ from scaffoldmaker.utils.spheremesh import SphereMesh, SphereShape from scaffoldmaker.utils.cylindermesh import Ellipse2D, EllipseShape from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D +from scaffoldmaker.utils import vector @@ -60,6 +61,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements across axis 3': 2, 'Number of elements across shell': 0, 'Number of elements across transition': 1, + 'Radius1': 1.0, + 'Radius2': 1.0, + 'Radius3': 1.0, 'Shell element thickness proportion': 1.0, 'Octant': False, 'Hemisphere': False, @@ -79,6 +83,9 @@ def getOrderedOptionNames(): 'Number of elements across axis 3', 'Number of elements across shell', 'Number of elements across transition', + 'Radius1', + 'Radius2', + 'Radius3', 'Shell element thickness proportion', 'Octant', 'Hemisphere', @@ -161,6 +168,10 @@ def checkOptions(cls, options): if options['Number of elements across axis 3'] % 2: options['Number of elements across axis 3'] += co3 + for radius in ['Radius1', 'Radius2', 'Radius3', ]: + if options[radius] <= 0: + options[radius] = 1.0 + # if options['Number of elements across transition'] < 1: # options['Number of elements across transition'] = 1 # Rcrit = min(options['Number of elements across major']-4, options['Number of elements across minor']-4)//2 @@ -191,6 +202,7 @@ def generateBaseMesh(region, options): elementsCountAcrossShell = options['Number of elements across shell'] elementsCountAcrossTransition = options['Number of elements across transition'] shellProportion = options['Shell element thickness proportion'] + radius = [options['Radius1'], options['Radius2'], options['Radius3']] useCrossDerivatives = options['Use cross derivatives'] if options['Octant']: sphere_shape = SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP @@ -206,7 +218,7 @@ def generateBaseMesh(region, options): axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] axis3 = [0.0, 0.0, 1.0] - axes = [axis1, axis2, axis3] + axes = [vector.scaleVector(axis1, radius[0]), vector.scaleVector(axis2, radius[1]), vector.scaleVector(axis3, radius[2])] elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index b983f255..3efe9709 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -1,5 +1,5 @@ """ -Utility functions for generating a solid spheroid. +Utility functions for generating a solid sphere/spheroid (ellipsoid in general). """ from enum import Enum @@ -178,9 +178,30 @@ def createSphereMesh3d(self, fieldModule, coordinates): sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) self.copy_octant_nodes_to_sphere_shield(octant4, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP) + self.sphere_to_spheroid() + self.generateNodes(nodes, fieldModule, coordinates) self.generateElements(mesh, fieldModule, coordinates) + def sphere_to_spheroid(self): + """ + + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + for n3 in range(self._elementsCount[2] + 1): + for n2 in range(self._elementsCount[0] + 1): + for n1 in range(self._elementsCount[1] + 1): + if btx[n3][n2][n1]: + btx[n3][n2][n1] = [self._radius[0] * btx[n3][n2][n1][0], self._radius[1] * btx[n3][n2][n1][1], self._radius[2] * btx[n3][n2][n1][2], ] + btd1[n3][n2][n1] = [self._radius[0] * btd1[n3][n2][n1][0], self._radius[1] * btd1[n3][n2][n1][1], self._radius[2] * btd1[n3][n2][n1][2], ] + btd2[n3][n2][n1] = [self._radius[0] * btd2[n3][n2][n1][0], self._radius[1] * btd2[n3][n2][n1][1], self._radius[2] * btd2[n3][n2][n1][2], ] + btd3[n3][n2][n1] = [self._radius[0] * btd3[n3][n2][n1][0], self._radius[1] * btd3[n3][n2][n1][1], self._radius[2] * btd3[n3][n2][n1][2], ] + def get_octant_axes_and_elements_count(self, octant_shape): """ @@ -229,6 +250,7 @@ def get_octant_axes_and_elements_count(self, octant_shape): elementsCountAcross[1] = elementsCountAcross[1] // 2 elementsCountAcross[2] = elementsCountAcross[2] // 2 + axes = [vector.normalise(v) for v in axes] return axes, elementsCountAcross, boxMapping def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): @@ -636,7 +658,7 @@ def calculate_surface_quadruple_point(self): # ratio = -0.1 * (min(self._elementsCount) - 2) + 1 if self._elementsCount[0] <= 2 else 0.2 ratio = 1 # local_x = intersection_of_two_great_circles_on_sphere(btx[0][0][n1y-1], btx[n3z][n2z][n1z], btx[0][2][n1z], btx[n3z][0][0]) - local_x = spherical_to_cartesian(radius, theta_3, ratio * phi_3 + (1-ratio)*math.pi/2) + local_x = spherical_to_cartesian(1.0, theta_3, ratio * phi_3 + (1-ratio)*math.pi/2) x = local_to_global_coordinates(local_x, self._axes, self._centre) @@ -1265,7 +1287,8 @@ def local_to_global_coordinates(local_x, local_axes, local_origin=None): """ if local_origin is None: local_origin = [0.0, 0.0, 0.0] - return vector.addVectors([vector.addVectors(local_axes, local_x), local_origin]) + normalised_axes = [vector.normalise(v) for v in local_axes] + return vector.addVectors([vector.addVectors(normalised_axes, local_x), local_origin]) def intersection_of_two_great_circles_on_sphere(p1, q1, p2, q2): From 040af1f35249d921eb006eb05a1611689a752f18 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 6 Oct 2021 11:36:29 +1300 Subject: [PATCH 25/37] Fix minor bugs and tidy up. --- .../meshtypes/meshtype_3d_solidsphere2.py | 22 +- src/scaffoldmaker/utils/shieldmesh.py | 2770 ++++++++--------- src/scaffoldmaker/utils/spheremesh.py | 626 ++-- 3 files changed, 1609 insertions(+), 1809 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index cd444d40..24d50e80 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -1,5 +1,5 @@ """ -Generates a solid sphere using a ShieldMesh of all cube elements, +Generates a solid sphere (spheroid/ellipsoid in general) using a ShieldMesh of all cube elements, with variable numbers of elements across axes and shell directions. """ @@ -9,19 +9,15 @@ from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.utils.meshrefinement import MeshRefinement -# from scaffoldmaker.utils.cylindermesh import CylinderMesh, CylinderShape, CylinderEnds, CylinderCentralPath from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 from opencmiss.zinc.node import Node from opencmiss.zinc.field import Field from scaffoldmaker.utils.spheremesh import SphereMesh, SphereShape -from scaffoldmaker.utils.cylindermesh import Ellipse2D, EllipseShape -from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D from scaffoldmaker.utils import vector - class MeshType_3d_solidsphere2(Scaffold_base): """ Generates a solid sphere using a ShieldMesh of all cube elements, @@ -56,9 +52,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): # centralPathOption = cls.centralPathDefaultScaffoldPackages['Cylinder 1'] options = { # 'Central path': copy.deepcopy(centralPathOption), - 'Number of elements across axis 1': 2, - 'Number of elements across axis 2': 2, - 'Number of elements across axis 3': 2, + 'Number of elements across axis 1': 4, + 'Number of elements across axis 2': 4, + 'Number of elements across axis 3': 4, 'Number of elements across shell': 0, 'Number of elements across transition': 1, 'Radius1': 1.0, @@ -81,12 +77,12 @@ def getOrderedOptionNames(): 'Number of elements across axis 1', 'Number of elements across axis 2', 'Number of elements across axis 3', - 'Number of elements across shell', - 'Number of elements across transition', + # 'Number of elements across shell', + # 'Number of elements across transition', 'Radius1', 'Radius2', 'Radius3', - 'Shell element thickness proportion', + # 'Shell element thickness proportion', 'Octant', 'Hemisphere', 'Full', @@ -207,7 +203,7 @@ def generateBaseMesh(region, options): if options['Octant']: sphere_shape = SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP elif options['Hemisphere']: - sphere_shape = SphereShape.SPHERE_SHAPE_HALF_NNP + sphere_shape = SphereShape.SPHERE_SHAPE_HALF_AAP else: sphere_shape = SphereShape.SPHERE_SHAPE_FULL @@ -223,7 +219,7 @@ def generateBaseMesh(region, options): sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=sphere_shape, useCrossDerivatives=False, boxMapping=[1, 3, 2]) + sphereShape=sphere_shape, useCrossDerivatives=False) annotationGroup = [] return annotationGroup diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 9e560002..802b2200 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -27,8 +27,15 @@ class ShieldShape2D(Enum): class ShieldShape3D(Enum): SHIELD_SHAPE_FULL = 1 - SHIELD_SHAPE_HALF_NNP = 2 # NNP is a3>=3 - SHIELD_SHAPE_OCTANT_PPP = 3 # in a right hand coordinate system (a1,a2,a3), PPP means a1>=0, a2>=0 and a3>=0 + SHIELD_SHAPE_HALF_AAP = 2 # AAP is a hemisphere where x_a3>=0 + SHIELD_SHAPE_OCTANT_PPP = 3 # PPP means positive axis1, positive axis2, positive axis3. + SHIELD_SHAPE_OCTANT_PNP = 4 + SHIELD_SHAPE_OCTANT_NNP = 5 + SHIELD_SHAPE_OCTANT_NPP = 6 + SHIELD_SHAPE_OCTANT_PPN = 7 + SHIELD_SHAPE_OCTANT_PNN = 8 + SHIELD_SHAPE_OCTANT_NNN = 9 + SHIELD_SHAPE_OCTANT_NPN = 10 class ShieldRimDerivativeMode(Enum): @@ -36,111 +43,365 @@ class ShieldRimDerivativeMode(Enum): SHIELD_RIM_DERIVATIVE_MODE_REGULAR = 2 # rim derivatives d1, d2 match interior nodes for regular elements -class ShieldMesh3D: - """ - Generates a 3D shield mesh. - """ +class ShieldMesh2D: + ''' + Shield mesh generator. + ''' - def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP, box_derivatives=None): - """ - 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the centre. - The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a unique node on the - surface where the elements merge. 'Triple curves' meet at the quadruple point and a fourth curve that connects - to another quadruple point which is inside. - The structure is like a elementsCountAcross[0] X elementsCountAcross[1] X elementsCountAcross[2] box where - some nodes does not exist and stored as None. The quadruple point is stored at [n3z][0][n1z] (top, front and right most node) - where n3z is top most and n1z is the right most indexes. - Triple curves and surfaces connecting to the quadruple point divide the exterior surface and interior region into 3 regions - (top, left and right). Triple curve 1 connects the quadruple point to the plane 2-3. Similarly, triple curves 2 and 3 - connect the quadruple point to the planes 1-3 and 1-2, respectively. It is the same for the inside quadruple. - Any point on region left has n2 = 0. Similarly on region right -> n1 = n1z and on top -> n3 = n3z. - There is a gap between node indexes of a node on a triple curve and the next nodes on the surface. + def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, trackSurface : TrackSurface=None, + elementsCountAlong=1, shieldMode=ShieldShape2D.SHIELD_SHAPE_LOWER_HALF, shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR): + ''' + Data structure for defining a shield-shaped mesh which is flat on the top and rounded around the bottom + and/or the same mirror mirrored on top. + It is represented as a regular box of elementsCountAcross x elementsCountUp + but with strips of elements absent on the bottom left and right. + Example showing elements for 4 across, 2 up and 0 rim, and how nodes/coordinates are stored in ShieldMesh: - :param elementsCountAcross: number of elements as a list [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] - :param elementsCountRim: - :param shieldMode: TODO should it be only Octant_PPP? - """ + N___N___N___N___N N___N___N___N___N + | | | | | | | | + | | | | | | | | + \ T---N---T / --> T---N---T + \ / | \ / | | | + N | N | | | + \----N----/ N---N---N + + The removal of 2 corners of the box is achieved by triple points T where 3 square elements + join in a triangle. + Extra rim elements go around the sides and bottom curve. Rim elements add nodes on the sides above the + triple points, and across the shorter bottom row. + Extra elements up add regular rows of nodes/elements on top, and extra non-rim elements across + add regular columns of nodes/elements up the centre. + :param elementsCountAcross: Number of elements across top of shield. Must be at least 4 + 2*elementsCountRim. + :param elementsCountUpFull: Number of elements up central axis of shield. Must be at least 2 + elementsCountRim if half and 4 + 2*elementsCountRim if full. + :param elementsCountAlong: Number of elements through wall for ventricle case (only 1 element is supported) and along cylinder axis in cylinder case. + :param elementsCountRim: Number of elements around bottom rim (not top) outside of 'triple points'. + :param trackSurface: Optional trackSurface to store or restrict points to. + :param shieldMode: It determines if the shield is full or just part of it. + :param shieldType: To distinguish between cylinder and ventricle type. Derivatives and directions are chosen differently for two cases. + ''' assert elementsCountRim >= 0 - # assert elementsCountAlong >= 1 - # assert elementsCountAcross >= (elementsCountRim + 4) - # assert elementsCountUpFull >= (elementsCountRim + 2) + assert elementsCountAlong >= 1 + assert elementsCountAcross >= (elementsCountRim + 4) + assert elementsCountUpFull >= (elementsCountRim + 2) self.elementsCountAcross = elementsCountAcross - - # self.elementsCountUpFull = elementsCountUpFull - # elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL else elementsCountUpFull - # self.elementsCountUp = elementsCountUp + self.elementsCountUpFull = elementsCountUpFull + elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL else elementsCountUpFull + self.elementsCountUp = elementsCountUp self.elementsCountRim = elementsCountRim - # self.elementsCountAlong = elementsCountAlong - # self.elementsCountUpRegular = elementsCountUp - 2 - elementsCountRim - # elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim - # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim - self._shieldMode = shieldMode - self._boxDerivatives = box_derivatives - - self.px = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.pd1 = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.pd2 = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.pd3 = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.nodeId = [ [] for _ in range(elementsCountAcross[2] + 1) ] - for n3 in range(elementsCountAcross[2] + 1): - for n2 in range(elementsCountAcross[0] + 1): + self.elementsCountAlong = elementsCountAlong + self.elementsCountUpRegular = elementsCountUp - 2 - elementsCountRim + elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim + self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim + self.trackSurface = trackSurface + self._mode = shieldMode + self._type = shieldType + self.px = [ [] for _ in range(elementsCountAlong+1) ] + self.pd1 = [ [] for _ in range(elementsCountAlong+1) ] + self.pd2 = [ [] for _ in range(elementsCountAlong+1) ] + self.pd3 = [ [] for _ in range(elementsCountAlong+1) ] + self.nodeId = [ [] for _ in range(elementsCountAlong+1) ] + for n3 in range(elementsCountAlong+1): + for n2 in range(elementsCountUpFull + 1): for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: - p.append([ None ]*(elementsCountAcross[1] + 1)) - - self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] + p.append([ None ]*(elementsCountAcross + 1)) + if trackSurface: + self.pProportions = [ [ None ]*(elementsCountAcross + 1) for n2 in range(elementsCountUp + 1) ] + if shieldType == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + self.elementId = [ [[ None ]*elementsCountAcross for n2 in range(elementsCountUpFull)] for e3 in range(elementsCountAlong) ] + else: + self.elementId = [[None] * elementsCountAcross for n2 in range(elementsCountUpFull)] - def set_derivatives(self, box_derivatives): - """ - Set the derivatives as specified by box_derivatives and circleMapping. - :param box_derivatives: List[d_axis1_negative, d_axis2, d_axis3]. Determines what derivatives should be - for back, right and up directions in the box region. Their values are in [1,2,3] range which 1, 2, 3 means - d1, d2 and d3 respectively. - The negative sign reverses the direction. e.g. [1, -3,2] means for the right direction use -d3. Default is [1,3, 2]. - :return: - """ - self._boxMapping = box_derivatives + def convertRimIndex(self, ix, rx=0): + ''' + Convert point index around the lower rim to n1, n2 across and up box. + :param ix: index around from 0 to self.elementsCountAroundFull + :param rx: rim index from 0 (around outside) to self.elementsCountRim + :return: n1, n2 + ''' + assert 0 <= ix <= self.elementsCountAroundFull + assert 0 <= rx <= self.elementsCountRim + if ix <= self.elementsCountUpRegular: + return rx, self.elementsCountUp - ix + mx = self.elementsCountAroundFull - ix + if mx <= self.elementsCountUpRegular: + return self.elementsCountAcross - rx, self.elementsCountUp - mx + return self.elementsCountRim + ix - self.elementsCountUpRegular, rx - dct = {1: self.pd1, 2: self.pd2, 3: self.pd3} - perm = {(1, 2): -3, (2, 3): -1, (3, 1): -2, (3, 2): 1, (1, 3): 2, (2, 1): 3} - if box_derivatives: - signs = [] - for c in box_derivatives: - sign = 1 if c > 0 else -1 - signs.append(sign) + def getTriplePoints(self, n3): + ''' + Compute coordinates and derivatives of points where 3 square elements merge. + :param n3: Index of through-wall coordinates to use. + ''' + n1a = self.elementsCountRim + n1b = n1a + 1 + n1c = n1a + 2 + m1a = self.elementsCountAcross - self.elementsCountRim + m1b = m1a - 1 + m1c = m1a - 2 + n2a = self.elementsCountRim + n2b = n2a + 1 + n2c = n2a + 2 + # left + ltx = [] - dervMapping = (abs(box_derivatives[0]), abs(box_derivatives[1]), abs(box_derivatives[2])) + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + tx, td1 = sampleCubicHermiteCurves( + [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]],[[(-self.pd1[n3][n2a][n1c][c] - self.pd3[n3][n2a][n1c][c]) for c in range(3)], self.pd1[n3][n2c][n1b]],2, arcLengthDerivatives=True)[0:2] + ltx.append(tx[1]) + # tx, td1 = sampleCubicHermiteCurves( + # [ self.px[n3][n2a][n1b], self.px[n3][n2c][n1c] ], [ [-self.pd3[n3][n2a][n1b][c] for c in range(3)], [ (self.pd1[n3][n2c][n1c][c] + self.pd3[n3][n2c][n1c][c]) for c in range(3) ] ], 2, arcLengthDerivatives = True)[0:2] + ltx.append(tx[1]) + tx, td1 = sampleCubicHermiteCurves( + [ self.px[n3][n2c][n1a], self.px[n3][n2b][n1c] ], [ [ (self.pd1[n3][n2c][n1a][c] - self.pd3[n3][n2c][n1a][c]) for c in range(3) ], self.pd3[n3][n2b][n1c] ], 2, arcLengthDerivatives = True)[0:2] + ltx.append(tx[1]) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + tx, td1 = sampleCubicHermiteCurves( + [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]], [[(-self.pd1[n3][n2a][n1c][c] + self.pd2[n3][n2a][n1c][c]) for c in range(3)],self.pd2[n3][n2c][n1b]], 2, arcLengthDerivatives = True)[0: 2] + ltx.append(tx[1]) + tx, td1 = sampleCubicHermiteCurves( + [self.px[n3][n2a][n1b], self.px[n3][n2c][n1c]], [self.pd2[n3][n2a][n1b], [(self.pd1[n3][n2c][n1c][c] + self.pd2[n3][n2c][n1c][c]) for c in range(3)]], 2, arcLengthDerivatives = True)[0: 2] + ltx.append(tx[1]) + tx, td1 = sampleCubicHermiteCurves( + [self.px[n3][n2c][n1a], self.px[n3][n2b][n1c]], [[(self.pd1[n3][n2c][n1a][c] - self.pd2[n3][n2c][n1a][c]) for c in range(3)], self.pd1[n3][n2b][n1c]], 2, arcLengthDerivatives = True)[0: 2] + ltx.append(tx[1]) + #x = [ (ltx[0][c] + ltx[1][c] + ltx[2][c])/3.0 for c in range(3) ] + x = [ (ltx[0][c] + ltx[2][c])/2.0 for c in range(3) ] + if self.trackSurface: + p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*(self.pProportions[n2b][n1c]))) + self.pProportions[n2b][n1b] = self.trackSurface.getProportion(p) + x, sd1, sd2 = self.trackSurface.evaluateCoordinates(p, derivatives=True) + d1, d2, d3 = calculate_surface_axes(sd1, sd2, vector.normalise(sd1)) + self.pd3[n3][n2b][n1b] = d3 + self.px [n3][n2b][n1b] = x + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + self.pd3[n3][n2b][n1b] = [ (self.px[n3][n2b][n1c][c] - self.px[n3][n2b][n1b][c]) for c in range(3) ] + self.pd1[n3][n2b][n1b] = [ (self.px[n3][n2c][n1b][c] - self.px[n3][n2b][n1b][c]) for c in range(3) ] + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + self.pd1[n3][n2b][n1b] = [(self.px[n3][n2b][n1c][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] + self.pd2[n3][n2b][n1b] = [(self.px[n3][n2c][n1b][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] + if not self.trackSurface: + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + self.pd2[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][n1b], self.pd1[n3][n2b][n1b])) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + self.pd3[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][n1b], self.pd2[n3][n2b][n1b])) + # right + rtx = [] + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + tx, td1 = sampleCubicHermiteCurves( + [ self.px[n3][n2a][m1c], self.px[n3][n2c][m1b] ], [ [ (self.pd1[n3][n2a][m1c][c] - self.pd3[n3][n2a][m1c][c]) for c in range(3) ], self.pd1[n3][n2c][m1b] ], 2, arcLengthDerivatives = True)[0:2] + rtx.append(tx[1]) + # tx, td1 = sampleCubicHermiteCurves( + # [ self.px[n3][n2a][m1b], self.px[n3][n2c][m1c] ], [ [-self.pd3[n3][n2a][m1b][c] for c in range(3)], [ (-self.pd3[n3][n2c][m1c][c] + self.pd1[n3][n2c][m1c][c]) for c in range(3) ] ], 2, arcLengthDerivatives = True)[0:2] + rtx.append(tx[1]) + tx, td1 = sampleCubicHermiteCurves( + [ self.px[n3][n2c][m1a], self.px[n3][n2b][m1c] ], [ [ (-self.pd1[n3][n2c][m1a][c] - self.pd3[n3][n2c][m1a][c]) for c in range(3) ], [ -d for d in self.pd3[n3][n2b][m1c] ] ], 2, arcLengthDerivatives = True)[0:2] + rtx.append(tx[1]) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + tx, td1 = sampleCubicHermiteCurves( + [self.px[n3][n2a][m1c], self.px[n3][n2c][m1b]], [[(self.pd1[n3][n2a][m1c][c] + self.pd2[n3][n2a][m1c][c]) for c in range(3)],self.pd2[n3][n2c][m1b]], 2, arcLengthDerivatives = True)[0: 2] + rtx.append(tx[1]) + tx, td1 = sampleCubicHermiteCurves( + [self.px[n3][n2a][m1b], self.px[n3][n2c][m1c]], [self.pd2[n3][n2a][m1b], [(-self.pd1[n3][n2c][m1c][c] + self.pd2[n3][n2c][m1c][c]) for c in range(3)]], 2, arcLengthDerivatives = True)[0: 2] + rtx.append(tx[1]) + tx, td1 = sampleCubicHermiteCurves( + [self.px[n3][n2c][m1a], self.px[n3][n2b][m1c]], [[(-self.pd1[n3][n2c][m1a][c] - self.pd2[n3][n2c][m1a][c]) for c in range(3)],[-d for d in self.pd1[n3][n2b][m1c]]], 2, arcLengthDerivatives = True)[0: 2] + rtx.append(tx[1]) + #x = [ (rtx[0][c] + rtx[1][c] + rtx[2][c])/3.0 for c in range(3) ] + x = [ (rtx[0][c] + rtx[2][c])/2.0 for c in range(3) ] + if self.trackSurface: + p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*(self.pProportions[n2b][m1c]))) + self.pProportions[n2b][m1b] = self.trackSurface.getProportion(p) + x, sd1, sd2 = self.trackSurface.evaluateCoordinates(p, derivatives=True) + d1, d2, d3 = calculate_surface_axes(sd1, sd2, vector.normalise(sd1)) + self.pd3[n3][n2b][m1b] = d3 + self.px [n3][n2b][m1b] = x + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + self.pd3[n3][n2b][m1b] = [ (self.px[n3][n2b][m1b][c] - self.px[n3][n2b][m1c][c]) for c in range(3) ] + self.pd1[n3][n2b][m1b] = [ (self.px[n3][n2c][m1b][c] - self.px[n3][n2b][m1b][c]) for c in range(3) ] + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + self.pd1[n3][n2b][m1b] = [(self.px[n3][n2b][m1b][c] - self.px[n3][n2b][m1c][c]) for c in range(3)] + self.pd2[n3][n2b][m1b] = [(self.px[n3][n2c][m1b][c] - self.px[n3][n2b][m1b][c]) for c in range(3)] + if not self.trackSurface: + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + self.pd2[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][m1b], self.pd1[n3][n2b][m1b])) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + self.pd3[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][m1b], self.pd2[n3][n2b][m1b])) - temp1 = copy.deepcopy(self.pd3) - temp2 = copy.deepcopy(self.pd2) - for n3 in range(self.elementsCountAcross[2] + 1): - for n2 in range(self.elementsCountAcross[0] + 1): - for n1 in range(self.elementsCountAcross[1] + 1): - if self.px[n3][n2][n1]: - if self.is_interior_regular_nodes(n3, n2, n1): - dct[dervMapping[0]][n3][n2][n1] = [signs[0] * c for c in self.pd1[n3][n2][n1]] - dct[dervMapping[1]][n3][n2][n1] = [signs[1] * c for c in temp1[n3][n2][n1]] - dct[dervMapping[2]][n3][n2][n1] = [signs[2] * c for c in temp2[n3][n2][n1]] - def is_interior_regular_nodes(self, n3, n2, n1): - """ - Determine if a node indicated by [n3,n2,n1], is inside the sphere. - :return: - """ - n3z = self.elementsCountAcross[2] - n1z = self.elementsCountAcross[1] - n2z = self.elementsCountAcross[0] - n3y = n3z - 1 + def smoothDerivativesToTriplePoints(self, n3, fixAllDirections=False): + ''' + Smooth derivatives leading to triple points where 3 square elements merge. + :param n3: Index of through-wall coordinates to use. + ''' + n1a = self.elementsCountRim + n1b = n1a + 1 + n1z = self.elementsCountAcross - self.elementsCountRim n1y = n1z - 1 + m1a = self.elementsCountAcross - self.elementsCountRim + m1b = m1a - 1 + n2a = self.elementsCountRim + n2b = n2a + 1 + n2c = n2a + 2 + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + # left + tx = [] + td3 = [] + for n2 in range(n2c): + tx.append(self.px[n3][n2][n1b]) + if n2 < n2b: + td3.append([-self.pd3[n3][n2][n1b][c] for c in range(3)]) + else: + td3.append([(self.pd1[n3][n2b][n1b][c] + self.pd3[n3][n2b][n1b][c]) for c in range(3)] ) - return n3 <= n3y and n2 >= 1 and n1 <= n1y - - def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier): + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + + for n2 in range(n2b): + self.pd3[n3][n2][n1b] = [-td3[n2][c] for c in range(3)] + + # right + tx = [] + td3 = [] + for n2 in range(n2c): + tx.append(self.px[n3][n2][n1y]) + if n2 < n2b: + td3.append([-self.pd3[n3][n2][n1y][c] for c in range(3)]) + else: + td3.append([(self.pd1[n3][n2b][n1y][c] - self.pd3[n3][n2b][n1y][c]) for c in range(3)]) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + + for n2 in range(n2b): + self.pd3[n3][n2][n1y] = [-td3[n2][c] for c in range(3)] + + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + # left + tx = [] + td2 = [] + for n2 in range(0, n2c): + tx .append(self.px [n3][n2][n1b]) + td2.append(self.pd2[n3][n2][n1b] if (n2 < n2b) else [(self.pd1[n3][n2][n1b][c] + self.pd2[n3][n2][n1b][c]) for c in range(3)]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections, fixEndDerivative=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) + for n2 in range(0, n2b): + self.pd2[n3][n2][n1b] = td2[n2] + # right + tx = [] + td2 = [] + for n2 in range(0, n2c): + tx .append(self.px [n3][n2][m1b]) + td2.append(self.pd2[n3][n2][m1b] if (n2 < n2b) else [(-self.pd1[n3][n2][m1b][c] + self.pd2[n3][n2][m1b][c]) for c in range(3)]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections,fixEndDerivative=True,magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) + for n2 in range(0, n2b): + self.pd2[n3][n2][m1b] = td2[n2] + + def smoothDerivativesAroundRim(self, n3, n3d=None, rx=0): + ''' + Smooth derivatives around rim. + :param n3: Index of through-wall coordinates to use. + :param n3d: Which n3 index to copy initial derivatives from. If None, use n3. + :param rx: rim index from 0 (around outside) to self.elementsCountRim + ''' + assert 0 <= rx <= self.elementsCountRim + if not n3d: + n3d = n3 + tx = [] + td1 = [] + for ix in range(self.elementsCountAroundFull + 1): + n1, n2 = self.convertRimIndex(ix, rx) + tx.append(self.px[n3][n2][n1]) + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + td1.append(self.pd1[n3d][n2][n1]) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + if n2 > self.elementsCountRim: # regular rows + if n1 <= self.elementsCountRim: + td1.append([ -d for d in self.pd2[n3d][n2][n1] ]) + else: + td1.append(self.pd2[n3d][n2][n1]) + else: + td1.append(self.pd1[n3d][n2][n1]) + + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + td1 = smoothCubicHermiteDerivativesLine(tx, td1) + + for ix in range(self.elementsCountAroundFull + 1): + n1, n2 = self.convertRimIndex(ix, rx) + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + self.pd1[n3][n2][n1] = td1[ix] + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + if n2 > self.elementsCountRim: # regular rows + if n1 <= self.elementsCountRim: + self.pd2[n3][n2][n1] = [ -d for d in td1[ix] ] + else: + self.pd2[n3][n2][n1] = td1[ix] + else: + self.pd1[n3][n2][n1] = td1[ix] + + def remap_derivatives(self, squareMapping, circleMapping=None): + """ + It remaps the derivatives as indicated by squareMapping and circleMapping. Limited to SHIELD_RIM_DERIVATIVE_MODE_AROUND. + :param squareMapping: List[up, right]. Determines what derivatives should be in the up and right directions in the + square part. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. + The negative sign reverses the direction. e.g. [-3,2] means d3 is down and d2 is right. The third derivative + is determined by the other two. RH rule applied. Assumes [1,3] initially. + :param circleMapping: List[circumferential, radial]. Determines what derivatives should be used for + circumferential and radial directions around the circle. + [-1, 3] means d1 -> clockwise and around. d3 -> outward and radial. Assumes [1,3] initially. + :return: + """ + dct = {1: self.pd1, 2: self.pd2, 3: self.pd3} + perm = {(1, 2): -3, (2, 3): -1, (3, 1): -2, (3, 2): 1, (1, 3): 2, (2, 1): 3} + + square = True + tripleRow = [self.elementsCountRim + 1, self.elementsCountUpFull - (self.elementsCountRim + 1)] + ellipseMapping = [squareMapping, circleMapping] + for mapping in ellipseMapping: + if mapping: + signs = [] + for c in mapping: + sign = 1 if c > 0 else -1 + signs.append(sign) + derv = (abs(mapping[0]), abs(mapping[1])) + sign = 1 if perm[derv] > 0 else -1 + signs.append(signs[0]*signs[1]*sign) + dervMapping = (derv[0], derv[1], abs(perm[derv])) + temp1 = copy.deepcopy(self.pd3) + temp2 = copy.deepcopy(self.pd2) + for n2 in range(self.elementsCountUpFull + 1): + for n3 in range(self.elementsCountAlong+1): + for n1 in range(self.elementsCountAcross + 1): + if self.px[n3][n2][n1]: + is_on_square = ((self.px[n3][n2][0] and self.px[n3][0][n1]) or n2 in tripleRow) + if (is_on_square and square) or (not is_on_square and not square): + dct[dervMapping[0]][n3][n2][n1] = [signs[0]*c for c in self.pd1[n3][n2][n1]] + dct[dervMapping[1]][n3][n2][n1] = [signs[1]*c for c in temp1[n3][n2][n1]] + dct[dervMapping[2]][n3][n2][n1] = [signs[2]*c for c in temp2[n3][n2][n1]] + square = False + + def generateNodesForOtherHalf(self, mirrorPlane): + """ + Generates coordinates and derivatives for the other half by mirroring them. It keeps the d1 direction. + :param mirrorPlane: plane ax+by+cz=d in form of [a,b,c,d] + :return: + """ + mirror=Mirror(mirrorPlane) + for n2 in range(self.elementsCountUp): + for n3 in range(self.elementsCountAlong + 1): + for n1 in range(self.elementsCountAcross + 1): + if self.px[n3][n2][n1]: + self.px[n3][2*self.elementsCountUp-n2][n1] = mirror.mirrorImageOfPoint(self.px[n3][n2][n1]) + self.pd1[n3][2*self.elementsCountUp-n2][n1] = mirror.reverseMirrorVector(self.pd1[n3][n2][n1]) + 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): """ 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 mirrorPlane: mirror plane ax+by+cz=d in form of [a,b,c,d] :return: next nodeIdentifier. """ nodeIdentifier = startNodeIdentifier @@ -151,15 +412,20 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier): 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_D_DS3, 1) - # In case we swap derivatives in the when we use remap function. - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) cache = fieldmodule.createFieldcache() - for n2 in range(self.elementsCountAcross[0] + 1): - for n3 in range(self.elementsCountAcross[2] + 1): - for n1 in range(self.elementsCountAcross[1] + 1): + #for n2 in range(self.elementsCountUp, -1, -1): + # s = "" + # for n1 in range(self.elementsCountAcross + 1): + # s += str(n1) if self.px[1][n2][n1] else " " + # print(n2, s, n2 - self.elementsCountUp - 1) + + if self._mode == ShieldShape2D.SHIELD_SHAPE_FULL and mirrorPlane: + self.generateNodesForOtherHalf(mirrorPlane) + + for n2 in range(self.elementsCountUpFull + 1): + for n3 in range(self.elementsCountAlong+1): + for n1 in range(self.elementsCountAcross + 1): if self.px[n3][n2][n1]: node = nodes.createNode(nodeIdentifier, nodetemplate) self.nodeId[n3][n2][n1] = nodeIdentifier @@ -172,469 +438,548 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier): return nodeIdentifier - # node types - CORNER_1 = 1 - CORNER_2 = 2 - CORNER_3 = 3 - - QUADRUPLE_DOWN_LEFT = 4 - QUADRUPLE_RIGHT = 5 - QUADRUPLE_UP = 6 - QUADRUPLE0_DOWN_LEFT = 7 - QUADRUPLE0_RIGHT = 8 - QUADRUPLE0_UP = 9 - - TRIPLE_12_LEFT = 10 - TRIPLE_12_RIGHT = 11 - TRIPLE_13_DOWN = 12 - TRIPLE_13_UP = 13 - TRIPLE_23_UP = 14 - TRIPLE_23_DOWN = 15 - TRIPLE0_12_LEFT = 16 - TRIPLE0_12_RIGHT = 17 - TRIPLE0_13_DOWN = 18 - TRIPLE0_13_Up = 19 - TRIPLE0_23_DOWN = 20 - TRIPLE0_23_UP = 21 - - BOUNDARY_12_LEFT = 22 - BOUNDARY_12_RIGHT = 23 - BOUNDARY_13_DOWN = 24 - BOUNDARY_13_UP = 25 - BOUNDARY_23_UP = 26 - BOUNDARY_23_DOWN = 27 - TRIPLE_CURVE_1_DOWN = 28 - TRIPLE_CURVE_1_UP = 29 - TRIPLE_CURVE_2_DOWN = 30 - TRIPLE_CURVE_2_UP = 31 - TRIPLE_CURVE_3_LEFT = 32 - TRIPLE_CURVE_3_RIGHT = 33 - TRIPLE_CURVE0_1_UP = 34 - TRIPLE_CURVE0_1_DOWN = 35 - TRIPLE_CURVE0_2_DOWN = 36 - TRIPLE_CURVE0_2_UP = 37 - TRIPLE_CURVE0_3_LEFT = 38 - TRIPLE_CURVE0_3_RIGHT = 39 + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, 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 meshGroups: Zinc mesh groups to add elements to. + :return: next elementIdentifier. + """ + elementIdentifier = startElementIdentifier + useCrossDerivatives = False + mesh = fieldmodule.findMeshByDimension(3) - SURFACE_REGULAR_DOWN_LEFT = 40 - SURFACE_REGULAR_DOWN_RIGHT = 41 - SURFACE_REGULAR_UP = 42 - REGULAR = 43 + tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) + eft = tricubichermite.createEftNoCrossDerivatives() + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) + elementtemplate.defineField(coordinates, -1, eft) - # element types - ELEMENT_REGULAR = 1 - ELEMENT_QUADRUPLE_DOWN_LEFT = 2 - ELEMENT_QUADRUPLE_DOWN_RIGHT = 3 - ELEMENT_QUADRUPLE_UP_LEFT = 4 - ELEMENT_QUADRUPLE_DOWN = 5 - ELEMENT_QUADRUPLE_UP = 6 - ELEMENT_QUADRUPLE_LEFT = 7 - ELEMENT_QUADRUPLE_RIGHT = 8 - ELEMENT_DOWN_RIGHT = 9 - ELEMENT_DOWN_LEFT = 10 + elementtemplate1 = mesh.createElementtemplate() + elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) - def local_node_mapping(self, boxMapping): - """ - - :return: - """ - # How to determine new curve labels? from mapping [c1, c3, c2] -> [3, -1, 2] neglect sign - # so c1_label = abs(self._boxMapping[0]), c2_label = abs(self._boxMapping[0]), c3_label = abs(self._boxMapping[0]). - # Note that generally, c1 is not any of d1, d2, d3 but its label is said to be d1, d2, d3 and it means the element axes or xi directions. - # and not nodal d1, d2, d3. So actually fromLabel or curveLabel is an element thing that for each node it is constructed differently. - - # now when we have remap(eft, ln, curveLabel, [(m1, [a1]), (m2, [a2]), (m3, [a3])]). Then this can be used for curve - # again if we find new ln, curvelabel and ms and as which describes the same curve again. - # so for a node, if we know mapping curveLabel = label[lm[c1]]. Note that we indirectly do this, i.e. first use - # a second derivative so the values of the derivatives don't get overwritten. - - # from nids orders, we should say if the curve direction is changed or not. e.g. if we want the nids follow the same - # order given by boxMapping then for [3, -1, 2] the sign of the c3 has changed to negative, so all the as should be multiplied by -1. - # for all the nodes and their curves that direction is negative. So if we are talking about changes applied to all interior nodes on the box, - # then this means for all of the such nodes, as for c3 should be multiplied by -1. Because nids are consistent, then we do this for all of the nodes not - # just the interior nodes. Note that nids orders and curves directions are applied for all the nodes and elements. - # Now label[lm[c1]] is gonna do this for all of the mappings. I need to store nid_order, so now here we have nid_order_signs = [1, 1, -1] - # i.e. we sf[a1*nid_order_sings[0]], ... - # Now, this was only the effect of changing nids. This is unneccessary and we could ignore this step and always use the same nids. - # However, because we want the second octant be consistent with the first octant, then element axes also should be consistent then we need - # to change the order of nodes to achieve that. the order of node is always the same as boxMapping. - # Note that if you want to see what order is used in an element, turn on element axes in scaffoldmaker. - # Now, if ms change as well, like here, [m1, m3, m2] -> [3, -1, 2] which means m1 = expressionLabel[1], where expressionLabel = {m1:d3, m3:d1, m2:d2} - # derivative_signs as well if derivative gets negative, for this case derivative_signs = {m1:1, m2:1, m3:-1}. Which then I multiply only a3 by -1. - # This mapping is done only for the nodes on the box, so for such nodes we have expressionLabel and a3X-1. - #[1, 3, 2] -> [-1, 2, 3] - - # Ok, now how to obtain nids from given boxMapping? - # - boxMapping_default = [1, 3, 2] + isEven = (self.elementsCountAcross % 2) == 0 + e1a = self.elementsCountRim + e1b = e1a + 1 + e1z = self.elementsCountAcross - 1 - self.elementsCountRim + e1y = e1z - 1 + e2a = self.elementsCountRim + e2b = self.elementsCountRim + 1 + e2c = self.elementsCountRim + 2 + e2z = 2*self.elementsCountUp-1-self.elementsCountRim + e2y = e2z - 1 + e2x = e2z - 2 + for e3 in range(self.elementsCountAlong): + for e2 in range(self.elementsCountUpFull): + for e1 in range(self.elementsCountAcross): + eft1 = eft + scalefactors = None + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2 + 1][e1], + self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3+1][e2][e1 + 1], self.nodeId[e3+1][e2 + 1][e1 + 1] ] + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + nids = [self.nodeId[0][e2][e1], self.nodeId[0][e2][e1 + 1], self.nodeId[0][e2 + 1][e1],self.nodeId[0][e2 + 1][e1 + 1], + self.nodeId[1][e2][e1], self.nodeId[1][e2][e1 + 1], self.nodeId[1][e2 + 1][e1], self.nodeId[1][e2 + 1][e1 + 1]] + if (e2 < e2b) or (e2 > e2y): + if (e1 < e1b) or (e1 > e1y): + continue # no element due to triple point closure + if (e2 < e2a) or (e2 > e2z): + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + if e2 < e2a: + nids = [self.nodeId[e3][e2+1][e1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3+1][e2+1][e1+1], + self.nodeId[e3][e2][e1], self.nodeId[e3][e2][e1+1], self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2][e1+1]] + elif e2 > e2z: + nids = [self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2][e1], self.nodeId[e3+1][e2][e1+1], self.nodeId[e3+1][e2][e1], + self.nodeId[e3][e2+1][e1+1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2+1][e1+1], self.nodeId[e3+1][e2+1][e1]] + elif (e2 == e2a) or (e2 == e2z): + # bottom and top row elements + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + if e2 == e2a: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [])]) + if (e1 == e1b) or (e1 == e1y): + # map bottom triple point element + if e1 == e1b: + remapEftNodeValueLabel(eft1, [ 2, 4 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [] ), ( Node.VALUE_LABEL_D_DS3, [] ) ]) + else: + remapEftNodeValueLabel(eft1, [ 6, 8 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [] ), ( Node.VALUE_LABEL_D_DS3, [1] ) ]) + elif e2 == e2z: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS3, [])]) + if (e1 == e1b) or (e1 == e1y): + # map top triple point element + if e1 == e1b: + remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) + else: + remapEftNodeValueLabel(eft1, [5, 7], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS3, [])]) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + if (e1 == e1b) or (e1 == e1y): + # map bottom triple point element + eft1 = tricubichermite.createEftNoCrossDerivatives() + if e1 == e1b: + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [])]) + else: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [1]),(Node.VALUE_LABEL_D_DS2, [])]) - signs = [] - xi_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} - for di in range(3): - sign = 1 if boxMapping[di]*boxMapping_default[di] > 0 else -1 - signs.append(sign) - xi_sign_change = [signs[0], signs[2], signs[1]] + elif (e2 == e2b) or (e2 == e2y): + if (e1 <= e1a) or (e1 >= e1z): + if e1 < e1a: + e2r = e1 + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + if e2 == e2b: + nids = [self.nodeId[e3][e2c][e1+1], self.nodeId[e3][e2r+1][e1b], self.nodeId[e3+1][e2c][e1+1], self.nodeId[e3+1][e2r+1][e1b], + self.nodeId[e3][e2c][e1], self.nodeId[e3][e2r][e1b], self.nodeId[e3+1][e2c][e1], self.nodeId[e3+1][e2r][e1b]] + if e2 == e2y: + e2r = 2*self.elementsCountUp - e1-1 + nids = [self.nodeId[e3][e2r][e1b], self.nodeId[e3][e2y][e1+1], self.nodeId[e3+1][e2r][e1b], self.nodeId[e3+1][e2y][e1+1], + self.nodeId[e3][e2r+1][e1b], self.nodeId[e3][e2y][e1], self.nodeId[e3+1][e2r+1][e1b], self.nodeId[e3+1][e2y][e1]] + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + nids[0] = self.nodeId[0][e2r ][e1b] + nids[1] = self.nodeId[0][e2r + 1][e1b] + nids[4] = self.nodeId[1][e2r ][e1b] + nids[5] = self.nodeId[1][e2r + 1][e1b] + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [ -1.0 ] + remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS2, [ ( Node.VALUE_LABEL_D_DS1, [1] ) ]) + remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS2, [] ) ]) + elif e1 == e1a: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [ -1.0 ] + if e2 == e2b: + nids[0] = self.nodeId[e3][e2a][e1b] + nids[2] = self.nodeId[e3+1][e2a][e1b] + tripleN = [5, 7] + remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [])]) + elif e2 == e2y: + nids[1] = self.nodeId[e3][e2z+1][e1b] + nids[3] = self.nodeId[e3+1][e2z+1][e1b] + tripleN = [6, 8] + remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [ 1, 2, 3, 4 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [1] ) ]) + remapEftNodeValueLabel(eft1, [ 1, 2, 3, 4 ], Node.VALUE_LABEL_D_DS3, [ ( Node.VALUE_LABEL_D_DS3, [1] ) ]) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [ -1.0 ] + nids[0] = self.nodeId[0][e2a][e1b] + nids[4] = self.nodeId[1][e2a][e1b] + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [])]) + elif e1 == e1z: + eft1 = tricubichermite.createEftNoCrossDerivatives() + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + if e2 == e2b: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + nids[4] = self.nodeId[e3][e2a][e1z] + nids[6] = self.nodeId[e3+1][e2a][e1z] + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [ -1.0 ] + remapEftNodeValueLabel(eft1, [ 1, 3 ], Node.VALUE_LABEL_D_DS3, [ ( Node.VALUE_LABEL_D_DS1, [1] ), ( Node.VALUE_LABEL_D_DS3, [] ) ]) + elif e2 == e2y: + nids[5] = self.nodeId[e3][e2z+1][e1z] + nids[7] = self.nodeId[e3+1][e2z+1][e1z] + remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [])]) + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + nids[1] = self.nodeId[0][e2a][e1z] + nids[5] = self.nodeId[1][e2a][e1z] + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [])]) + elif e1 > e1z: + e2r = self.elementsCountAcross - e1 + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + if e2 == e2b: + nids = [self.nodeId[e3][e2r][e1z], self.nodeId[e3][e2c][e1], self.nodeId[e3+1][e2r][e1z], self.nodeId[e3+1][e2c][e1], + self.nodeId[e3][e2r-1][e1z], self.nodeId[e3][e2c][e1+1], self.nodeId[e3+1][e2r-1][e1z], self.nodeId[e3+1][e2c][e1+1]] + elif e2 == e2y: + e2r = e2z+e1-e1z + nids[1] = self.nodeId[e3][e2r][e1z] + nids[3] = self.nodeId[e3+1][e2r][e1z] + nids[5] = self.nodeId[e3][e2r+1][e1z] + nids[7] = self.nodeId[e3+1][e2r+1][e1z] + elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [-1.0] + nids[0] = self.nodeId[0][e2r ][e1z] + nids[1] = self.nodeId[0][e2r - 1][e1z] + nids[4] = self.nodeId[1][e2r ][e1z] + nids[5] = self.nodeId[1][e2r - 1][e1z] + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [ -1.0 ] + remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS2, [1] ) ]) + remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS2, [ ( Node.VALUE_LABEL_D_DS1, [] ) ]) + else: + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + if e1 < e1a: + nids = [ self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3][e2][e1 + 1], self.nodeId[e3+1][e2 + 1][e1 + 1], self.nodeId[e3+1][e2][e1 + 1], + self.nodeId[e3][e2 + 1][e1], self.nodeId[e3][e2][e1], self.nodeId[e3+1][e2 + 1][e1], self.nodeId[e3+1][e2][e1]] + elif e1 == e1a: + # map left column elements + eft1 = tricubichermite.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + scalefactors = [ -1.0 ] + remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS3, [1])]) - xi_node_map = {(0, 0, 0): 1, (1, 0, 0): 2, (0, 1, 0): 3, (1, 1, 0): 4, - (0, 0, 1): 5, (1, 0, 1): 6, (0, 1, 1): 7, (1, 1, 1): 8} - node_xi_map = {1: (0, 0, 0), 2: (1, 0, 0), 3: (0, 1, 0), 4: (1, 1, 0), - 5: (0, 0, 1), 6: (1, 0, 1), 7: (0, 1, 1), 8: (1, 1, 1)} + if eft1 is not eft: + elementtemplate1.defineField(coordinates, -1, eft1) + element = mesh.createElement(elementIdentifier, elementtemplate1) + else: + element = mesh.createElement(elementIdentifier, elementtemplate) + result2 = element.setNodesByIdentifier(eft1, nids) + if scalefactors: + result3 = element.setScaleFactors(eft1, scalefactors) + else: + result3 = 7 + #print('create element shield', elementIdentifier, result2, result3, nids) + if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: + self.elementId[e3][e2][e1] = elementIdentifier + else: + self.elementId[e2][e1] = elementIdentifier + elementIdentifier += 1 - lnm = {} - for ln in range(1, 9): - xi_l = [] - xi = [node_xi_map[ln][xi_map['xi1'] - 1], node_xi_map[ln][xi_map['xi2'] - 1], node_xi_map[ln][xi_map['xi3'] - 1]] - signs = [xi_sign_change[xi_map['xi1'] - 1], xi_sign_change[xi_map['xi2'] - 1], xi_sign_change[xi_map['xi3'] - 1]] - for i in range(3): - if signs[i] > 0: - xi_l.append(xi[i]) - else: - xi_l.append(1 - xi[i]) - lnm[ln] = xi_node_map[tuple(xi_l)] + for meshGroup in meshGroups: + meshGroup.addElement(element) - signs = [] - deriv_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} - for di in range(3): - sign = 1 if boxMapping[di]*boxMapping_default[di] > 0 else -1 - signs.append(sign) - deriv_sign_change = [signs[0], signs[2], signs[1]] + return elementIdentifier - self._xi_mapping = {1: xi_map['xi1'], 2: xi_map['xi2'], 3: xi_map['xi3']} - self._xi_signs = {1: xi_sign_change[0], 2: xi_sign_change[1], 3: xi_sign_change[2]} - self._deriv_mapping = {1: deriv_map['xi1'], 2: deriv_map['xi2'], 3: deriv_map['xi3']} - self._deriv_signs = {1: deriv_sign_change[0], 2: deriv_sign_change[1], 3: deriv_sign_change[2]} - self._local_node_mapping = lnm - - # nids_default = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3 + 1][e2][e1], self.nodeId[e3 + 1][e2 + 1][e1], - # self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3 + 1][e2][e1 + 1], self.nodeId[e3 + 1][e2 + 1][e1 + 1]] - # nids = [None] * 8 - # for i in range(1, 9): - # nids[lnm[i]-1] = (nids_default[i - 1]) - - - # lnm = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8} - # if self._boxMapping == [-1, 2, 3]: - # lnm = {1: 2, 2: 1, 3: 6, 4: 5, 5: 4, 6: 3, 7: 8, 8: 7} - # if self._boxMapping == [3, -1, 2]: - # lnm = {1: 2, 2: 6, 3: 4, 4: 8, 5: 1, 6: 5, 7: 3, 8: 7} - - # px_default = [self.px[e3][e2][e1], self.px[e3][e2 + 1][e1], self.px[e3 + 1][e2][e1], self.px[e3 + 1][e2 + 1][e1], - # self.px[e3][e2][e1 + 1], self.px[e3][e2 + 1][e1 + 1], self.px[e3 + 1][e2][e1 + 1], self.px[e3 + 1][e2 + 1][e1 + 1]] - # pd1_default = [self.pd1[e3][e2][e1], self.pd1[e3][e2 + 1][e1], self.pd1[e3 + 1][e2][e1], self.pd1[e3 + 1][e2 + 1][e1], - # self.pd1[e3][e2][e1 + 1], self.pd1[e3][e2 + 1][e1 + 1], self.pd1[e3 + 1][e2][e1 + 1], self.pd1[e3 + 1][e2 + 1][e1 + 1]] - # pd2_default = [self.pd2[e3][e2][e1], self.pd2[e3][e2 + 1][e1], self.pd2[e3 + 1][e2][e1], self.pd2[e3 + 1][e2 + 1][e1], - # self.pd2[e3][e2][e1 + 1], self.pd2[e3][e2 + 1][e1 + 1], self.pd2[e3 + 1][e2][e1 + 1], self.pd2[e3 + 1][e2 + 1][e1 + 1]] - # pd3_default = [self.pd3[e3][e2][e1], self.pd3[e3][e2 + 1][e1], self.pd3[e3 + 1][e2][e1], self.pd3[e3 + 1][e2 + 1][e1], - # self.pd3[e3][e2][e1 + 1], self.pd3[e3][e2 + 1][e1 + 1], self.pd3[e3 + 1][e2][e1 + 1], self.pd3[e3 + 1][e2 + 1][e1 + 1]] - - # px = [] - # pd1 = [] - # pd2 = [] - # pd3 = [] - - # px.append(px_default[lnm[i] - 1]) - # pd1.append(pd1_default[lnm[i] - 1]) - # pd2.append(pd2_default[lnm[i] - 1]) - # pd3.append(pd3_default[lnm[i] - 1]) - - # npd1 = [] - # for ln in range(0, 8, 2): - # npd1.append(vector.addVectors([px[ln+1], px[ln]], [1, -1])) - # npd1.append(vector.addVectors([px[ln+1], px[ln]], [1, -1])) - # - # npd2 = [] - # for ln in range(8): - # lne = ln % 2 + (ln//4)*4 - # npd2.append(vector.addVectors([px[lne + 2], px[lne]], [1, -1])) - # - # npd3 = [] - # for ln in range(8): - # lne = ln % 4 - # npd3.append(vector.addVectors([px[lne + 4], px[lne]], [1, -1])) - # - # #TODO if any np.nd1 <0 scale factor is needed - # for ln in range(8): - # s1 = vector.dotproduct(npd1[ln], pd1[ln]) - return lnm +class ShieldMesh3D: + """ + Generates a 3D shield mesh. + """ - def get_element_type(self, e3, e2, e1): + def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP, box_derivatives=None): """ + 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the centre. + The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a unique node on the + surface where the elements merge. 'Triple curves' meet at the quadruple point and a fourth curve that connects + to another quadruple point which is inside. + The structure is like a elementsCountAcross[0] X elementsCountAcross[1] X elementsCountAcross[2] box where + some nodes does not exist and stored as None. The quadruple point is stored at [n3z][0][n1z] (top, front and right most node) + where n3z is top most and n1z is the right most indexes. + Triple curves and surfaces connecting to the quadruple point divide the exterior surface and interior region into 3 regions + (top, left and right). Triple curve 1 connects the quadruple point to the plane 2-3. Similarly, triple curves 2 and 3 + connect the quadruple point to the planes 1-3 and 1-2, respectively. It is the same for the inside quadruple. + Any point on region left has n2 = 0. Similarly on region right -> n1 = n1z and on top -> n3 = n3z. + There is a gap between node indexes of a node on a triple curve and the next nodes on the surface. - :return: + :param elementsCountAcross: number of elements as a list [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + :param elementsCountRim: + :param shieldMode: It can be full or just a section of the whole shield. """ - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - octant_number = 1 - e3o, e2o, e1o = e3, e2, e1 - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[0] - 1 - e1zo = self.elementsCountAcross[1] - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_NNP: - if e2 < self.elementsCountAcross[0]//2: - if e1 >= self.elementsCountAcross[1]//2: - octant_number = 1 - e3o, e2o, e1o = e3, e2, e1 - self.elementsCountAcross[1]//2 - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[0]//2 - 1 - e1zo = self.elementsCountAcross[1]//2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - else: - octant_number = 2 - e3o, e2o, e1o = e3, e1, self.elementsCountAcross[0]//2 - 1 - e2 - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[1]//2 - 1 - e1zo = self.elementsCountAcross[0]//2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - - else: - if e1 < self.elementsCountAcross[1]//2: - octant_number = 3 - e3o, e2o, e1o = e3, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1]//2 - 1 - e1 - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[0]//2 - 1 - e1zo = self.elementsCountAcross[1]//2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - else: - octant_number = 4 - e3o, e2o, e1o = e3, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0]//2 - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[1]//2 - 1 - e1zo = self.elementsCountAcross[0]//2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if e3 >= self.elementsCountAcross[2] // 2: - if e2 < self.elementsCountAcross[0] // 2: - if e1 >= self.elementsCountAcross[1] // 2: - octant_number = 1 - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e2, e1 - self.elementsCountAcross[1] // 2 - e3zo = self.elementsCountAcross[2]//2 - 1 - e2zo = self.elementsCountAcross[0] // 2 - 1 - e1zo = self.elementsCountAcross[1] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - else: - octant_number = 2 - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e1, self.elementsCountAcross[0] // 2 - 1 - e2 - e3zo = self.elementsCountAcross[2]//2 - 1 - e2zo = self.elementsCountAcross[1] // 2 - 1 - e1zo = self.elementsCountAcross[0] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - - else: - if e1 < self.elementsCountAcross[1] // 2: - octant_number = 3 - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1] // 2 - 1 - e1 - e3zo = self.elementsCountAcross[2]//2 - 1 - e2zo = self.elementsCountAcross[0] // 2 - 1 - e1zo = self.elementsCountAcross[1] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - else: - octant_number = 4 - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0] // 2 - e3zo = self.elementsCountAcross[2]//2 - 1 - e2zo = self.elementsCountAcross[1] // 2 - 1 - e1zo = self.elementsCountAcross[0] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - else: - if e2 < self.elementsCountAcross[0] // 2: - if e1 >= self.elementsCountAcross[1] // 2: - octant_number = 5 - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[1] - 1 - e1, self.elementsCountAcross[0]//2 - 1 - e2 - e3zo = self.elementsCountAcross[2] //2 - 1 - e2zo = self.elementsCountAcross[1] // 2 - 1 - e1zo = self.elementsCountAcross[0] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - else: - octant_number = 6 - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e2, self.elementsCountAcross[1] // 2 - 1 - e1 - e3zo = self.elementsCountAcross[2] //2 - 1 - e2zo = self.elementsCountAcross[0] // 2 - 1 - e1zo = self.elementsCountAcross[1] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - - else: - if e1 < self.elementsCountAcross[1] // 2: - octant_number = 7 - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e1, e2 - self.elementsCountAcross[0]//2 - e3zo = self.elementsCountAcross[2] //2 - 1 - e2zo = self.elementsCountAcross[1] // 2 - 1 - e1zo = self.elementsCountAcross[0] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - else: - octant_number = 8 - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[0] - 1 - e2, e1 - self.elementsCountAcross[1]//2 - e3zo = self.elementsCountAcross[2] //2 - 1 - e2zo = self.elementsCountAcross[0] // 2 - 1 - e1zo = self.elementsCountAcross[1] // 2 - 1 - e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + assert elementsCountRim >= 0 + # assert elementsCountAcross >= (elementsCountRim + 4) + # assert elementsCountUpFull >= (elementsCountRim + 2) + self.elementsCountAcross = elementsCountAcross + self.elementsCountRim = elementsCountRim + # self.elementsCountUpRegular = elementsCountUp - 2 - elementsCountRim + # elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim + # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim + self._shieldMode = shieldMode + self._boxDerivatives = box_derivatives - if e3o <= e3yo and e2o >= e2bo and e1o <= e1yo: - element_type = self.ELEMENT_REGULAR - elif e3o == e3yo and e2o == 0 and e1o == e1yo: - element_type = self.ELEMENT_QUADRUPLE_DOWN_LEFT - elif e3o == e3yo and e2o >= e2bo and e1o == e1zo: - element_type = self.ELEMENT_QUADRUPLE_DOWN_RIGHT - elif e3o == e3zo and e2o >= e2bo and e1o == e1yo: - element_type = self.ELEMENT_QUADRUPLE_UP_LEFT - elif e3o == e3yo and e2o == 0 and e1o < e1yo: - element_type = self.ELEMENT_QUADRUPLE_DOWN - elif e3o == e3zo and e2o >= e2bo and e1o < e1yo: - element_type = self.ELEMENT_QUADRUPLE_UP - elif e3o < e3yo and e2o == 0 and e1o == e1yo: - element_type = self.ELEMENT_QUADRUPLE_LEFT - elif e3o < e3yo and e2o == e2bo and e1o == e1zo: - element_type = self.ELEMENT_QUADRUPLE_RIGHT - elif e3o < e3yo and e2o > e2bo and e1o == e1zo: - element_type = self.ELEMENT_DOWN_RIGHT - elif e3o < e3yo and e2o == 0 and e1o < e1yo: - element_type = self.ELEMENT_DOWN_LEFT - else: - element_type = 0 + self.px = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.pd1 = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.pd2 = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.pd3 = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.nodeId = [ [] for _ in range(elementsCountAcross[2] + 1) ] + for n3 in range(elementsCountAcross[2] + 1): + for n2 in range(elementsCountAcross[0] + 1): + for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: + p.append([ None ]*(elementsCountAcross[1] + 1)) - return octant_number, element_type, e3o, e2o, e1o, e3zo, e2zo, e1zo + self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] - def get_global_node_index(self, octant_number, n3o, n2o, n1o): + def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier): """ + 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. + :return: next nodeIdentifier. + """ + nodeIdentifier = startNodeIdentifier + nodes = fieldmodule.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) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + # In case we swap derivatives in the when we use remap function. + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) + cache = fieldmodule.createFieldcache() - :return: - """ - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - n3, n2, n1 = n3o, n2o, n1o - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_NNP: - if octant_number == 1: - n3, n2, n1 = n3o, n2o, n1o + self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 - n1o, n2o - elif octant_number == 3: - n3, n2, n1 = n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o - elif octant_number == 4: - n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if octant_number == 1: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, n2o, n1o + self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 - n1o, n2o - elif octant_number == 3: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o - elif octant_number == 4: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o - elif octant_number == 5: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0]//2 - n1o, self.elementsCountAcross[1] - n2o - elif octant_number == 6: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n2o, self.elementsCountAcross[1]//2 - n1o - elif octant_number == 7: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n1o + self.elementsCountAcross[0]//2, n2o - elif octant_number == 8: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1]//2 + n1o + for n2 in range(self.elementsCountAcross[0] + 1): + for n3 in range(self.elementsCountAcross[2] + 1): + for n1 in range(self.elementsCountAcross[1] + 1): + if self.px[n3][n2][n1]: + node = nodes.createNode(nodeIdentifier, nodetemplate) + self.nodeId[n3][n2][n1] = nodeIdentifier + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, self.px [n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, self.pd1[n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, self.pd2[n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, self.pd3[n3][n2][n1]) + nodeIdentifier += 1 - return n3, n2, n1 + return nodeIdentifier - def get_octant_node_index(self, octant_number, n3, n2, n1): + def set_derivatives(self, box_derivatives): """ - + Set the derivatives as specified by box_derivatives. + :param box_derivatives: List[d_axis1_negative, d_axis2, d_axis3]. Determines what derivatives should be + for back, right and up directions in the box region. Their values are in [1,2,3] range which 1, 2, 3 means + d1, d2 and d3 respectively. + The negative sign reverses the direction. e.g. [1, -3,2] means for the right direction use -d3. Default is [1,3, 2]. :return: """ - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - n3o, n2o, n1o = n3, n2, n1 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_NNP: - if octant_number == 1: - n3o, n2o, n1o = n3, n2, n1 - self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3o, n2o, n1o = n3, n1, self.elementsCountAcross[0] // 2 - n2 - elif octant_number == 3: - n3o, n2o, n1o = n3, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 - elif octant_number == 4: - n3o, n2o, n1o = n3, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if octant_number == 1: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n2, n1 - self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n1, self.elementsCountAcross[0] // 2 - n2 - elif octant_number == 3: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 - elif octant_number == 4: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 - elif octant_number == 5: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[1] - n1, self.elementsCountAcross[0]//2 - n2 - elif octant_number == 6: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n2, self.elementsCountAcross[1]//2 - n1 - elif octant_number == 7: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n1, n2 - self.elementsCountAcross[0]//2 - elif octant_number == 8: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[0] - n2, n1 - self.elementsCountAcross[1]//2 - - return n3o, n2o, n1o + self._boxMapping = box_derivatives - def getNodeId(self, octant_number, n3, n2, n1, n3yo, n1yo, n2zo): - """ + dct = {1: self.pd1, 2: self.pd2, 3: self.pd3} + perm = {(1, 2): -3, (2, 3): -1, (3, 1): -2, (3, 2): 1, (1, 3): 2, (2, 1): 3} - :return: - """ - n1zo = n1yo + 1 - n3zo = n3yo + 1 - n3o, n2o, n1o = self.get_octant_node_index(octant_number, n3, n2, n1) - if n2o == 0 and n1o == n1yo: - if n3o == n3yo: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o, n1o+1) - elif n3o == n3yo: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o + 1) - else: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o, n1o + 1) - elif n2o == 1 and n1o == n1zo: - if n3o == n3yo: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o-1, n1o) - elif n3o == n3yo: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o+1) - else: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o) - elif n3o == n3yo and (n2o == 0 or n1o == n1zo): - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o, n1o) - elif n3o == n3zo and n2o == 1 and n1o == n1yo: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o+1) - elif n3o == n3zo and n2o == 1: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o - 1, n1o) - elif n3o == n3zo and n2o > 1 and n1o == n1yo: - n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o, n1o+1) - else: - n3r, n2r, n1r = n3, n2, n1 + if box_derivatives: + signs = [1 if c > 0 else -1 for c in box_derivatives] + dervMapping = (abs(box_derivatives[0]), abs(box_derivatives[1]), abs(box_derivatives[2])) - return self.nodeId[n3r][n2r][n1r] # (1,1,1)->(2,1,1) + temp1 = copy.deepcopy(self.pd3) + temp2 = copy.deepcopy(self.pd2) + for n3 in range(self.elementsCountAcross[2] + 1): + for n2 in range(self.elementsCountAcross[0] + 1): + for n1 in range(self.elementsCountAcross[1] + 1): + if self.px[n3][n2][n1]: + if self.is_interior_regular_nodes(n3, n2, n1): + dct[dervMapping[0]][n3][n2][n1] = [signs[0] * c for c in self.pd1[n3][n2][n1]] + dct[dervMapping[1]][n3][n2][n1] = [signs[1] * c for c in temp1[n3][n2][n1]] + dct[dervMapping[2]][n3][n2][n1] = [signs[2] * c for c in temp2[n3][n2][n1]] - def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): + def is_interior_regular_nodes(self, n3, n2, n1): """ - 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 meshGroups: Zinc mesh groups to add elements to. - :return: next elementIdentifier. - """ - elementIdentifier = startElementIdentifier - useCrossDerivatives = False - mesh = fieldmodule.findMeshByDimension(3) + Determine if a node indicated by [n3,n2,n1], is inside the sphere. + :return: True, if the node is inside. + """ + n3z = self.elementsCountAcross[2] + n1z = self.elementsCountAcross[1] + n2z = self.elementsCountAcross[0] + n3y = n3z - 1 + n1y = n1z - 1 - tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) - eft = tricubichermite.createEftNoCrossDerivatives() - elementtemplate = mesh.createElementtemplate() - elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) - elementtemplate.defineField(coordinates, -1, eft) + return n3 <= n3y and n2 >= 1 and n1 <= n1y - elementtemplate1 = mesh.createElementtemplate() - elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) + # node types + CORNER_1 = 1 + CORNER_2 = 2 + CORNER_3 = 3 - # isEven = (self.elementsCountAcross % 2) == 0 - # e1a = self.elementsCountRim - # e1b = e1a + 1 - # e1z = self.elementsCountAcross[1] - 1 - self.elementsCountRim - # e1y = e1z - 1 - # e2a = self.elementsCountRim - # e2b = self.elementsCountRim + 1 - # e2c = self.elementsCountRim + 2 - # e2z = self.elementsCountAcross[0] - 1 - # e2y = e2z - 1 - # e2x = e2z - 2 + QUADRUPLE_DOWN_LEFT = 4 + QUADRUPLE_RIGHT = 5 + QUADRUPLE_UP = 6 + QUADRUPLE0_DOWN_LEFT = 7 + QUADRUPLE0_RIGHT = 8 + QUADRUPLE0_UP = 9 + + TRIPLE_12_LEFT = 10 + TRIPLE_12_RIGHT = 11 + TRIPLE_13_DOWN = 12 + TRIPLE_13_UP = 13 + TRIPLE_23_UP = 14 + TRIPLE_23_DOWN = 15 + TRIPLE0_12_LEFT = 16 + TRIPLE0_12_RIGHT = 17 + TRIPLE0_13_DOWN = 18 + TRIPLE0_13_Up = 19 + TRIPLE0_23_DOWN = 20 + TRIPLE0_23_UP = 21 + + BOUNDARY_12_LEFT = 22 + BOUNDARY_12_RIGHT = 23 + BOUNDARY_13_DOWN = 24 + BOUNDARY_13_UP = 25 + BOUNDARY_23_UP = 26 + BOUNDARY_23_DOWN = 27 + + TRIPLE_CURVE_1_DOWN = 28 + TRIPLE_CURVE_1_UP = 29 + TRIPLE_CURVE_2_DOWN = 30 + TRIPLE_CURVE_2_UP = 31 + TRIPLE_CURVE_3_LEFT = 32 + TRIPLE_CURVE_3_RIGHT = 33 + TRIPLE_CURVE0_1_UP = 34 + TRIPLE_CURVE0_1_DOWN = 35 + TRIPLE_CURVE0_2_DOWN = 36 + TRIPLE_CURVE0_2_UP = 37 + TRIPLE_CURVE0_3_LEFT = 38 + TRIPLE_CURVE0_3_RIGHT = 39 + + SURFACE_REGULAR_DOWN_LEFT = 40 + SURFACE_REGULAR_DOWN_RIGHT = 41 + SURFACE_REGULAR_UP = 42 + REGULAR = 43 + + # element types + ELEMENT_REGULAR = 1 + ELEMENT_QUADRUPLE_DOWN_LEFT = 2 + ELEMENT_QUADRUPLE_DOWN_RIGHT = 3 + ELEMENT_QUADRUPLE_UP_LEFT = 4 + ELEMENT_QUADRUPLE_DOWN = 5 + ELEMENT_QUADRUPLE_UP = 6 + ELEMENT_QUADRUPLE_LEFT = 7 + ELEMENT_QUADRUPLE_RIGHT = 8 + ELEMENT_DOWN_RIGHT = 9 + ELEMENT_DOWN_LEFT = 10 + + def set_derivatives_for_irregualr_nodes(self, octant_number): + """ + For irregular nodes such as corners that are common between octants, change local derivatives to be the same + directions of the octant_PPP. This is because the remapping is done for octant_PPP only and for others we need + to make them similar, so similar remapping can be performed. Therefore, always same vectors is used for remapping. + e.g. [1, 0, 0] generates curve 1 in octant1. For one octant d1 is [1,0,0] and for another octant -d2. + :param octant_number: see get_element_type + :return: Derivatives for irregular nodes. + """ + default = [1, 2, 3] + + corner1derivs = default + corner2derivs = default + corner3derivs = default + boundary12leftderivs = default + boundary12rightderivs = default + triple12leftderivs = default + triple12rightderivs = default + + if octant_number == 1: + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + corner3derivs = [2, -1, 3] + else: + corner3derivs = [1, 2, 3] + elif octant_number == 2: + corner3derivs = [-2, 1, 3] + elif octant_number == 3: + corner3derivs = [-1, -2, 3] + elif octant_number == 4: + corner3derivs = [2, -1, 3] + elif octant_number == 5: + corner3derivs = [-1, -2, 3] + elif octant_number == 6: + corner3derivs = [-2, 1, 3] + elif octant_number == 7: + corner3derivs = [1, 2, 3] + elif octant_number == 8: + corner3derivs = [2, -1, 3] + else: + corner3derivs = [1, 2, 3] + + if octant_number in [5, 6, 7, 8]: + corner1derivs = [-1, -2, 3] + corner2derivs = [-1, -2, 3] + boundary12leftderivs = [-1, -2, 3] + boundary12rightderivs = [-1, -2, 3] + triple12leftderivs = [-1, -2, 3] + triple12rightderivs = [-1, -2, 3] + + return corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs, triple12leftderivs, triple12rightderivs + + def get_box_mapping_for_other_octants(self, octant_number, octant1_mapping=None): + """ + Find mapping for box nodes derivatives to make each octant similar to octant1. + :param octant1_mapping: + :return: boxMapping + """ + if not octant1_mapping: + octant1_mapping = [1, 3, 2] + + swap12 = [octant1_mapping[1], octant1_mapping[0], octant1_mapping[2]] + + signs = self.get_octant_signs(octant_number) + + if octant_number in [2, 4, 5, 7]: + boxMapping = [swap12[c] * signs[c] for c in range(3)] + else: + boxMapping = [octant1_mapping[c] * signs[c] for c in range(3)] + + return boxMapping + + def get_octant_signs(self, octant_number): + """ + Box mapping for each octant is different from octant1. for some of them 1 and 2 swaps. Also, the sign of them + might change. + :return: + """ + if octant_number == 1: + signs = [1, 1, 1] + elif octant_number == 2: + #y<0 + signs = [1, -1, 1] + elif octant_number == 3: + #x<0, y<0 + signs = [-1, -1, 1] + elif octant_number == 4: + # x<0 + signs = [-1, 1, 1] + elif octant_number == 5: + # z<0 + signs = [-1, -1, -1] + elif octant_number == 6: + # y<0, z<0 + signs = [1, -1, -1] + elif octant_number == 7: + # x<0, y<0, z<0 + signs = [1, 1, -1] + elif octant_number == 8: + # x<0, z<0 + signs = [-1, 1, -1] + else: + signs = [1, 1, 1] + + return signs + + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, 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 meshGroups: Zinc mesh groups to add elements to. + :return: next elementIdentifier. + """ + elementIdentifier = startElementIdentifier + useCrossDerivatives = False + mesh = fieldmodule.findMeshByDimension(3) + + tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) + eft = tricubichermite.createEftNoCrossDerivatives() + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) + elementtemplate.defineField(coordinates, -1, eft) + + elementtemplate1 = mesh.createElementtemplate() + elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): @@ -642,74 +987,18 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes eft1 = eft scalefactors = None - octant_number, element_type, e3o, e2o, e1o, e3zo, e2zo, e1zo = self.get_element_type(e3, e2, e1) + octant_number, element_type, e3zo, e2zo, e1zo = self.get_element_type(e3, e2, e1) + e3o, e2o, e1o = self.get_local_element_index(octant_number, e3, e2, e1) e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - nids = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo, e2zo+1), - self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo, e2zo+1), - self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo, e2zo+1), - self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo, e2zo+1), self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo, e2zo+1)] - - corner1derivs = [1, 2, 3] - corner2derivs = [1, 2, 3] - boundary12leftderivs = [1, 2, 3] - boundary12rightderivs = [1, 2, 3] - triple12leftderivs = [1, 2, 3] - triple12rightderivs = [1, 2, 3] - if octant_number == 1: - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - lnm = self.local_node_mapping([1, 3, 2]) - corner3derivs = [2, -1, 3] - else: - lnm = self.local_node_mapping([1, 3, 2]) - corner3derivs = [1, 2, 3] - elif octant_number == 2: - lnm = self.local_node_mapping([3, -1, 2]) - corner3derivs = [-2, 1, 3] - elif octant_number == 3: - lnm = self.local_node_mapping([-1, -3, 2]) - corner3derivs = [-1, -2, 3] - elif octant_number == 4: - lnm = self.local_node_mapping([-3, 1, 2]) - corner3derivs = [2, -1, 3] - elif octant_number == 5: - lnm = self.local_node_mapping([-3, -1, -2]) - corner1derivs = [-1, -2, 3] - corner2derivs = [-1, -2, 3] - corner3derivs = [-1, -2, 3] - boundary12leftderivs = [-1, -2, 3] - boundary12rightderivs = [-1, -2, 3] - triple12leftderivs = [-1, -2, 3] - triple12rightderivs = [-1, -2, 3] - elif octant_number == 6: - lnm = self.local_node_mapping([1, -3, -2]) - corner1derivs = [-1, -2, 3] - corner2derivs = [-1, -2, 3] - corner3derivs = [-2, 1, 3] - boundary12leftderivs = [-1, -2, 3] - boundary12rightderivs = [-1, -2, 3] - triple12leftderivs = [-1, -2, 3] - triple12rightderivs = [-1, -2, 3] - elif octant_number == 7: - lnm = self.local_node_mapping([3, 1, -2]) - corner1derivs = [-1, -2, 3] - corner2derivs = [-1, -2, 3] - corner3derivs = [1, 2, 3] - boundary12leftderivs = [-1, -2, 3] - boundary12rightderivs = [-1, -2, 3] - triple12leftderivs = [-1, -2, 3] - triple12rightderivs = [-1, -2, 3] - elif octant_number == 8: - lnm = self.local_node_mapping([-1, 3, -2]) - corner1derivs = [-1, -2, 3] - corner2derivs = [-1, -2, 3] - corner3derivs = [2, -1, 3] - boundary12leftderivs = [-1, -2, 3] - boundary12rightderivs = [-1, -2, 3] - triple12leftderivs = [-1, -2, 3] - triple12rightderivs = [-1, -2, 3] - else: - lnm = self.local_node_mapping([1, 3, 2]) - corner3derivs = [1, 2, 3] + nids = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo)] + + boxMapping = self.get_box_mapping_for_other_octants(octant_number) + lnm = self.local_node_mapping(boxMapping) + corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs, triple12leftderivs,\ + triple12rightderivs = self.set_derivatives_for_irregualr_nodes(octant_number) if element_type == self.ELEMENT_REGULAR: pass @@ -1031,850 +1320,513 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes return elementIdentifier - def remap_eft_node_value_label(self, eft, localNodeIndexes, NODE_TYPE, derivatives=None): + def local_node_mapping(self, boxMapping): """ - remaps derivatives for common types of nodes. - :return: + Find local node mapping between local node number of octant and local node number of sphere. Obtain, xi mapping + and box irregular derivatives mapping that are used for elements in octant that locally might have different + xi directions from their global sphere xi directions. Then they are used in remap_eft_node_value_label. + :return: lnm, local node mapping between local node number of octant and local node number of sphere. """ - label = {1: Node.VALUE_LABEL_D2_DS2DS3, 2: Node.VALUE_LABEL_D2_DS1DS3, 3: Node.VALUE_LABEL_D2_DS1DS2} - expressionLabel = {1: Node.VALUE_LABEL_D_DS1, 2: Node.VALUE_LABEL_D_DS2, 3: Node.VALUE_LABEL_D_DS3} - sf = {1: [], -1: [1]} - # lm, signs = self.label_map() - xim = self._xi_mapping - xis = self._xi_signs - if derivatives: - dm = {1: abs(derivatives[0]), 2: abs(derivatives[1]), 3: abs(derivatives[2])} - signs = [1 if c > 0 else -1 for c in derivatives] - ds = {1: signs[0], 2: signs[1], 3: signs[2]} - else: - dm = self._deriv_mapping - ds = self._deriv_signs + boxMapping_default = [1, 3, 2] - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D2_DS1DS3, [])]) - remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS1DS2, [])]) + xi_node_map = {(0, 0, 0): 1, (1, 0, 0): 2, (0, 1, 0): 3, (1, 1, 0): 4, + (0, 0, 1): 5, (1, 0, 1): 6, (0, 1, 1): 7, (1, 1, 1): 8} + node_xi_map = {1: (0, 0, 0), 2: (1, 0, 0), 3: (0, 1, 0), 4: (1, 1, 0), + 5: (0, 0, 1), 6: (1, 0, 1), 7: (0, 1, 1), 8: (1, 1, 1)} - if NODE_TYPE == self.CORNER_1: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) - elif NODE_TYPE == self.CORNER_2: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - elif NODE_TYPE == self.CORNER_3: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + xi_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} + signs = [1 if boxMapping[c]*boxMapping_default[c] > 0 else -1 for c in range(3)] + xi_sign_change = [signs[0], signs[2], signs[1]] - elif NODE_TYPE == self.QUADRUPLE_DOWN_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) - elif NODE_TYPE == self.QUADRUPLE_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - elif NODE_TYPE == self.QUADRUPLE_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - elif NODE_TYPE == self.QUADRUPLE0_DOWN_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - elif NODE_TYPE == self.QUADRUPLE0_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - elif NODE_TYPE == self.QUADRUPLE0_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + lnm = {} + for ln in range(1, 9): + xi_l = [] + xi = [node_xi_map[ln][xi_map['xi1'] - 1], node_xi_map[ln][xi_map['xi2'] - 1], node_xi_map[ln][xi_map['xi3'] - 1]] + signs = [xi_sign_change[xi_map['xi1'] - 1], xi_sign_change[xi_map['xi2'] - 1], xi_sign_change[xi_map['xi3'] - 1]] + for i in range(3): + if signs[i] > 0: + xi_l.append(xi[i]) + else: + xi_l.append(1 - xi[i]) + lnm[ln] = xi_node_map[tuple(xi_l)] - elif NODE_TYPE == self.TRIPLE_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) - elif NODE_TYPE == self.TRIPLE_12_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - elif NODE_TYPE == self.TRIPLE_13_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) - elif NODE_TYPE == self.TRIPLE_13_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap - elif NODE_TYPE == self.TRIPLE_23_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - elif NODE_TYPE == self.TRIPLE_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - elif NODE_TYPE == self.TRIPLE0_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - elif NODE_TYPE == self.TRIPLE0_12_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - elif NODE_TYPE == self.TRIPLE0_13_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) - elif NODE_TYPE == self.TRIPLE0_13_Up: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - elif NODE_TYPE == self.TRIPLE0_23_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - elif NODE_TYPE == self.TRIPLE0_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + deriv_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} + signs = [1 if boxMapping[c]*boxMapping_default[c] > 0 else -1 for c in range(3)] + deriv_sign_change = [signs[0], signs[2], signs[1]] - elif NODE_TYPE == self.BOUNDARY_12_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) - elif NODE_TYPE == self.BOUNDARY_12_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - elif NODE_TYPE == self.BOUNDARY_13_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) - elif NODE_TYPE == self.BOUNDARY_13_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap - # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, [])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) - elif NODE_TYPE == self.BOUNDARY_23_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - elif NODE_TYPE == self.BOUNDARY_23_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + self._xi_mapping = {1: xi_map['xi1'], 2: xi_map['xi2'], 3: xi_map['xi3']} + self._xi_signs = {1: xi_sign_change[0], 2: xi_sign_change[1], 3: xi_sign_change[2]} + self._box_deriv_mapping = {1: deriv_map['xi1'], 2: deriv_map['xi2'], 3: deriv_map['xi3']} + self._box_deriv_signs = {1: deriv_sign_change[0], 2: deriv_sign_change[1], 3: deriv_sign_change[2]} - elif NODE_TYPE == self.TRIPLE_CURVE_1_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - elif NODE_TYPE == self.TRIPLE_CURVE_1_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - elif NODE_TYPE == self.TRIPLE_CURVE_2_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) - elif NODE_TYPE == self.TRIPLE_CURVE_2_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - elif NODE_TYPE == self.TRIPLE_CURVE_3_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) - elif NODE_TYPE == self.TRIPLE_CURVE_3_RIGHT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - elif NODE_TYPE == self.TRIPLE_CURVE0_1_UP: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) - elif NODE_TYPE == self.TRIPLE_CURVE0_1_DOWN: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - elif NODE_TYPE == self.TRIPLE_CURVE0_2_DOWN: + return lnm + + def get_element_type(self, e3, e2, e1): + """ + Find element type. + :return:octant number, element type and extends for the octant. + """ + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + octant_number = 1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: + if e2 < self.elementsCountAcross[0]//2: + if e1 >= self.elementsCountAcross[1]//2: + octant_number = 1 + else: + octant_number = 2 + else: + if e1 < self.elementsCountAcross[1]//2: + octant_number = 3 + else: + octant_number = 4 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if e3 >= self.elementsCountAcross[2] // 2: + if e2 < self.elementsCountAcross[0] // 2: + if e1 >= self.elementsCountAcross[1] // 2: + octant_number = 1 + else: + octant_number = 2 + else: + if e1 < self.elementsCountAcross[1] // 2: + octant_number = 3 + else: + octant_number = 4 + else: + if e2 < self.elementsCountAcross[0] // 2: + if e1 >= self.elementsCountAcross[1] // 2: + octant_number = 5 + else: + octant_number = 6 + else: + if e1 < self.elementsCountAcross[1] // 2: + octant_number = 7 + else: + octant_number = 8 + + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[0] - 1 + e1zo = self.elementsCountAcross[1] - 1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: + if octant_number in [1, 3]: + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[0] // 2 - 1 + e1zo = self.elementsCountAcross[1] // 2 - 1 + else: + e3zo = self.elementsCountAcross[2] - 1 + e2zo = self.elementsCountAcross[1] // 2 - 1 + e1zo = self.elementsCountAcross[0] // 2 - 1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if octant_number in [2, 4, 5, 7]: + e3zo = self.elementsCountAcross[2] // 2 - 1 + e2zo = self.elementsCountAcross[1] // 2 - 1 + e1zo = self.elementsCountAcross[0] // 2 - 1 + else: + e3zo = self.elementsCountAcross[2] // 2 - 1 + e2zo = self.elementsCountAcross[0] // 2 - 1 + e1zo = self.elementsCountAcross[1] // 2 - 1 + + e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 + e3o, e2o, e1o = self.get_local_element_index(octant_number, e3, e2, e1) + + if e3o <= e3yo and e2o >= e2bo and e1o <= e1yo: + element_type = self.ELEMENT_REGULAR + elif e3o == e3yo and e2o == 0 and e1o == e1yo: + element_type = self.ELEMENT_QUADRUPLE_DOWN_LEFT + elif e3o == e3yo and e2o >= e2bo and e1o == e1zo: + element_type = self.ELEMENT_QUADRUPLE_DOWN_RIGHT + elif e3o == e3zo and e2o >= e2bo and e1o == e1yo: + element_type = self.ELEMENT_QUADRUPLE_UP_LEFT + elif e3o == e3yo and e2o == 0 and e1o < e1yo: + element_type = self.ELEMENT_QUADRUPLE_DOWN + elif e3o == e3zo and e2o >= e2bo and e1o < e1yo: + element_type = self.ELEMENT_QUADRUPLE_UP + elif e3o < e3yo and e2o == 0 and e1o == e1yo: + element_type = self.ELEMENT_QUADRUPLE_LEFT + elif e3o < e3yo and e2o == e2bo and e1o == e1zo: + element_type = self.ELEMENT_QUADRUPLE_RIGHT + elif e3o < e3yo and e2o > e2bo and e1o == e1zo: + element_type = self.ELEMENT_DOWN_RIGHT + elif e3o < e3yo and e2o == 0 and e1o < e1yo: + element_type = self.ELEMENT_DOWN_LEFT + else: + element_type = 0 + + return octant_number, element_type, e3zo, e2zo, e1zo + + def get_local_element_index(self, octant_number, e3, e2, e1): + """ + Get octant element index from sphere element index. + :return:e3o, e2o, e1o, local octant element indexes. + """ + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + e3o, e2o, e1o = e3, e2, e1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: + if octant_number == 1: + e3o, e2o, e1o = e3, e2, e1 - self.elementsCountAcross[1]//2 + elif octant_number == 2: + e3o, e2o, e1o = e3, e1, self.elementsCountAcross[0]//2 - 1 - e2 + elif octant_number == 3: + e3o, e2o, e1o = e3, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1]//2 - 1 - e1 + elif octant_number == 4: + e3o, e2o, e1o = e3, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0]//2 + + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if octant_number == 1: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e2, e1 - self.elementsCountAcross[1] // 2 + elif octant_number == 2: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e1, self.elementsCountAcross[0] // 2 - 1 - e2 + elif octant_number == 3: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1] // 2 - 1 - e1 + elif octant_number == 4: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0] // 2 + elif octant_number == 5: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[1] - 1 - e1, self.elementsCountAcross[0]//2 - 1 - e2 + elif octant_number == 6: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e2, self.elementsCountAcross[1] // 2 - 1 - e1 + elif octant_number == 7: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e1, e2 - self.elementsCountAcross[0]//2 + elif octant_number == 8: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[0] - 1 - e2, e1 - self.elementsCountAcross[1]//2 + else: + raise ValueError("Not implemented.") + + return e3o, e2o, e1o + + def get_global_node_index(self, octant_number, n3o, n2o, n1o): + """ + Get octant element index from sphere element index. + :return: n3, n2, n1, sphere element indexes. + """ + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + n3, n2, n1 = n3o, n2o, n1o + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: + if octant_number == 1: + n3, n2, n1 = n3o, n2o, n1o + self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 - n1o, n2o + elif octant_number == 3: + n3, n2, n1 = n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o + elif octant_number == 4: + n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if octant_number == 1: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, n2o, n1o + self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 - n1o, n2o + elif octant_number == 3: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o + elif octant_number == 4: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o + elif octant_number == 5: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0]//2 - n1o, self.elementsCountAcross[1] - n2o + elif octant_number == 6: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n2o, self.elementsCountAcross[1]//2 - n1o + elif octant_number == 7: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n1o + self.elementsCountAcross[0]//2, n2o + elif octant_number == 8: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1]//2 + n1o + + return n3, n2, n1 + + def get_octant_node_index(self, octant_number, n3, n2, n1): + """ + Get local octant node index from sphere node index. + :return: n3o, n2o, n1o, local octant node indexes. + """ + if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: + n3o, n2o, n1o = n3, n2, n1 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: + if octant_number == 1: + n3o, n2o, n1o = n3, n2, n1 - self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3o, n2o, n1o = n3, n1, self.elementsCountAcross[0] // 2 - n2 + elif octant_number == 3: + n3o, n2o, n1o = n3, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 + elif octant_number == 4: + n3o, n2o, n1o = n3, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 + elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: + if octant_number == 1: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n2, n1 - self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n1, self.elementsCountAcross[0] // 2 - n2 + elif octant_number == 3: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 + elif octant_number == 4: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 + elif octant_number == 5: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[1] - n1, self.elementsCountAcross[0]//2 - n2 + elif octant_number == 6: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n2, self.elementsCountAcross[1]//2 - n1 + elif octant_number == 7: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n1, n2 - self.elementsCountAcross[0]//2 + elif octant_number == 8: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[0] - n2, n1 - self.elementsCountAcross[1]//2 + + return n3o, n2o, n1o + + def getNodeId(self, octant_number, n3, n2, n1, n3yo, n1yo): + """ + Get node identifier. Use node indexes n3, n2, n1 to find it. If the indexes represent removed nodes in the lattice, + find the right indexes first. + :return: Node identifier. + """ + n1zo = n1yo + 1 + n3zo = n3yo + 1 + n3o, n2o, n1o = self.get_octant_node_index(octant_number, n3, n2, n1) + if n2o == 0 and n1o == n1yo: + if n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o, n1o+1) + elif n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o + 1) + else: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o, n1o + 1) + elif n2o == 1 and n1o == n1zo: + if n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o-1, n1o) + elif n3o == n3yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o+1) + else: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o) + elif n3o == n3yo and (n2o == 0 or n1o == n1zo): + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o+1, n2o, n1o) + elif n3o == n3zo and n2o == 1 and n1o == n1yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o-1, n1o+1) + elif n3o == n3zo and n2o == 1: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o - 1, n1o) + elif n3o == n3zo and n2o > 1 and n1o == n1yo: + n3r, n2r, n1r = self.get_global_node_index(octant_number, n3o, n2o, n1o+1) + else: + n3r, n2r, n1r = n3, n2, n1 + + return self.nodeId[n3r][n2r][n1r] + + def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivatives=None): + """ + Remaps derivatives for common types of nodes. It assumes the directions of derivatives in a certain way. If + directions are different, then we can use the 'derivatives' argument to fix this. This part is done for irregular nodes, + in the box and for other nodes, derivatives should be given. + :param node_type: e.g. corner 1 represents an end node on the axis1. + :param derivatives: derivatives to be changed to. + :return: + """ + label = {1: Node.VALUE_LABEL_D2_DS2DS3, 2: Node.VALUE_LABEL_D2_DS1DS3, 3: Node.VALUE_LABEL_D2_DS1DS2} + expressionLabel = {1: Node.VALUE_LABEL_D_DS1, 2: Node.VALUE_LABEL_D_DS2, 3: Node.VALUE_LABEL_D_DS3} + sf = {1: [], -1: [1]} + + xim = self._xi_mapping + xis = self._xi_signs + if derivatives: + dm = {1: abs(derivatives[0]), 2: abs(derivatives[1]), 3: abs(derivatives[2])} + signs = [1 if c > 0 else -1 for c in derivatives] + ds = {1: signs[0], 2: signs[1], 3: signs[2]} + else: + dm = self._box_deriv_mapping + ds = self._box_deriv_signs + + # use cross derivatives for swapping derivatives. + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D2_DS2DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D2_DS1DS3, [])]) + remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS1DS2, [])]) + + if node_type == self.CORNER_1: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) - elif NODE_TYPE == self.TRIPLE_CURVE0_2_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) + elif node_type == self.CORNER_2: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + elif node_type == self.CORNER_3: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + + elif node_type == self.QUADRUPLE_DOWN_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - elif NODE_TYPE == self.TRIPLE_CURVE0_3_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + elif node_type == self.QUADRUPLE_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + elif node_type == self.QUADRUPLE_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + elif node_type == self.QUADRUPLE0_DOWN_LEFT: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - elif NODE_TYPE == self.TRIPLE_CURVE0_3_RIGHT: + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + elif node_type == self.QUADRUPLE0_RIGHT: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + elif node_type == self.QUADRUPLE0_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) - elif NODE_TYPE == self.SURFACE_REGULAR_DOWN_LEFT: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + elif node_type == self.TRIPLE_12_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) + elif node_type == self.TRIPLE_12_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + elif node_type == self.TRIPLE_13_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) - elif NODE_TYPE == self.SURFACE_REGULAR_DOWN_RIGHT: + elif node_type == self.TRIPLE_13_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + elif node_type == self.TRIPLE_23_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - elif NODE_TYPE == self.SURFACE_REGULAR_UP: + elif node_type == self.TRIPLE_23_UP: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - elif NODE_TYPE == self.REGULAR: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + elif node_type == self.TRIPLE0_12_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + elif node_type == self.TRIPLE0_12_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + elif node_type == self.TRIPLE0_13_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) + elif node_type == self.TRIPLE0_13_Up: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + elif node_type == self.TRIPLE0_23_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + elif node_type == self.TRIPLE0_23_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + + elif node_type == self.BOUNDARY_12_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) + elif node_type == self.BOUNDARY_12_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + elif node_type == self.BOUNDARY_13_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + elif node_type == self.BOUNDARY_13_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, [])]) + # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + elif node_type == self.BOUNDARY_23_DOWN: remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) - else: - raise ValueError("Remapping for derivatives of this 'node type' is not implemented") - - -class ShieldMesh2D: - ''' - Shield mesh generator. - ''' - - def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, trackSurface : TrackSurface=None, - elementsCountAlong=1, shieldMode=ShieldShape2D.SHIELD_SHAPE_LOWER_HALF, shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR): - ''' - Data structure for defining a shield-shaped mesh which is flat on the top and rounded around the bottom - and/or the same mirror mirrored on top. - It is represented as a regular box of elementsCountAcross x elementsCountUp - but with strips of elements absent on the bottom left and right. - Example showing elements for 4 across, 2 up and 0 rim, and how nodes/coordinates are stored in ShieldMesh: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + elif node_type == self.BOUNDARY_23_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) - N___N___N___N___N N___N___N___N___N - | | | | | | | | - | | | | | | | | - \ T---N---T / --> T---N---T - \ / | \ / | | | - N | N | | | - \----N----/ N---N---N + elif node_type == self.TRIPLE_CURVE_1_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + elif node_type == self.TRIPLE_CURVE_1_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + elif node_type == self.TRIPLE_CURVE_2_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + elif node_type == self.TRIPLE_CURVE_2_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + elif node_type == self.TRIPLE_CURVE_3_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + elif node_type == self.TRIPLE_CURVE_3_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + elif node_type == self.TRIPLE_CURVE0_1_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + elif node_type == self.TRIPLE_CURVE0_1_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + elif node_type == self.TRIPLE_CURVE0_2_DOWN: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) + elif node_type == self.TRIPLE_CURVE0_2_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + elif node_type == self.TRIPLE_CURVE0_3_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + elif node_type == self.TRIPLE_CURVE0_3_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - The removal of 2 corners of the box is achieved by triple points T where 3 square elements - join in a triangle. - Extra rim elements go around the sides and bottom curve. Rim elements add nodes on the sides above the - triple points, and across the shorter bottom row. - Extra elements up add regular rows of nodes/elements on top, and extra non-rim elements across - add regular columns of nodes/elements up the centre. - :param elementsCountAcross: Number of elements across top of shield. Must be at least 4 + 2*elementsCountRim. - :param elementsCountUpFull: Number of elements up central axis of shield. Must be at least 2 + elementsCountRim if half and 4 + 2*elementsCountRim if full. - :param elementsCountAlong: Number of elements through wall for ventricle case (only 1 element is supported) and along cylinder axis in cylinder case. - :param elementsCountRim: Number of elements around bottom rim (not top) outside of 'triple points'. - :param trackSurface: Optional trackSurface to store or restrict points to. - :param shieldMode: It determines if the shield is full or just part of it. - :param shieldType: To distinguish between cylinder and ventricle type. Derivatives and directions are chosen differently for two cases. - ''' - assert elementsCountRim >= 0 - assert elementsCountAlong >= 1 - assert elementsCountAcross >= (elementsCountRim + 4) - assert elementsCountUpFull >= (elementsCountRim + 2) - self.elementsCountAcross = elementsCountAcross - self.elementsCountUpFull = elementsCountUpFull - elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL else elementsCountUpFull - self.elementsCountUp = elementsCountUp - self.elementsCountRim = elementsCountRim - self.elementsCountAlong = elementsCountAlong - self.elementsCountUpRegular = elementsCountUp - 2 - elementsCountRim - elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim - self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim - self.trackSurface = trackSurface - self._mode = shieldMode - self._type = shieldType - self.px = [ [] for _ in range(elementsCountAlong+1) ] - self.pd1 = [ [] for _ in range(elementsCountAlong+1) ] - self.pd2 = [ [] for _ in range(elementsCountAlong+1) ] - self.pd3 = [ [] for _ in range(elementsCountAlong+1) ] - self.nodeId = [ [] for _ in range(elementsCountAlong+1) ] - for n3 in range(elementsCountAlong+1): - for n2 in range(elementsCountUpFull + 1): - for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: - p.append([ None ]*(elementsCountAcross + 1)) - if trackSurface: - self.pProportions = [ [ None ]*(elementsCountAcross + 1) for n2 in range(elementsCountUp + 1) ] - if shieldType == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.elementId = [ [[ None ]*elementsCountAcross for n2 in range(elementsCountUpFull)] for e3 in range(elementsCountAlong) ] + elif node_type == self.SURFACE_REGULAR_DOWN_LEFT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) + elif node_type == self.SURFACE_REGULAR_DOWN_RIGHT: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) + elif node_type == self.SURFACE_REGULAR_UP: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) + elif node_type == self.REGULAR: + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) else: - self.elementId = [[None] * elementsCountAcross for n2 in range(elementsCountUpFull)] - - def convertRimIndex(self, ix, rx=0): - ''' - Convert point index around the lower rim to n1, n2 across and up box. - :param ix: index around from 0 to self.elementsCountAroundFull - :param rx: rim index from 0 (around outside) to self.elementsCountRim - :return: n1, n2 - ''' - assert 0 <= ix <= self.elementsCountAroundFull - assert 0 <= rx <= self.elementsCountRim - if ix <= self.elementsCountUpRegular: - return rx, self.elementsCountUp - ix - mx = self.elementsCountAroundFull - ix - if mx <= self.elementsCountUpRegular: - return self.elementsCountAcross - rx, self.elementsCountUp - mx - return self.elementsCountRim + ix - self.elementsCountUpRegular, rx - - - def getTriplePoints(self, n3): - ''' - Compute coordinates and derivatives of points where 3 square elements merge. - :param n3: Index of through-wall coordinates to use. - ''' - n1a = self.elementsCountRim - n1b = n1a + 1 - n1c = n1a + 2 - m1a = self.elementsCountAcross - self.elementsCountRim - m1b = m1a - 1 - m1c = m1a - 2 - n2a = self.elementsCountRim - n2b = n2a + 1 - n2c = n2a + 2 - # left - ltx = [] - - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]],[[(-self.pd1[n3][n2a][n1c][c] - self.pd3[n3][n2a][n1c][c]) for c in range(3)], self.pd1[n3][n2c][n1b]],2, arcLengthDerivatives=True)[0:2] - ltx.append(tx[1]) - # tx, td1 = sampleCubicHermiteCurves( - # [ self.px[n3][n2a][n1b], self.px[n3][n2c][n1c] ], [ [-self.pd3[n3][n2a][n1b][c] for c in range(3)], [ (self.pd1[n3][n2c][n1c][c] + self.pd3[n3][n2c][n1c][c]) for c in range(3) ] ], 2, arcLengthDerivatives = True)[0:2] - ltx.append(tx[1]) - tx, td1 = sampleCubicHermiteCurves( - [ self.px[n3][n2c][n1a], self.px[n3][n2b][n1c] ], [ [ (self.pd1[n3][n2c][n1a][c] - self.pd3[n3][n2c][n1a][c]) for c in range(3) ], self.pd3[n3][n2b][n1c] ], 2, arcLengthDerivatives = True)[0:2] - ltx.append(tx[1]) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]], [[(-self.pd1[n3][n2a][n1c][c] + self.pd2[n3][n2a][n1c][c]) for c in range(3)],self.pd2[n3][n2c][n1b]], 2, arcLengthDerivatives = True)[0: 2] - ltx.append(tx[1]) - tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][n1b], self.px[n3][n2c][n1c]], [self.pd2[n3][n2a][n1b], [(self.pd1[n3][n2c][n1c][c] + self.pd2[n3][n2c][n1c][c]) for c in range(3)]], 2, arcLengthDerivatives = True)[0: 2] - ltx.append(tx[1]) - tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2c][n1a], self.px[n3][n2b][n1c]], [[(self.pd1[n3][n2c][n1a][c] - self.pd2[n3][n2c][n1a][c]) for c in range(3)], self.pd1[n3][n2b][n1c]], 2, arcLengthDerivatives = True)[0: 2] - ltx.append(tx[1]) - #x = [ (ltx[0][c] + ltx[1][c] + ltx[2][c])/3.0 for c in range(3) ] - x = [ (ltx[0][c] + ltx[2][c])/2.0 for c in range(3) ] - if self.trackSurface: - p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*(self.pProportions[n2b][n1c]))) - self.pProportions[n2b][n1b] = self.trackSurface.getProportion(p) - x, sd1, sd2 = self.trackSurface.evaluateCoordinates(p, derivatives=True) - d1, d2, d3 = calculate_surface_axes(sd1, sd2, vector.normalise(sd1)) - self.pd3[n3][n2b][n1b] = d3 - self.px [n3][n2b][n1b] = x - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd3[n3][n2b][n1b] = [ (self.px[n3][n2b][n1c][c] - self.px[n3][n2b][n1b][c]) for c in range(3) ] - self.pd1[n3][n2b][n1b] = [ (self.px[n3][n2c][n1b][c] - self.px[n3][n2b][n1b][c]) for c in range(3) ] - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - self.pd1[n3][n2b][n1b] = [(self.px[n3][n2b][n1c][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] - self.pd2[n3][n2b][n1b] = [(self.px[n3][n2c][n1b][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] - if not self.trackSurface: - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd2[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][n1b], self.pd1[n3][n2b][n1b])) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - self.pd3[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][n1b], self.pd2[n3][n2b][n1b])) - # right - rtx = [] - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - tx, td1 = sampleCubicHermiteCurves( - [ self.px[n3][n2a][m1c], self.px[n3][n2c][m1b] ], [ [ (self.pd1[n3][n2a][m1c][c] - self.pd3[n3][n2a][m1c][c]) for c in range(3) ], self.pd1[n3][n2c][m1b] ], 2, arcLengthDerivatives = True)[0:2] - rtx.append(tx[1]) - # tx, td1 = sampleCubicHermiteCurves( - # [ self.px[n3][n2a][m1b], self.px[n3][n2c][m1c] ], [ [-self.pd3[n3][n2a][m1b][c] for c in range(3)], [ (-self.pd3[n3][n2c][m1c][c] + self.pd1[n3][n2c][m1c][c]) for c in range(3) ] ], 2, arcLengthDerivatives = True)[0:2] - rtx.append(tx[1]) - tx, td1 = sampleCubicHermiteCurves( - [ self.px[n3][n2c][m1a], self.px[n3][n2b][m1c] ], [ [ (-self.pd1[n3][n2c][m1a][c] - self.pd3[n3][n2c][m1a][c]) for c in range(3) ], [ -d for d in self.pd3[n3][n2b][m1c] ] ], 2, arcLengthDerivatives = True)[0:2] - rtx.append(tx[1]) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][m1c], self.px[n3][n2c][m1b]], [[(self.pd1[n3][n2a][m1c][c] + self.pd2[n3][n2a][m1c][c]) for c in range(3)],self.pd2[n3][n2c][m1b]], 2, arcLengthDerivatives = True)[0: 2] - rtx.append(tx[1]) - tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][m1b], self.px[n3][n2c][m1c]], [self.pd2[n3][n2a][m1b], [(-self.pd1[n3][n2c][m1c][c] + self.pd2[n3][n2c][m1c][c]) for c in range(3)]], 2, arcLengthDerivatives = True)[0: 2] - rtx.append(tx[1]) - tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2c][m1a], self.px[n3][n2b][m1c]], [[(-self.pd1[n3][n2c][m1a][c] - self.pd2[n3][n2c][m1a][c]) for c in range(3)],[-d for d in self.pd1[n3][n2b][m1c]]], 2, arcLengthDerivatives = True)[0: 2] - rtx.append(tx[1]) - #x = [ (rtx[0][c] + rtx[1][c] + rtx[2][c])/3.0 for c in range(3) ] - x = [ (rtx[0][c] + rtx[2][c])/2.0 for c in range(3) ] - if self.trackSurface: - p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*(self.pProportions[n2b][m1c]))) - self.pProportions[n2b][m1b] = self.trackSurface.getProportion(p) - x, sd1, sd2 = self.trackSurface.evaluateCoordinates(p, derivatives=True) - d1, d2, d3 = calculate_surface_axes(sd1, sd2, vector.normalise(sd1)) - self.pd3[n3][n2b][m1b] = d3 - self.px [n3][n2b][m1b] = x - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd3[n3][n2b][m1b] = [ (self.px[n3][n2b][m1b][c] - self.px[n3][n2b][m1c][c]) for c in range(3) ] - self.pd1[n3][n2b][m1b] = [ (self.px[n3][n2c][m1b][c] - self.px[n3][n2b][m1b][c]) for c in range(3) ] - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - self.pd1[n3][n2b][m1b] = [(self.px[n3][n2b][m1b][c] - self.px[n3][n2b][m1c][c]) for c in range(3)] - self.pd2[n3][n2b][m1b] = [(self.px[n3][n2c][m1b][c] - self.px[n3][n2b][m1b][c]) for c in range(3)] - if not self.trackSurface: - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd2[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][m1b], self.pd1[n3][n2b][m1b])) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - self.pd3[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][m1b], self.pd2[n3][n2b][m1b])) - - - def smoothDerivativesToTriplePoints(self, n3, fixAllDirections=False): - ''' - Smooth derivatives leading to triple points where 3 square elements merge. - :param n3: Index of through-wall coordinates to use. - ''' - n1a = self.elementsCountRim - n1b = n1a + 1 - n1z = self.elementsCountAcross - self.elementsCountRim - n1y = n1z - 1 - m1a = self.elementsCountAcross - self.elementsCountRim - m1b = m1a - 1 - n2a = self.elementsCountRim - n2b = n2a + 1 - n2c = n2a + 2 - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - # left - tx = [] - td3 = [] - for n2 in range(n2c): - tx.append(self.px[n3][n2][n1b]) - if n2 < n2b: - td3.append([-self.pd3[n3][n2][n1b][c] for c in range(3)]) - else: - td3.append([(self.pd1[n3][n2b][n1b][c] + self.pd3[n3][n2b][n1b][c]) for c in range(3)] ) - - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - - for n2 in range(n2b): - self.pd3[n3][n2][n1b] = [-td3[n2][c] for c in range(3)] - - # right - tx = [] - td3 = [] - for n2 in range(n2c): - tx.append(self.px[n3][n2][n1y]) - if n2 < n2b: - td3.append([-self.pd3[n3][n2][n1y][c] for c in range(3)]) - else: - td3.append([(self.pd1[n3][n2b][n1y][c] - self.pd3[n3][n2b][n1y][c]) for c in range(3)]) - - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - - for n2 in range(n2b): - self.pd3[n3][n2][n1y] = [-td3[n2][c] for c in range(3)] - - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - # left - tx = [] - td2 = [] - for n2 in range(0, n2c): - tx .append(self.px [n3][n2][n1b]) - td2.append(self.pd2[n3][n2][n1b] if (n2 < n2b) else [(self.pd1[n3][n2][n1b][c] + self.pd2[n3][n2][n1b][c]) for c in range(3)]) - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections, fixEndDerivative=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) - for n2 in range(0, n2b): - self.pd2[n3][n2][n1b] = td2[n2] - # right - tx = [] - td2 = [] - for n2 in range(0, n2c): - tx .append(self.px [n3][n2][m1b]) - td2.append(self.pd2[n3][n2][m1b] if (n2 < n2b) else [(-self.pd1[n3][n2][m1b][c] + self.pd2[n3][n2][m1b][c]) for c in range(3)]) - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections,fixEndDerivative=True,magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) - for n2 in range(0, n2b): - self.pd2[n3][n2][m1b] = td2[n2] - - def smoothDerivativesAroundRim(self, n3, n3d=None, rx=0): - ''' - Smooth derivatives around rim. - :param n3: Index of through-wall coordinates to use. - :param n3d: Which n3 index to copy initial derivatives from. If None, use n3. - :param rx: rim index from 0 (around outside) to self.elementsCountRim - ''' - assert 0 <= rx <= self.elementsCountRim - if not n3d: - n3d = n3 - tx = [] - td1 = [] - for ix in range(self.elementsCountAroundFull + 1): - n1, n2 = self.convertRimIndex(ix, rx) - tx.append(self.px[n3][n2][n1]) - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - td1.append(self.pd1[n3d][n2][n1]) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - if n2 > self.elementsCountRim: # regular rows - if n1 <= self.elementsCountRim: - td1.append([ -d for d in self.pd2[n3d][n2][n1] ]) - else: - td1.append(self.pd2[n3d][n2][n1]) - else: - td1.append(self.pd1[n3d][n2][n1]) - - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - td1 = smoothCubicHermiteDerivativesLine(tx, td1, fixStartDirection=True, fixEndDirection=True) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - td1 = smoothCubicHermiteDerivativesLine(tx, td1) - - for ix in range(self.elementsCountAroundFull + 1): - n1, n2 = self.convertRimIndex(ix, rx) - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd1[n3][n2][n1] = td1[ix] - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - if n2 > self.elementsCountRim: # regular rows - if n1 <= self.elementsCountRim: - self.pd2[n3][n2][n1] = [ -d for d in td1[ix] ] - else: - self.pd2[n3][n2][n1] = td1[ix] - else: - self.pd1[n3][n2][n1] = td1[ix] - - def remap_derivatives(self, squareMapping, circleMapping=None): - """ - It remaps the derivatives as indicated by squareMapping and circleMapping. Limited to SHIELD_RIM_DERIVATIVE_MODE_AROUND. - :param squareMapping: List[up, right]. Determines what derivatives should be in the up and right directions in the - square part. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. - The negative sign reverses the direction. e.g. [-3,2] means d3 is down and d2 is right. The third derivative - is determined by the other two. RH rule applied. Assumes [1,3] initially. - :param circleMapping: List[circumferential, radial]. Determines what derivatives should be used for - circumferential and radial directions around the circle. - [-1, 3] means d1 -> clockwise and around. d3 -> outward and radial. Assumes [1,3] initially. - :return: - """ - dct = {1: self.pd1, 2: self.pd2, 3: self.pd3} - perm = {(1, 2): -3, (2, 3): -1, (3, 1): -2, (3, 2): 1, (1, 3): 2, (2, 1): 3} - - square = True - tripleRow = [self.elementsCountRim + 1, self.elementsCountUpFull - (self.elementsCountRim + 1)] - ellipseMapping = [squareMapping, circleMapping] - for mapping in ellipseMapping: - if mapping: - signs = [] - for c in mapping: - sign = 1 if c > 0 else -1 - signs.append(sign) - derv = (abs(mapping[0]), abs(mapping[1])) - sign = 1 if perm[derv] > 0 else -1 - signs.append(signs[0]*signs[1]*sign) - dervMapping = (derv[0], derv[1], abs(perm[derv])) - temp1 = copy.deepcopy(self.pd3) - temp2 = copy.deepcopy(self.pd2) - for n2 in range(self.elementsCountUpFull + 1): - for n3 in range(self.elementsCountAlong+1): - for n1 in range(self.elementsCountAcross + 1): - if self.px[n3][n2][n1]: - is_on_square = ((self.px[n3][n2][0] and self.px[n3][0][n1]) or n2 in tripleRow) - if (is_on_square and square) or (not is_on_square and not square): - dct[dervMapping[0]][n3][n2][n1] = [signs[0]*c for c in self.pd1[n3][n2][n1]] - dct[dervMapping[1]][n3][n2][n1] = [signs[1]*c for c in temp1[n3][n2][n1]] - dct[dervMapping[2]][n3][n2][n1] = [signs[2]*c for c in temp2[n3][n2][n1]] - square = False - - def generateNodesForOtherHalf(self, mirrorPlane): - """ - Generates coordinates and derivatives for the other half by mirroring them. It keeps the d1 direction. - :param mirrorPlane: plane ax+by+cz=d in form of [a,b,c,d] - :return: - """ - mirror=Mirror(mirrorPlane) - for n2 in range(self.elementsCountUp): - for n3 in range(self.elementsCountAlong + 1): - for n1 in range(self.elementsCountAcross + 1): - if self.px[n3][n2][n1]: - self.px[n3][2*self.elementsCountUp-n2][n1] = mirror.mirrorImageOfPoint(self.px[n3][n2][n1]) - self.pd1[n3][2*self.elementsCountUp-n2][n1] = mirror.reverseMirrorVector(self.pd1[n3][n2][n1]) - 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): - """ - 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 mirrorPlane: mirror plane ax+by+cz=d in form of [a,b,c,d] - :return: next nodeIdentifier. - """ - nodeIdentifier = startNodeIdentifier - nodes = fieldmodule.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) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) - cache = fieldmodule.createFieldcache() - - #for n2 in range(self.elementsCountUp, -1, -1): - # s = "" - # for n1 in range(self.elementsCountAcross + 1): - # s += str(n1) if self.px[1][n2][n1] else " " - # print(n2, s, n2 - self.elementsCountUp - 1) - - if self._mode == ShieldShape2D.SHIELD_SHAPE_FULL and mirrorPlane: - self.generateNodesForOtherHalf(mirrorPlane) - - for n2 in range(self.elementsCountUpFull + 1): - for n3 in range(self.elementsCountAlong+1): - for n1 in range(self.elementsCountAcross + 1): - if self.px[n3][n2][n1]: - node = nodes.createNode(nodeIdentifier, nodetemplate) - self.nodeId[n3][n2][n1] = nodeIdentifier - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, self.px [n3][n2][n1]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, self.pd1[n3][n2][n1]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, self.pd2[n3][n2][n1]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, self.pd3[n3][n2][n1]) - nodeIdentifier += 1 - - return nodeIdentifier - - - def generateElements(self, fieldmodule, coordinates, startElementIdentifier, 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 meshGroups: Zinc mesh groups to add elements to. - :return: next elementIdentifier. - """ - elementIdentifier = startElementIdentifier - useCrossDerivatives = False - mesh = fieldmodule.findMeshByDimension(3) - - tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) - eft = tricubichermite.createEftNoCrossDerivatives() - elementtemplate = mesh.createElementtemplate() - elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) - elementtemplate.defineField(coordinates, -1, eft) - - elementtemplate1 = mesh.createElementtemplate() - elementtemplate1.setElementShapeType(Element.SHAPE_TYPE_CUBE) - - isEven = (self.elementsCountAcross % 2) == 0 - e1a = self.elementsCountRim - e1b = e1a + 1 - e1z = self.elementsCountAcross - 1 - self.elementsCountRim - e1y = e1z - 1 - e2a = self.elementsCountRim - e2b = self.elementsCountRim + 1 - e2c = self.elementsCountRim + 2 - e2z = 2*self.elementsCountUp-1-self.elementsCountRim - e2y = e2z - 1 - e2x = e2z - 2 - for e3 in range(self.elementsCountAlong): - for e2 in range(self.elementsCountUpFull): - for e1 in range(self.elementsCountAcross): - eft1 = eft - scalefactors = None - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2 + 1][e1], - self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3+1][e2][e1 + 1], self.nodeId[e3+1][e2 + 1][e1 + 1] ] - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - nids = [self.nodeId[0][e2][e1], self.nodeId[0][e2][e1 + 1], self.nodeId[0][e2 + 1][e1],self.nodeId[0][e2 + 1][e1 + 1], - self.nodeId[1][e2][e1], self.nodeId[1][e2][e1 + 1], self.nodeId[1][e2 + 1][e1], self.nodeId[1][e2 + 1][e1 + 1]] - if (e2 < e2b) or (e2 > e2y): - if (e1 < e1b) or (e1 > e1y): - continue # no element due to triple point closure - if (e2 < e2a) or (e2 > e2z): - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - if e2 < e2a: - nids = [self.nodeId[e3][e2+1][e1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3+1][e2+1][e1+1], - self.nodeId[e3][e2][e1], self.nodeId[e3][e2][e1+1], self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2][e1+1]] - elif e2 > e2z: - nids = [self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2][e1], self.nodeId[e3+1][e2][e1+1], self.nodeId[e3+1][e2][e1], - self.nodeId[e3][e2+1][e1+1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2+1][e1+1], self.nodeId[e3+1][e2+1][e1]] - elif (e2 == e2a) or (e2 == e2z): - # bottom and top row elements - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - if e2 == e2a: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [])]) - if (e1 == e1b) or (e1 == e1y): - # map bottom triple point element - if e1 == e1b: - remapEftNodeValueLabel(eft1, [ 2, 4 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [] ), ( Node.VALUE_LABEL_D_DS3, [] ) ]) - else: - remapEftNodeValueLabel(eft1, [ 6, 8 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [] ), ( Node.VALUE_LABEL_D_DS3, [1] ) ]) - elif e2 == e2z: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS3, [])]) - if (e1 == e1b) or (e1 == e1y): - # map top triple point element - if e1 == e1b: - remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) - else: - remapEftNodeValueLabel(eft1, [5, 7], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS3, [])]) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - if (e1 == e1b) or (e1 == e1y): - # map bottom triple point element - eft1 = tricubichermite.createEftNoCrossDerivatives() - if e1 == e1b: - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [])]) - else: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [1]),(Node.VALUE_LABEL_D_DS2, [])]) - - elif (e2 == e2b) or (e2 == e2y): - if (e1 <= e1a) or (e1 >= e1z): - if e1 < e1a: - e2r = e1 - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - if e2 == e2b: - nids = [self.nodeId[e3][e2c][e1+1], self.nodeId[e3][e2r+1][e1b], self.nodeId[e3+1][e2c][e1+1], self.nodeId[e3+1][e2r+1][e1b], - self.nodeId[e3][e2c][e1], self.nodeId[e3][e2r][e1b], self.nodeId[e3+1][e2c][e1], self.nodeId[e3+1][e2r][e1b]] - if e2 == e2y: - e2r = 2*self.elementsCountUp - e1-1 - nids = [self.nodeId[e3][e2r][e1b], self.nodeId[e3][e2y][e1+1], self.nodeId[e3+1][e2r][e1b], self.nodeId[e3+1][e2y][e1+1], - self.nodeId[e3][e2r+1][e1b], self.nodeId[e3][e2y][e1], self.nodeId[e3+1][e2r+1][e1b], self.nodeId[e3+1][e2y][e1]] - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - nids[0] = self.nodeId[0][e2r ][e1b] - nids[1] = self.nodeId[0][e2r + 1][e1b] - nids[4] = self.nodeId[1][e2r ][e1b] - nids[5] = self.nodeId[1][e2r + 1][e1b] - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS2, [ ( Node.VALUE_LABEL_D_DS1, [1] ) ]) - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS2, [] ) ]) - elif e1 == e1a: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - if e2 == e2b: - nids[0] = self.nodeId[e3][e2a][e1b] - nids[2] = self.nodeId[e3+1][e2a][e1b] - tripleN = [5, 7] - remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [])]) - elif e2 == e2y: - nids[1] = self.nodeId[e3][e2z+1][e1b] - nids[3] = self.nodeId[e3+1][e2z+1][e1b] - tripleN = [6, 8] - remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [ 1, 2, 3, 4 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [1] ) ]) - remapEftNodeValueLabel(eft1, [ 1, 2, 3, 4 ], Node.VALUE_LABEL_D_DS3, [ ( Node.VALUE_LABEL_D_DS3, [1] ) ]) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - nids[0] = self.nodeId[0][e2a][e1b] - nids[4] = self.nodeId[1][e2a][e1b] - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [])]) - elif e1 == e1z: - eft1 = tricubichermite.createEftNoCrossDerivatives() - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - if e2 == e2b: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - nids[4] = self.nodeId[e3][e2a][e1z] - nids[6] = self.nodeId[e3+1][e2a][e1z] - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [ 1, 3 ], Node.VALUE_LABEL_D_DS3, [ ( Node.VALUE_LABEL_D_DS1, [1] ), ( Node.VALUE_LABEL_D_DS3, [] ) ]) - elif e2 == e2y: - nids[5] = self.nodeId[e3][e2z+1][e1z] - nids[7] = self.nodeId[e3+1][e2z+1][e1z] - remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [])]) - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - nids[1] = self.nodeId[0][e2a][e1z] - nids[5] = self.nodeId[1][e2a][e1z] - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [])]) - elif e1 > e1z: - e2r = self.elementsCountAcross - e1 - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - if e2 == e2b: - nids = [self.nodeId[e3][e2r][e1z], self.nodeId[e3][e2c][e1], self.nodeId[e3+1][e2r][e1z], self.nodeId[e3+1][e2c][e1], - self.nodeId[e3][e2r-1][e1z], self.nodeId[e3][e2c][e1+1], self.nodeId[e3+1][e2r-1][e1z], self.nodeId[e3+1][e2c][e1+1]] - elif e2 == e2y: - e2r = e2z+e1-e1z - nids[1] = self.nodeId[e3][e2r][e1z] - nids[3] = self.nodeId[e3+1][e2r][e1z] - nids[5] = self.nodeId[e3][e2r+1][e1z] - nids[7] = self.nodeId[e3+1][e2r+1][e1z] - elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - nids[0] = self.nodeId[0][e2r ][e1z] - nids[1] = self.nodeId[0][e2r - 1][e1z] - nids[4] = self.nodeId[1][e2r ][e1z] - nids[5] = self.nodeId[1][e2r - 1][e1z] - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS2, [1] ) ]) - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS2, [ ( Node.VALUE_LABEL_D_DS1, [] ) ]) - else: - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - if e1 < e1a: - nids = [ self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3][e2][e1 + 1], self.nodeId[e3+1][e2 + 1][e1 + 1], self.nodeId[e3+1][e2][e1 + 1], - self.nodeId[e3][e2 + 1][e1], self.nodeId[e3][e2][e1], self.nodeId[e3+1][e2 + 1][e1], self.nodeId[e3+1][e2][e1]] - elif e1 == e1a: - # map left column elements - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS3, [1])]) - - if eft1 is not eft: - elementtemplate1.defineField(coordinates, -1, eft1) - element = mesh.createElement(elementIdentifier, elementtemplate1) - else: - element = mesh.createElement(elementIdentifier, elementtemplate) - result2 = element.setNodesByIdentifier(eft1, nids) - if scalefactors: - result3 = element.setScaleFactors(eft1, scalefactors) - else: - result3 = 7 - #print('create element shield', elementIdentifier, result2, result3, nids) - if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.elementId[e3][e2][e1] = elementIdentifier - else: - self.elementId[e2][e1] = elementIdentifier - elementIdentifier += 1 - - for meshGroup in meshGroups: - meshGroup.addElement(element) - - return elementIdentifier + raise ValueError("Remapping for derivatives of this 'node type' is not implemented") diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 3efe9709..d2f81838 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -10,14 +10,13 @@ from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, interpolateSampleCubicHermite, \ smoothCubicHermiteDerivativesLine, interpolateSampleLinear, interpolateCubicHermite -from scaffoldmaker.utils.mirror import Mirror from scaffoldmaker.utils.cylindermesh import Ellipse2D, EllipseShape class SphereShape(Enum): SPHERE_SHAPE_FULL = 1 - SPHERE_SHAPE_HALF_NNP = 2 # NNP is a3>=0 - SPHERESHIELD_SHAPE_OCTANT_PPP = 3 + SPHERE_SHAPE_HALF_AAP = 2 # AAP is a hemisphere where x_a3>=0 + SPHERESHIELD_SHAPE_OCTANT_PPP = 3 # positive axis1, positive axis2, positive axis3 SPHERESHIELD_SHAPE_OCTANT_NPP = 4 SPHERESHIELD_SHAPE_OCTANT_PNP = 5 SPHERESHIELD_SHAPE_OCTANT_NNP = 6 @@ -39,14 +38,17 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. :param centre, axes: centre and axes of the sphere. - :param elementsCountAcross: [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] Total number of elements - across the sphere axes. + :param elementsCountAcross: [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + Total number of elements across the sphere axes. :param elementsCountAcrossShell, elementsCountAcrossTransition: Total number of elements across each axis consists of regular elements in the middle cube, transition elements from cube to a sphere (core boundary) and shell elements around it. Shell nodes and derivatives are similar to the core boundary and don't need - remapping. The topology of the shield structure is extended to 3D with a quadruple points. - :param sphereShape: A value from enum sphereMode specifying. Octant_PPP for example, is the octant in axis1>=0 - axis2>=0 and axis3>=0 + remapping. The topology of the shield structure is extended to 3D with quadruple points. + :param sphereShape: A value from enum SphereShape specifying the shape of sphere. Octant_PPP, for example is + the octant in positive axis1, positive axis2 and positive axis3. SPHERE_SHAPE_HALF_AAP is a hemisphere on + the positive side of axis3. + :param boxMapping: It is a list of [deriv1,deriv2,deriv3] and is used to change the derivatives names. + Default is [1, 3, 2] and [3, 1, 2] means swap 1 and 3. """ self._axes = axes @@ -58,8 +60,7 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, self._elementsCountAcrossTransition = elementsCountAcrossTransition self._elementsCountAcrossRim = self._elementsCountAcrossShell + self._elementsCountAcrossTransition - 1 self._shellProportion = shellProportion - self._elementsCountAround12 = 2 * (self._elementsCount[0] + self._elementsCount[1] - - 4*(self._elementsCountAcrossRim + 1)) + self._startNodeIdentifier = 1 self._startElementIdentifier = 1 self._endNodeIdentifier = 1 @@ -87,21 +88,33 @@ def createSphereMesh3d(self, fieldModule, coordinates): :param coordinates: Coordinate field to define. :return: Final values of nextNodeIdentifier, nextElementIdentifier. """ - # for i in range(3): - # assert (self._elementsCount[i] > 1), 'createSphereMesh3d: Invalid number of elements' - # assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ - # ' is not an even number' + if 'OCTANT' in str(self._sphereShape): + minimum = [2, 2, 2] + era = 0 + elif 'SPHERE_SHAPE_HALF_AAP' in str(self._sphereShape): + minimum = [4, 4, 2] + era = 2 + else: + minimum = [4, 4, 4] + era = 3 + + for i in range(3): + assert (self._elementsCount[i] >= minimum[i]), 'createSphereMesh3d: Invalid number of elements' + + for i in range(era): + assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ + ' is not an even number' - # assert (self._sphereShape in [self._sphereShape.SPHERE_SHAPE_FULL, - # self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ - # 'createSphereMesh3d: Invalid sphere mode.' + assert (self._sphereShape in [SphereShape.SPHERE_SHAPE_FULL, + SphereShape.SPHERE_SHAPE_HALF_AAP, + SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), 'createSphereMesh3d: Invalid sphere mode.' elementsCountRim = self._elementsCountAcrossRim if self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: shieldMode = ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP - elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: - shieldMode = ShieldShape3D.SHIELD_SHAPE_HALF_NNP + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_AAP: + shieldMode = ShieldShape3D.SHIELD_SHAPE_HALF_AAP elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL @@ -114,135 +127,77 @@ def createSphereMesh3d(self, fieldModule, coordinates): elementsCountAcrossTransition = self._elementsCountAcrossTransition shellProportion = self._shellProportion - if self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) - octant1 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant1, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) - elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP or self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: - if self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( - self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN) - octant5 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, - boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant5, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN) - - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( - self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN) - octant6 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, - boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant6, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN) - - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( - self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN) - octant7 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, - boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant7, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN) - - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count( - self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN) - octant8 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, - boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant8, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN) - - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) - octant1 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant1, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP) - - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP) - octant2 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant2, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP) + # order of octants is important because common nodes will overwrite + OctantVariationsAll = [SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN, SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN, + SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN, SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN, + SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP, + SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP, SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP] - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP) - octant3 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant3, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP) + if self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + OctantVariationsType = [SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP] + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_AAP: + OctantVariationsType = OctantVariationsAll[4:9] + else: + OctantVariationsType = OctantVariationsAll - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP) - octant4 = OctantMesh(fieldModule, coordinates, self._centre, axes, elementsCountAcross, + for octantType in OctantVariationsType: + axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(octantType) + octant = OctantMesh(self._centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) - self.copy_octant_nodes_to_sphere_shield(octant4, self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP) + self.copy_octant_nodes_to_sphere_shield(octant, octantType) self.sphere_to_spheroid() self.generateNodes(nodes, fieldModule, coordinates) self.generateElements(mesh, fieldModule, coordinates) - def sphere_to_spheroid(self): - """ - - :return: - """ - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - for n3 in range(self._elementsCount[2] + 1): - for n2 in range(self._elementsCount[0] + 1): - for n1 in range(self._elementsCount[1] + 1): - if btx[n3][n2][n1]: - btx[n3][n2][n1] = [self._radius[0] * btx[n3][n2][n1][0], self._radius[1] * btx[n3][n2][n1][1], self._radius[2] * btx[n3][n2][n1][2], ] - btd1[n3][n2][n1] = [self._radius[0] * btd1[n3][n2][n1][0], self._radius[1] * btd1[n3][n2][n1][1], self._radius[2] * btd1[n3][n2][n1][2], ] - btd2[n3][n2][n1] = [self._radius[0] * btd2[n3][n2][n1][0], self._radius[1] * btd2[n3][n2][n1][1], self._radius[2] * btd2[n3][n2][n1][2], ] - btd3[n3][n2][n1] = [self._radius[0] * btd3[n3][n2][n1][0], self._radius[1] * btd3[n3][n2][n1][1], self._radius[2] * btd3[n3][n2][n1][2], ] - def get_octant_axes_and_elements_count(self, octant_shape): """ - - :return: + Get the octants axes, elements count across and box mapping for 8 octants in 8 different regions. + :param octant_shape: A value from enum SphereShape specifying the shape of sphere + :return: axes, elementsCountAcross, boxMapping for the octant. """ + boxMappingV1 = self._boxMapping + boxMappingV2 = [self._boxMapping[1], self._boxMapping[0], self._boxMapping[2]] + axesV1 = [self._axes[0], self._axes[1], self._axes[2]] + axesV2 = [self._axes[1], self._axes[0], self._axes[2]] + elementsCountAcrossV1 = [c for c in self._elementsCount] + elementsCountAcrossV2 = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: - boxMapping = self._boxMapping - axes = self._axes - elementsCountAcross = [c for c in self._elementsCount] + octant_number = 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: - boxMapping = [self._boxMapping[1], -self._boxMapping[0], self._boxMapping[2]] - axes = [vector.scaleVector(self._axes[1], -1), vector.scaleVector(self._axes[0], 1), self._axes[2]] - elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + octant_number = 2 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: - boxMapping = [-self._boxMapping[0], -self._boxMapping[1], self._boxMapping[2]] - axes = [vector.scaleVector(self._axes[0], -1), vector.scaleVector(self._axes[1], -1), self._axes[2]] - elementsCountAcross = [c for c in self._elementsCount] + octant_number = 3 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: - boxMapping = [-self._boxMapping[1], self._boxMapping[0], self._boxMapping[2]] - axes = [vector.scaleVector(self._axes[1], 1), vector.scaleVector(self._axes[0], -1), self._axes[2]] - elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + octant_number = 4 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: - boxMapping = [-self._boxMapping[1], -self._boxMapping[0], -self._boxMapping[2]] - axes = [vector.scaleVector(self._axes[1], 1), vector.scaleVector(self._axes[0], 1), vector.scaleVector(self._axes[2], -1)] - elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + octant_number = 5 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: - boxMapping = [self._boxMapping[0], -self._boxMapping[1], -self._boxMapping[2]] - axes = [vector.scaleVector(self._axes[0], 1), vector.scaleVector(self._axes[1], -1), vector.scaleVector(self._axes[2], -1)] - elementsCountAcross = [self._elementsCount[0], self._elementsCount[1], self._elementsCount[2]] + octant_number = 6 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: - boxMapping = [self._boxMapping[1], self._boxMapping[0], -self._boxMapping[2]] - axes = [vector.scaleVector(self._axes[1], -1), vector.scaleVector(self._axes[0], -1), vector.scaleVector(self._axes[2], -1)] - elementsCountAcross = [self._elementsCount[1], self._elementsCount[0], self._elementsCount[2]] + octant_number = 7 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: - boxMapping = [-self._boxMapping[0], self._boxMapping[1], -self._boxMapping[2]] - axes = [vector.scaleVector(self._axes[0], -1), vector.scaleVector(self._axes[1], 1), vector.scaleVector(self._axes[2], -1)] - elementsCountAcross = [self._elementsCount[0], self._elementsCount[1], self._elementsCount[2]] + octant_number = 8 else: raise ValueError("Not implemented.") - if self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: + axesSignsV1 = [1 if str(octant_shape).split('_')[-1][c] == 'P' else -1 for c in range(3)] + axesSignsV2 = [axesSignsV1[1], axesSignsV1[0], axesSignsV1[2]] + + signs = self._shield3D.get_octant_signs(octant_number) + if octant_number in [2, 4, 5, 7]: + boxMapping = [boxMappingV2[c] * signs[c] for c in range(3)] + elementsCountAcross = elementsCountAcrossV2 + axes = [vector.scaleVector(axesV2[c], axesSignsV2[c]) for c in range(3)] + else: + boxMapping = [boxMappingV1[c] * signs[c] for c in range(3)] + elementsCountAcross = elementsCountAcrossV1 + axes = [vector.scaleVector(axesV1[c], axesSignsV1[c]) for c in range(3)] + + if self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_AAP: elementsCountAcross[0] = elementsCountAcross[0]//2 elementsCountAcross[1] = elementsCountAcross[1]//2 elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: @@ -255,8 +210,9 @@ def get_octant_axes_and_elements_count(self, octant_shape): def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): """ - - :param octant: + Copy octant nodes to sphere shield. + :param octant: octant instance. + :param octant_shape: A value from enum SphereShape specifying the shape of sphere :return: """ n3a = 0 @@ -265,128 +221,98 @@ def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): n2z = self._elementsCount[0] n1a = 0 n1z = self._elementsCount[1] - c13, c23 = 0, 1 if self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + octant_number = 1 n3a = self._elementsCount[2]//2 n2z = self._elementsCount[0]//2 n1a = self._elementsCount[1]//2 - c11, c21 = -n1a, 1 - c12, c22 = 0, 1 - c13, c23 = -self._elementsCount[2]//2, 1 - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: - n3a = self._elementsCount[2]//2 - n2a = self._elementsCount[0]//2 - n1a = self._elementsCount[1]//2 - c11, c21 = n1z, -1 - c12, c22 = -n2a, 1 - c13, c23 = -self._elementsCount[2] // 2, 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: + octant_number = 2 n3a = self._elementsCount[2]//2 n2z = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 - c11, c21 = -n1a, 1 - c12, c22 = n2z, -1 - c13, c23 = -self._elementsCount[2] // 2, 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: + octant_number = 3 n3a = self._elementsCount[2]//2 n2a = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 - c11, c21 = n1z, -1 - c12, c22 = n2z, -1 - c13, c23 = -self._elementsCount[2] // 2, 1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: + octant_number = 4 + n3a = self._elementsCount[2]//2 + n2a = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: + octant_number = 5 n3z = self._elementsCount[2]//2 n2z = self._elementsCount[0]//2 n1a = self._elementsCount[1]//2 - c11, c21 = n1z, -1 - c12, c22 = n2z, -1 - c13, c23 = self._elementsCount[2] // 2, -1 - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: - n3z = self._elementsCount[2]//2 - n2a = self._elementsCount[0]//2 - n1a = self._elementsCount[1]//2 - c11, c21 = -n1a, 1 - c12, c22 = n2z, -1 - c13, c23 = self._elementsCount[2] // 2, -1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: + octant_number = 6 n3z = self._elementsCount[2]//2 n2z = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 - c11, c21 = n1z, -1 - c12, c22 = -n2a, 1 - c13, c23 = self._elementsCount[2] // 2, -1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: + octant_number = 7 n3z = self._elementsCount[2]//2 n2a = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 - c11, c21 = n1a, 1 - c12, c22 = -n2a, 1 - c13, c23 = self._elementsCount[2] // 2, -1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: + octant_number = 8 + n3z = self._elementsCount[2]//2 + n2a = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 else: raise ValueError("Not implemented.") - elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_NNP: + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_AAP: if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + octant_number = 1 n2z = self._elementsCount[0]//2 n1a = self._elementsCount[1]//2 - c11, c21 = -n1a, 1 - c12, c22 = 0, 1 - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: - n2a = self._elementsCount[0]//2 - n1a = self._elementsCount[1]//2 - c11, c21 = n1z, -1 - c12, c22 = -n2a, 1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: + octant_number = 2 n2z = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 - c11, c21 = -n1a, 1 - c12, c22 = n2z, -1 elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: + octant_number = 3 n2a = self._elementsCount[0]//2 n1z = self._elementsCount[1]//2 - c11, c21 = n1z, -1 - c12, c22 = n2z, -1 + elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: + octant_number = 4 + n2a = self._elementsCount[0]//2 + n1a = self._elementsCount[1]//2 elif self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: - c11, c21 = 0, 1 - c12, c22 = 0, 1 + octant_number = 1 else: raise ValueError("Not implemented.") for n3 in range(n3a, n3z + 1): for n2 in range(n2a, n2z + 1): for n1 in range(n1a, n1z + 1): - n3o, n2o, n1o = self.shield_index_mapping(c13 + c23*n3, c12 + c22*n2, c11 + c21*n1, octant_shape) + n3o, n2o, n1o = self._shield3D.get_octant_node_index(octant_number, n3, n2, n1) self._shield3D.px[n3][n2][n1] = octant._shield3D.px[n3o][n2o][n1o] self._shield3D.pd1[n3][n2][n1] = octant._shield3D.pd1[n3o][n2o][n1o] self._shield3D.pd2[n3][n2][n1] = octant._shield3D.pd2[n3o][n2o][n1o] self._shield3D.pd3[n3][n2][n1] = octant._shield3D.pd3[n3o][n2o][n1o] - def shield_index_mapping(self, n3r, n2r, n1r, octant_shape): + def sphere_to_spheroid(self): """ - + Using the radius in each direction,transform the sphere to ellipsoid. :return: """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 - if octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: - n3o, n2o, n1o = n3r, n2r, n1r - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPP: - n3o, n2o, n1o = n3r, n1r, n2r - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNP: - n3o, n2o, n1o = n3r, n1r, n2r - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNP: - n3o, n2o, n1o = n3r, n2r, n1r - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPN: - n3o, n2o, n1o = n3r, n1r, n2r - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NPN: - n3o, n2o, n1o = n3r, n2r, n1r - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PNN: - n3o, n2o, n1o = n3r, n2r, n1r - elif octant_shape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_NNN: - n3o, n2o, n1o = n3r, n1r, n2r - else: - raise ValueError("Not implemented.") - - return n3o, n2o, n1o + for n3 in range(self._elementsCount[2] + 1): + for n2 in range(self._elementsCount[0] + 1): + for n1 in range(self._elementsCount[1] + 1): + if btx[n3][n2][n1]: + btx[n3][n2][n1] = [self._radius[c] * btx[n3][n2][n1][c] for c in range(3)] + btd1[n3][n2][n1] = [self._radius[c] * btd1[n3][n2][n1][c] for c in range(3)] + btd2[n3][n2][n1] = [self._radius[c] * btd2[n3][n2][n1][c] for c in range(3)] + btd3[n3][n2][n1] = [self._radius[c] * btd3[n3][n2][n1][c] for c in range(3)] def generateNodes(self, nodes, fieldModule, coordinates): """ @@ -415,26 +341,25 @@ def generateElements(self, mesh, fieldModule, coordinates): class OctantMesh: """ - Sphere mesh generator. + Octant mesh generator. """ - def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, + def __init__(self, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. - :param centre, axes: centre and axes of the sphere. + :param centre, axes: centre and axes of the octant. :param elementsCountAcross: [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] Total number of elements - across the sphere axes. + across the octant axes. :param elementsCountAcrossShell, elementsCountAcrossTransition: Total number of elements across each axis consists of regular elements in the middle cube, transition elements from cube to a sphere (core boundary) and shell elements around it. Shell nodes and derivatives are similar to the core boundary and don't need remapping. The topology of the shield structure is extended to 3D with a quadruple points. - :param sphereShape: A value from enum sphereMode specifying. Octant_PPP for example, is the octant in axis1>=0 - axis2>=0 and axis3>=0 + :param sphereShape: A value from enum SphereShape specifying one of the 8 octant regions. Octant_PPP for example, + is the octant in positive axis1, positive axis2 and positive axis3. """ - self._axes = axes self._radius = [vector.magnitude(axis) for axis in axes] self._coreRadius = [] @@ -444,12 +369,7 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, self._elementsCountAcrossTransition = elementsCountAcrossTransition self._elementsCountAcrossRim = self._elementsCountAcrossShell + self._elementsCountAcrossTransition - 1 self._shellProportion = shellProportion - self._elementsCountAround12 = 2 * (self._elementsCount[0] + self._elementsCount[1] - - 4*(self._elementsCountAcrossRim + 1)) - self._startNodeIdentifier = 1 - self._startElementIdentifier = 1 - self._endNodeIdentifier = 1 - self._endElementIdentifier = 1 + self._sphereShape = sphereShape self._useCrossDerivatives = useCrossDerivatives @@ -464,24 +384,12 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, (1 - shellProportion * elementsCountAcrossShell / elementsAxis) * self._radius[i]) # generate the mesh - self.createOctantMesh3d(fieldModule, coordinates) + self.createOctantMesh3d() - def createOctantMesh3d(self, fieldModule, coordinates): + def createOctantMesh3d(self): """ - Create a sphere mesh based on the shield topology. - :param fieldModule: Zinc fieldModule to create elements in. - :param coordinates: Coordinate field to define. - :return: Final values of nextNodeIdentifier, nextElementIdentifier. + Create an octant mesh based on the shield topology. """ - # for i in range(3): - # assert (self._elementsCount[i] > 1), 'createSphereMesh3d: Invalid number of elements' - # assert (self._elementsCount[i] % 2 == 0), 'createSphereMesh3d: number of across elements' \ - # ' is not an even number' - - # assert (self._sphereShape in [self._sphereShape.SPHERE_SHAPE_FULL, - # self._sphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ - # 'createSphereMesh3d: Invalid sphere mode.' - elementsCountRim = self._elementsCountAcrossRim self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP) @@ -492,10 +400,9 @@ def createOctantMesh3d(self, fieldModule, coordinates): def create_boundary_ellipses_nodes(self): """ - + Use ellipse class to create 3 ellipses needed for the octant. :return: """ - centre = self._centre elementsCountAcrossShell = self._elementsCountAcrossShell elementsCountAcrossTransition = self._elementsCountAcrossTransition @@ -513,6 +420,11 @@ def create_boundary_ellipses_nodes(self): (2 * self._elementsCount[2], 2 * self._elementsCount[1]), (2 * self._elementsCount[0], 2 * self._elementsCount[2])] + # set derivatives in up and right direction for each ellipse in square region and the circle around. + # We need to do this so the octant derivatives comes out as we want. + squareDerivatives = [[1, 3], [2, 3], [1, -2]] + circleDerivatives = [[1, 3], [2, 3], [-2, 3]] + for i in range(3): majorAxis = ellipseAxes[i][0] minorAxis = ellipseAxes[i][1] @@ -526,17 +438,12 @@ def create_boundary_ellipses_nodes(self): elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) - self.copy_ellipses_nodes_to_shield_nodes(ellipse, i) + self.copy_ellipses_nodes_to_shield_nodes(ellipse, i+1, squareDerivatives[i], circleDerivatives[i]) - def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): + def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipse_number, squareDerivatives, circleDerivatives): """ Copy coordinates and derivatives of ellipse to shield. - :param n3: the index number of ellipse along the central path. """ - n1z = self._elementsCount[1] - n2z = self._elementsCount[0] - n3z = self._elementsCount[2] - btx = self._shield3D.px btd1 = self._shield3D.pd1 btd2 = self._shield3D.pd2 @@ -544,81 +451,63 @@ def copy_ellipses_nodes_to_shield_nodes(self, ellipse, ellipsenumber): shield = ellipse.getShield() - # Modify the shield12 to get only the quarter that you want. make others None so you can generate the nodes. - if ellipsenumber == 0: - for n2 in range(self._elementsCount[0] + 1): # TODO modify this to number of elements. - for n1 in range(self._elementsCount[1] + 1): - # only first quadrant is needed TODO we need to modify this to number of elements half of the elments across each direction. - # btd2[0][n2][n1] = [c for c in alongAxis] - if n2 == 0 and n1 == self._elementsCount[1] - 1: - n1s = n1 + 1 - else: - n1s = n1 - n1e = n1 + self._elementsCount[1] - if shield.px[0][n2][n1e]: - btx[0][n2][n1s] = shield.px[0][n2][n1e] - btd1[0][n2][n1s] = shield.pd1[0][n2][n1e] - btd2[0][n2][n1s] = shield.pd2[0][n2][n1e] - btd3[0][n2][n1s] = shield.pd3[0][n2][n1e] - elif ellipsenumber == 1: - shield.remap_derivatives([2, 3], circleMapping=[2, 3]) - n2s = self._elementsCount[0] - for n3 in range(self._elementsCount[2] + 1): + # Modify the shield to get only the quarter that you want. make others None so you can generate the nodes. + shield.remap_derivatives(squareDerivatives, circleMapping=circleDerivatives) + for n3 in range(self._elementsCount[2] + 1): + for n2 in range(self._elementsCount[0] + 1): for n1 in range(self._elementsCount[1] + 1): - # btd2[n3][n2s][n1] = [c for c in alongAxis] - if n3 == self._elementsCount[2] and n1 == self._elementsCount[1] - 1: - n1s = n1 + 1 - else: - n1s = n1 - n2e = n3 + self._elementsCount[2] - n1e = n1 + self._elementsCount[1] - if n3 == 0: - if n1 == self._elementsCount[1]: - btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] - else: - btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] - else: - if shield.px[0][n2e][n1 + self._elementsCount[1]]: - btx[n3][n2s][n1s] = [c for c in shield.px[0][n2e][n1e]] - btd1[n3][n2s][n1s] = [c for c in shield.pd1[0][n2e][n1e]] - btd2[n3][n2s][n1s] = [c for c in shield.pd2[0][n2e][n1e]] - btd3[n3][n2s][n1s] = [c for c in shield.pd3[0][n2e][n1e]] - elif ellipsenumber == 2: - shield.remap_derivatives([1, -2], circleMapping=[-2, 3]) - n1s = 0 - for n3 in range(self._elementsCount[2] + 1): - for n2 in range(self._elementsCount[0] + 1): - - if n2 == 0 and n3 == self._elementsCount[2] - 1: - n3s = self._elementsCount[2] - else: - n3s = n3 - n1e = self._elementsCount[2] - n3 - if n3 == 0: - if n2 == 0: - btd2[n3][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] - elif 0 < n2 < self._elementsCount[0]: - btd2[n3][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] - else: + n3s, n2s, n1s = n3, n2, n1 + n3e, n2e, n1e = 0, n2, n1 + if ellipse_number == 1: + if n3 > 0: + continue + if n2 == 0 and n1 == self._elementsCount[1] - 1: + n1s = n1 + 1 + n1e = n1 + self._elementsCount[1] + elif ellipse_number == 2: if n2 < self._elementsCount[0]: - # btd2[n3][n2][n1s] = [c for c in alongAxis] - if shield.px[0][n2][n1e]: - btx[n3s][n2][n1s] = [c for c in shield.px[0][n2][n1e]] - btd1[n3s][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] - btd2[n3s][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] - btd3[n3s][n2][n1s] = [c for c in shield.pd3[0][n2][n1e]] - else: - if n3 == self._elementsCount[2]: - btd1[n3][n2][n1s] = [c for c in shield.pd2[0][n2][n1e]] + continue + if n3 == self._elementsCount[2] and n1 == self._elementsCount[1] - 1: + n1s = n1 + 1 + n2e = n3 + self._elementsCount[2] + n1e = n1 + self._elementsCount[1] + if n3 == 0: + if n1 == self._elementsCount[1]: + btd2[n3][n2s][n1s] = shield.pd2[0][n2e][n1e] else: - btd1[n3][n2][n1s] = [c for c in shield.pd1[0][n2][n1e]] + btd2[n3][n2s][n1s] = shield.pd2[0][n2e][n1e] + continue + elif ellipse_number == 3: + if n1 > 0: + continue + if n2 == 0 and n3 == self._elementsCount[2] - 1: + n3s = self._elementsCount[2] + n1e = self._elementsCount[2] - n3 + if n3 == 0: + if n2 == 0: + btd2[n3][n2][n1s] = shield.pd2[0][n2][n1e] + elif 0 < n2 < self._elementsCount[0]: + btd2[n3][n2][n1s] = shield.pd2[0][n2][n1e] + continue + else: + if n2 == self._elementsCount[0]: + if n3 == self._elementsCount[2]: + btd1[n3][n2][n1s] = shield.pd2[0][n2][n1e] + else: + btd1[n3][n2][n1s] = shield.pd1[0][n2][n1e] + continue + + if shield.px[n3e][n2e][n1e]: + btx[n3s][n2s][n1s] = shield.px[n3e][n2e][n1e] + btd1[n3s][n2s][n1s] = shield.pd1[n3e][n2e][n1e] + btd2[n3s][n2s][n1s] = shield.pd2[n3e][n2e][n1e] + btd3[n3s][n2s][n1s] = shield.pd3[n3e][n2e][n1e] def create_surface_and_interior_nodes(self): """ - + Create octant exterior surface nodes and interior nodes :return: """ - self.calculate_surface_quadruple_point() self.sample_triple_curves_on_sphere() self.sample_regular_curves_on_sphere() @@ -630,7 +519,6 @@ def calculate_surface_quadruple_point(self): Calculate coordinates and derivatives of the quadruple point on the surface, where 3 hex elements merge. :return: """ - btx = self._shield3D.px btd1 = self._shield3D.pd1 btd2 = self._shield3D.pd2 @@ -642,8 +530,6 @@ def calculate_surface_quadruple_point(self): n3z = self._elementsCount[2] n3y = n3z - 1 - radius = self._radius[0] # TODO need to be changed for spheroid - elementsAroundEllipse12 = self._elementsCount[0] + self._elementsCount[1] - 2 radiansAroundEllipse12 = math.pi / 2 radiansPerElementAroundEllipse12 = radiansAroundEllipse12 / elementsAroundEllipse12 @@ -654,7 +540,6 @@ def calculate_surface_quadruple_point(self): theta_2 = n3y * radiansPerElementAroundEllipse13 theta_3 = n1y * radiansPerElementAroundEllipse12 phi_3 = calculate_azimuth(theta_3, theta_2) - # We assume it is a sphere not a spheroid for now. TODO Use the relations for spheroid instead # ratio = -0.1 * (min(self._elementsCount) - 2) + 1 if self._elementsCount[0] <= 2 else 0.2 ratio = 1 # local_x = intersection_of_two_great_circles_on_sphere(btx[0][0][n1y-1], btx[n3z][n2z][n1z], btx[0][2][n1z], btx[n3z][0][0]) @@ -674,10 +559,6 @@ def sample_triple_curves_on_sphere(self): Sample points on the triple curves of the 'quadruple point' on the sphere surface. :return: """ - n1z = self._elementsCount[1] - n2z = self._elementsCount[0] - n3z = self._elementsCount[2] - # sample on curve 1 of the triple curves and smooth the end derivatives. n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, index_output=True) n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, cx=1, index_output=True) @@ -733,17 +614,54 @@ def sample_regular_curves_on_sphere(self): def create_interior_nodes(self): """ - + Create box nodes. :return: """ - self.calculate_interior_quadruple_point() self.sample_interior_curves() self.smooth_regular_interior_curves() + def smooth_derivatives_to_surface(self): + """ + Smooth derivatives leading to quadruple point where 3 hex elements merge. + :return: + """ + n3z = self._elementsCount[2] + n1z = self._elementsCount[1] + + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + for n3 in range(1, self._elementsCount[2] + 1): + for n2 in range(self._elementsCount[0]): + for n1 in range(1, self._elementsCount[1]+1): + if self.on_sphere(n3, n2, n1): + # find indices of the neighbour node inside and contribution of its derivatives. + n3r = n3 - 1 if n3 == n3z else n3 + n2r = n2 + 1 if n2 == 0 else n2 + n1r = n1 - 1 if n1 == n1z else n1 + co = [-1, 1, 1] + co[0] = -1 if n2 == 0 else 0 + co[1] = 1 if n3 == n3z else 0 + co[2] = 1 if n1 == n1z else 0 + + tx = [] + td3 = [] + tx.append(btx[n3r][n2r][n1r]) + td3.append( + [(co[0]*btd1[n3r][n2r][n1r][c] + co[1]*btd2[n3r][n2r][n1r][c] + co[2]*btd3[n3r][n2r][n1r][c]) for c in range(3)]) + + tx.append(btx[n3][n2][n1]) + td3.append(btd3[n3][n2][n1]) + + td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) + btd3[n3][n2][n1] = td3[1] + def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStart, dbetween, dEnd): """ - samples curves on the sphere surface between two points given by their indexes. + Samples curves on the sphere surface between two points given by their indexes. :param id1, id2: [n3,n2,n1] for the first and second points. :param dStart, dBetween, dEnd: Specifies the derivatives that are used for this curve at the beginning, end and in between. e.g. dStart=[2, -1, None] means d2 for the first node, -d1 for the second node and skip the third one. @@ -809,7 +727,6 @@ def smooth_derivatives_regular_surface_curve(self, constant_index, nc, dStart, d the values are given for two curves that connect one end to the other end of the sphere surface. :return: """ - btx = self._shield3D.px btd1 = self._shield3D.pd1 btd2 = self._shield3D.pd2 @@ -897,7 +814,7 @@ def smooth_derivatives_regular_surface_curve(self, constant_index, nc, dStart, d def calculate_interior_quadruple_point(self): """ - + Calculate coordinates and derivatives of the quadruple point inside, where 3 hex elements merge. :return: """ btx = self._shield3D.px @@ -934,7 +851,7 @@ def calculate_interior_quadruple_point(self): def sample_interior_curves(self): """ - + Sample box curves. :return: """ btx = self._shield3D.px @@ -948,33 +865,6 @@ def sample_interior_curves(self): n3y = n3z - 1 n2z = self._elementsCount[0] - # btd = {1: btd1, 2: btd2, 3: btd3} - - - # - # n3s = [[n3y, n3y, 0, 0], [n3y, n3y, 0, 0], [0, n3y, 0, n3y]] - # n2s = [[1, 1, 1, 1], [1, n2z, 1, n2z], [1, 1, 1, 1]] - # n1s = [[0, n1y, 0, n1y], [n1y, n1y, n1y, n1y], [n1y, n1y, 0, 0]] - # - # n3x2 = n3y - # n3d1 = 0 - # n2x1 = 1 - # n2d1 = 1 - # n1x2 = n1y - # for nic in range(3): - # n3x1 = 0 if nic == 2 else n3y - # n3d2 = n3y if nic == 2 else 0 - # n2x2 = n2z if nic == 1 else 1 - # n2d2 = n2z if nic == 1 else 1 - # n1x1 = 0 if nic == 1 else n1y - # n1d1 = n1y if nic == 1 else 0 - # n1d2 = 0 if nic == 2 else n1y - # - # tx, td = sampleCubicHermiteCurves([btx[n3x1][n2x1][n1x1], btx[n3x2][n2x2][n1x2]], - # [btd[nic][n3d1][n2d1][n1d1], btd[nic][n3d2][n2d2][n1d2]], self._elementsCount[nic] - 1)[:2] - # - # for ni in range(ni0, self._elementsCount[nic] - 1 + ni0) - tx, td1 = sampleCubicHermiteCurves([btx[n3y][1][n1y], btx[n3y][n2z][n1y]], [btd1[0][1][n1y], btd1[0][n2z][n1y]], self._elementsCount[0] - 1)[:2] @@ -984,7 +874,7 @@ def sample_interior_curves(self): btd2[n3y][n2][n1y] = [0.0, 0.0, (btx[n3z][n2][n1z][2] - btx[n3y][n2][n1y][2])] btd3[n3y][n2][n1y] = [0.0, (btx[n3z][n2][n1z][1] - btx[n3y][n2][n1y][1]), 0.0] - # curve 2 and parallel curves TODO change all [1] to n3y. + # curve 2 and parallel curves for n2 in range(1, self._elementsCount[0]): tx, td3 = sampleCubicHermiteCurves([btx[n3y][n2][0], btx[n3y][n2][n1y]], [btd3[0][n2][0], btd3[0][n2][n1y]], self._elementsCount[1] - 1)[:2] @@ -1002,9 +892,6 @@ def sample_interior_curves(self): btd1[n3y][n2][n1] = vector.addVectors([btx[n3y][n2][n1], btx[n3y][n2+1][n1]], [-1, 1]) btd2[n3y][n2][n1] = vector.addVectors([btx[n3y][n2][n1], btx[0][n2][n1]], [1, -1]) - - - # sample along curve0_3 for n2 in range(1, self._elementsCount[0]): for n1 in range(1, self._elementsCount[1]): @@ -1027,7 +914,7 @@ def sample_interior_curves(self): def smooth_regular_interior_curves(self): """ - + Smooth box curves. :return: """ btx = self._shield3D.px @@ -1097,9 +984,12 @@ def smooth_regular_interior_curves(self): def get_triple_curves_end_node_parameters(self, rx, cx=None, index_output=False): """ - :param cx: - :param rx: - :return: + Find the indexes or node parameters for the 6 end nodes of unique curves of triple curves on the surface and inside. + if cx is not given, it returns the quadruple points identified by rx. + :param cx: curve index. Curve 1 connects quadruples to ellipse 23. + Similarly, curve 2, connects quadruples to ellipse 13 + :param rx: 1 means on the exterior surface, 0 in one below. + :return: indexes of the point or the node parameters. """ btx = self._shield3D.px btd1 = self._shield3D.pd1 @@ -1137,44 +1027,6 @@ def get_triple_curves_end_node_parameters(self, rx, cx=None, index_output=False) else: return btx[n3r][n2r][n1r], btd1[n3r][n2r][n1r], btd2[n3r][n2r][n1r], btd3[n3r][n2r][n1r] - def smooth_derivatives_to_surface(self): - ''' - Smooth derivatives leading to quadruple point where 3 hex elements merge. - :param n3: Index of through-wall coordinates to use. - ''' - n3z = self._elementsCount[2] - n1z = self._elementsCount[1] - - btx = self._shield3D.px - btd1 = self._shield3D.pd1 - btd2 = self._shield3D.pd2 - btd3 = self._shield3D.pd3 - - for n3 in range(1, self._elementsCount[2] + 1): - for n2 in range(self._elementsCount[0]): - for n1 in range(1, self._elementsCount[1]+1): - if self.on_sphere(n3, n2, n1): - # find indices of the neighbour node inside and contribution of its derivatives. - n3r = n3 - 1 if n3 == n3z else n3 - n2r = n2 + 1 if n2 == 0 else n2 - n1r = n1 - 1 if n1 == n1z else n1 - co = [-1, 1, 1] - co[0] = -1 if n2 == 0 else 0 - co[1] = 1 if n3 == n3z else 0 - co[2] = 1 if n1 == n1z else 0 - - tx = [] - td3 = [] - tx.append(btx[n3r][n2r][n1r]) - td3.append( - [(co[0]*btd1[n3r][n2r][n1r][c] + co[1]*btd2[n3r][n2r][n1r][c] + co[2]*btd3[n3r][n2r][n1r][c]) for c in range(3)]) - - tx.append(btx[n3][n2][n1]) - td3.append(btd3[n3][n2][n1]) - - td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) - btd3[n3][n2][n1] = td3[1] - def on_sphere(self, n3, n2, n1): """ Check if the given point is on the sphere. From 2391c82c94c98d85970b8ac97a64d3da754bef9c Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 6 Oct 2021 13:33:34 +1300 Subject: [PATCH 26/37] Add unittest for sphere mesh. --- tests/test_sphere.py | 66 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/test_sphere.py diff --git a/tests/test_sphere.py b/tests/test_sphere.py new file mode 100644 index 00000000..4124b720 --- /dev/null +++ b/tests/test_sphere.py @@ -0,0 +1,66 @@ +import unittest +import copy +from opencmiss.utils.zinc.finiteelement import evaluateFieldNodesetRange +from opencmiss.utils.zinc.general import ChangeManager +from opencmiss.zinc.context import Context +from opencmiss.zinc.field import Field +from opencmiss.zinc.result import RESULT_OK +from scaffoldmaker.meshtypes.meshtype_3d_solidsphere2 import MeshType_3d_solidsphere2 +from testutils import assertAlmostEqualList + + +class SphereScaffoldTestCase(unittest.TestCase): + + def test_sphere1(self): + """ + Test creation of Sphere scaffold. + """ + scaffold = MeshType_3d_solidsphere2 + parameterSetNames = scaffold.getParameterSetNames() + self.assertEqual(parameterSetNames, ["Default"]) + options = scaffold.getDefaultOptions("Default") + self.assertEqual(15, len(options)) + self.assertEqual(4, options.get("Number of elements across axis 1")) + self.assertEqual(4, options.get("Number of elements across axis 2")) + self.assertEqual(4, options.get("Number of elements across axis 3")) + self.assertEqual(0, options.get("Number of elements across shell")) + self.assertEqual(1, options.get("Number of elements across transition")) + self.assertEqual(1.0, options.get("Radius1")) + self.assertEqual(1.0, options.get("Radius2")) + self.assertEqual(1.0, options.get("Radius3")) + self.assertEqual(1.0, options.get("Shell element thickness proportion")) + context = Context("Test") + region = context.getDefaultRegion() + self.assertTrue(region.isValid()) + annotationGroups = scaffold.generateMesh(region, options) + self.assertEqual(0, len(annotationGroups)) + fieldmodule = region.getFieldmodule() + mesh3d = fieldmodule.findMeshByDimension(3) + self.assertEqual(32, mesh3d.getSize()) + mesh2d = fieldmodule.findMeshByDimension(2) + self.assertEqual(108, mesh2d.getSize()) + mesh1d = fieldmodule.findMeshByDimension(1) + self.assertEqual(128, mesh1d.getSize()) + nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + self.assertEqual(53, nodes.getSize()) + datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) + self.assertEqual(0, datapoints.getSize()) + + # check coordinates range, sphere volume + coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() + self.assertTrue(coordinates.isValid()) + minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) + assertAlmostEqualList(self, minimums, [-1.0, -1.0, -1.0], 1.0E-6) + assertAlmostEqualList(self, maximums, [ 1.0, 1.0, 1.0 ], 1.0E-6) + with ChangeManager(fieldmodule): + one = fieldmodule.createFieldConstant(1.0) + volumeField = fieldmodule.createFieldMeshIntegral(one, coordinates, mesh3d) + volumeField.setNumbersOfPoints(3) + fieldcache = fieldmodule.createFieldcache() + result, volume = volumeField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(volume, 4.093180374780382, delta=1.0E-3) + + +if __name__ == "__main__": + unittest.main() From ff5b6b47168a80858b1c5776c56c62c414eee18b Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 6 Oct 2021 17:30:36 +1300 Subject: [PATCH 27/37] Add box and transition groups. --- .../meshtypes/meshtype_3d_solidsphere2.py | 15 ++++++++++++--- src/scaffoldmaker/utils/shieldmesh.py | 8 ++++++++ src/scaffoldmaker/utils/spheremesh.py | 5 +++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 24d50e80..db2a03eb 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -16,6 +16,7 @@ from opencmiss.zinc.field import Field from scaffoldmaker.utils.spheremesh import SphereMesh, SphereShape from scaffoldmaker.utils import vector +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup class MeshType_3d_solidsphere2(Scaffold_base): @@ -210,6 +211,14 @@ def generateBaseMesh(region, options): fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) + mesh = fm.findMeshByDimension(3) + boxGroup = AnnotationGroup(region, ("box group", "")) + boxMeshGroup = boxGroup.getMeshGroup(mesh) + transitionGroup = AnnotationGroup(region, ("transition group", "")) + transitionMeshGroup = transitionGroup.getMeshGroup(mesh) + meshGroups = [boxMeshGroup, transitionMeshGroup] + annotationGroups = [boxGroup, transitionGroup] + centre = [0.0, 0.0, 0.0] axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] @@ -219,10 +228,10 @@ def generateBaseMesh(region, options): sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=sphere_shape, useCrossDerivatives=False) + sphereShape=sphere_shape, useCrossDerivatives=False, meshGroups=meshGroups) + + return annotationGroups - annotationGroup = [] - return annotationGroup @classmethod def refineMesh(cls, meshRefinement, options): diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 802b2200..f44e1eab 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -1318,6 +1318,14 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes elementIdentifier += 1 + if element_type == self.ELEMENT_REGULAR: + for meshGroup in meshGroups[:1]: + meshGroup.addElement(element) + else: + for meshGroup in meshGroups[1:2]: + meshGroup.addElement(element) + + return elementIdentifier def local_node_mapping(self, boxMapping): diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index d2f81838..d029a5d6 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -33,7 +33,7 @@ class SphereMesh: def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None): + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None, meshGroups=[]): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. @@ -72,6 +72,7 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, self._centre = centre self._boxMapping = boxMapping if boxMapping else [1, 3, 2] + self._meshGroups = meshGroups for i in range(3): elementsAxis = elementsCountAcross[i] - elementsCountAcrossShell * (1 - shellProportion) @@ -335,7 +336,7 @@ def generateElements(self, mesh, fieldModule, coordinates): """ elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1) self._startElementIdentifier = elementIdentifier - elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, []) + elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, self._meshGroups) self._endElementIdentifier = elementIdentifier From 2f63932986f62460ef200ddce99f6796b065fd91 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Wed, 20 Oct 2021 11:04:29 +1300 Subject: [PATCH 28/37] Fix non-conforming mesh issue and make quadruple curve almost linear. --- src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py | 6 +++--- src/scaffoldmaker/utils/shieldmesh.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index db2a03eb..84c62495 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -67,7 +67,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Full': True, 'Use cross derivatives': False, 'Refine': False, - 'Refine number of elements across': 1, + 'Refine number of elements': 1, } return options @@ -88,7 +88,7 @@ def getOrderedOptionNames(): 'Hemisphere', 'Full', 'Refine', - 'Refine number of elements across' + 'Refine number of elements' ] @classmethod @@ -241,5 +241,5 @@ def refineMesh(cls, meshRefinement, options): :param options: Dict containing options. See getDefaultOptions(). """ assert isinstance(meshRefinement, MeshRefinement) - refineElementsCountAcross = options['Refine number of elements across'] + refineElementsCountAcross = options['Refine number of elements'] meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcross, refineElementsCountAcross, refineElementsCountAcross) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index f44e1eab..f558c398 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -1111,6 +1111,7 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if e2o == e2bo: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_2_UP) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.QUADRUPLE0_UP) self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_UP) if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) From a4525b1342850d9f2a5aaa860105b04c2fe6fcd7 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Thu, 21 Oct 2021 14:26:24 +1300 Subject: [PATCH 29/37] Make a new feature for box derivatives. It enables the user to choose derivatives in the box region. --- .../meshtypes/meshtype_3d_solidsphere2.py | 12 +- src/scaffoldmaker/utils/shieldmesh.py | 320 ++++++++++++++---- src/scaffoldmaker/utils/spheremesh.py | 30 +- 3 files changed, 275 insertions(+), 87 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 84c62495..ef83954a 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -65,6 +65,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Octant': False, 'Hemisphere': False, 'Full': True, + 'Box derivatives': [1, 3, 2], 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements': 1, @@ -87,6 +88,7 @@ def getOrderedOptionNames(): 'Octant', 'Hemisphere', 'Full', + 'Box derivatives', 'Refine', 'Refine number of elements' ] @@ -169,6 +171,11 @@ def checkOptions(cls, options): if options[radius] <= 0: options[radius] = 1.0 + if not all(abs(d) in [1, 2, 3] for d in options['Box derivatives']): + options['Box derivatives'] = [1, 3, 2] + if len(options['Box derivatives']) > len(set(options['Box derivatives'])): + options['Box derivatives'] = [1, 3, 2] + # if options['Number of elements across transition'] < 1: # options['Number of elements across transition'] = 1 # Rcrit = min(options['Number of elements across major']-4, options['Number of elements across minor']-4)//2 @@ -201,6 +208,8 @@ def generateBaseMesh(region, options): shellProportion = options['Shell element thickness proportion'] radius = [options['Radius1'], options['Radius2'], options['Radius3']] useCrossDerivatives = options['Use cross derivatives'] + sphereBoxDerivatives = options['Box derivatives'] + if options['Octant']: sphere_shape = SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP elif options['Hemisphere']: @@ -219,6 +228,7 @@ def generateBaseMesh(region, options): meshGroups = [boxMeshGroup, transitionMeshGroup] annotationGroups = [boxGroup, transitionGroup] + # sphereBoxDerivatives = [1, 3, 2] # consistent with default derivatives of cylinder mesh. centre = [0.0, 0.0, 0.0] axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] @@ -228,7 +238,7 @@ def generateBaseMesh(region, options): sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=sphere_shape, useCrossDerivatives=False, meshGroups=meshGroups) + sphereShape=sphere_shape, useCrossDerivatives=False, boxDerivatives=sphereBoxDerivatives, meshGroups=meshGroups) return annotationGroups diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index f558c398..40f3d3ee 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -700,6 +700,11 @@ def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim self._shieldMode = shieldMode self._boxDerivatives = box_derivatives + self._element_needs_scale_factor = False + self._xi_mapping = None + self._xi_signs = None + self._box_deriv_mapping = None + self._box_deriv_signs = None self.px = [ [] for _ in range(elementsCountAcross[2] + 1) ] self.pd1 = [ [] for _ in range(elementsCountAcross[2] + 1) ] @@ -905,23 +910,23 @@ def set_derivatives_for_irregualr_nodes(self, octant_number): return corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs, triple12leftderivs, triple12rightderivs - def get_box_mapping_for_other_octants(self, octant_number, octant1_mapping=None): + def get_box_mapping_for_other_octants(self, octant_number, octant1_box_derivatives=None): """ Find mapping for box nodes derivatives to make each octant similar to octant1. - :param octant1_mapping: + :param octant1_box_derivatives: default is [1, 3, 2] for octant 1 box derivatives. :return: boxMapping """ - if not octant1_mapping: - octant1_mapping = [1, 3, 2] + if not octant1_box_derivatives: + octant1_box_derivatives = [1, 3, 2] - swap12 = [octant1_mapping[1], octant1_mapping[0], octant1_mapping[2]] + swap12 = [octant1_box_derivatives[1], octant1_box_derivatives[0], octant1_box_derivatives[2]] signs = self.get_octant_signs(octant_number) if octant_number in [2, 4, 5, 7]: boxMapping = [swap12[c] * signs[c] for c in range(3)] else: - boxMapping = [octant1_mapping[c] * signs[c] for c in range(3)] + boxMapping = [octant1_box_derivatives[c] * signs[c] for c in range(3)] return boxMapping @@ -959,6 +964,27 @@ def get_octant_signs(self, octant_number): return signs + def get_element_node_identifiers(self, octant_number, e3, e2, e1, e3zo, e1zo): + """ + Find node identifiers for given element represented by its indexes (e3,e2,e1). It uses default order of nodes for + [1,3,2] default element axes and finds the mapping between octant default local node numbers and the sphere. + :param octant_number: + :return: nids, node s for given element represented by its indexes (e3,e2,e1). + """ + nids_default = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo)] + + # change the order of nodes according to the box derivatives. + boxMappingOctant1 = self.get_box_mapping_for_other_octants(1, octant1_box_derivatives=self._boxDerivatives) + lnm_octant1 = self.local_node_mapping(boxMappingOctant1) + nids = [1] * 8 + for ln in range(1, 9): + nids[lnm_octant1[ln] - 1] = nids_default[ln - 1] + + return nids + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): """ Create shield elements from nodes. @@ -984,18 +1010,18 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): for e1 in range(self.elementsCountAcross[1]): - eft1 = eft scalefactors = None + self._element_needs_scale_factor = False octant_number, element_type, e3zo, e2zo, e1zo = self.get_element_type(e3, e2, e1) e3o, e2o, e1o = self.get_local_element_index(octant_number, e3, e2, e1) e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - nids = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo), - self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo), - self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo), - self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo)] - boxMapping = self.get_box_mapping_for_other_octants(octant_number) + eft1 = eft if element_type == self.ELEMENT_REGULAR else tricubichermite.createEftNoCrossDerivatives() + + nids = self.get_element_node_identifiers(octant_number, e3, e2, e1, e3zo, e1zo) + + boxMapping = self.get_box_mapping_for_other_octants(octant_number, octant1_box_derivatives=self._boxDerivatives) lnm = self.local_node_mapping(boxMapping) corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs, triple12leftderivs,\ triple12rightderivs = self.set_derivatives_for_irregualr_nodes(octant_number) @@ -1003,10 +1029,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes if element_type == self.ELEMENT_REGULAR: pass elif element_type == self.ELEMENT_QUADRUPLE_DOWN_LEFT: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_DOWN_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.QUADRUPLE0_DOWN_LEFT) if e3o == 0: @@ -1031,10 +1053,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[1]], self.SURFACE_REGULAR_DOWN_LEFT) elif element_type == self.ELEMENT_QUADRUPLE_DOWN: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_13_DOWN) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_2_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_2_DOWN) @@ -1055,11 +1073,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[1], lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) elif element_type == self.ELEMENT_QUADRUPLE_DOWN_RIGHT: - eft1 = tricubichermite.createEftNoCrossDerivatives() - if e2o == e2bo or octant_number != 1: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - if e2o == e2bo: self.remap_eft_node_value_label(eft1, [lnm[3]], self.QUADRUPLE0_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_RIGHT) @@ -1105,10 +1118,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_DOWN) elif element_type == self.ELEMENT_QUADRUPLE_UP_LEFT: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - if e2o == e2bo: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_2_UP) self.remap_eft_node_value_label(eft1, [lnm[5]], self.QUADRUPLE0_UP) @@ -1132,7 +1141,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.SURFACE_REGULAR_UP) elif e2o == e2zo: - self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_UP) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE0_1_UP) self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) @@ -1154,10 +1162,7 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_UP) elif element_type == self.ELEMENT_QUADRUPLE_UP: - eft1 = tricubichermite.createEftNoCrossDerivatives() if e2o == e2bo: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_13_Up) else: @@ -1182,9 +1187,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[4]], self.SURFACE_REGULAR_UP) self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_UP) elif e2o == e2zo: - if octant_number != 2 or e1o == 0: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) @@ -1194,9 +1196,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_UP) self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_UP) else: - if octant_number != 2 or e1o == 0: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.BOUNDARY_13_UP) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) @@ -1204,11 +1203,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4], lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) elif element_type == self.ELEMENT_QUADRUPLE_LEFT: - eft1 = tricubichermite.createEftNoCrossDerivatives() - if octant_number != 4: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_3_LEFT) if e3o == 0: @@ -1231,10 +1225,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[1]], self.SURFACE_REGULAR_DOWN_LEFT) elif element_type == self.ELEMENT_QUADRUPLE_RIGHT: - eft1 = tricubichermite.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] - self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE0_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_RIGHT) if e3o == 0: @@ -1257,10 +1247,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) elif element_type == self.ELEMENT_DOWN_RIGHT: - eft1 = tricubichermite.createEftNoCrossDerivatives() - if octant_number != 1: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] if e3o == 0: if e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) @@ -1281,10 +1267,6 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes self.remap_eft_node_value_label(eft1, [lnm[6], lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) elif element_type == self.ELEMENT_DOWN_LEFT: - eft1 = tricubichermite.createEftNoCrossDerivatives() - if octant_number != 4: - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [-1.0] if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, derivatives=boundary12rightderivs) self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -1304,6 +1286,9 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes else: continue + if self._element_needs_scale_factor: + scalefactors = [-1.0] + if eft1 is not eft: elementtemplate1.defineField(coordinates, -1, eft1) element = mesh.createElement(elementIdentifier, elementtemplate1) @@ -1326,14 +1311,13 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes for meshGroup in meshGroups[1:2]: meshGroup.addElement(element) - return elementIdentifier def local_node_mapping(self, boxMapping): """ - Find local node mapping between local node number of octant and local node number of sphere. Obtain, xi mapping - and box irregular derivatives mapping that are used for elements in octant that locally might have different - xi directions from their global sphere xi directions. Then they are used in remap_eft_node_value_label. + Find local node mapping between default local node number of octant and global local node number of sphere. + Obtain xi mapping and box irregular derivatives mapping. they are used for elements in octant that locally might have + different xi directions from their global sphere xi directions. Then they are used in remap_eft_node_value_label. :return: lnm, local node mapping between local node number of octant and local node number of sphere. """ boxMapping_default = [1, 3, 2] @@ -1343,15 +1327,27 @@ def local_node_mapping(self, boxMapping): node_xi_map = {1: (0, 0, 0), 2: (1, 0, 0), 3: (0, 1, 0), 4: (1, 1, 0), 5: (0, 0, 1), 6: (1, 0, 1), 7: (0, 1, 1), 8: (1, 1, 1)} - xi_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} + xi_dm = {1: 'xi1', 2: 'xi2', 3: 'xi3'} + xi_default_to_global_map = {xi_dm[abs(boxMapping_default[0])]: abs(boxMapping[0]), + xi_dm[abs(boxMapping_default[1])]: abs(boxMapping[1]), + xi_dm[abs(boxMapping_default[2])]: abs(boxMapping[2])} + xi_global_to_default_map = {xi_dm[abs(boxMapping[0])]: abs(boxMapping_default[0]), + xi_dm[abs(boxMapping[1])]: abs(boxMapping_default[1]), + xi_dm[abs(boxMapping[2])]: abs(boxMapping_default[2])} signs = [1 if boxMapping[c]*boxMapping_default[c] > 0 else -1 for c in range(3)] - xi_sign_change = [signs[0], signs[2], signs[1]] + xi_sign_change = [signs[abs(boxMapping_default[0])-1], signs[abs(boxMapping_default[1])-1], signs[abs(boxMapping_default[2])-1]] lnm = {} + signs = [xi_sign_change[xi_global_to_default_map['xi1'] - 1], + xi_sign_change[xi_global_to_default_map['xi2'] - 1], + xi_sign_change[xi_global_to_default_map['xi3'] - 1]] for ln in range(1, 9): xi_l = [] - xi = [node_xi_map[ln][xi_map['xi1'] - 1], node_xi_map[ln][xi_map['xi2'] - 1], node_xi_map[ln][xi_map['xi3'] - 1]] - signs = [xi_sign_change[xi_map['xi1'] - 1], xi_sign_change[xi_map['xi2'] - 1], xi_sign_change[xi_map['xi3'] - 1]] + xi_default = node_xi_map[ln] + xi = [xi_default[xi_global_to_default_map['xi1'] - 1], + xi_default[xi_global_to_default_map['xi2'] - 1], + xi_default[xi_global_to_default_map['xi3'] - 1]] + for i in range(3): if signs[i] > 0: xi_l.append(xi[i]) @@ -1359,13 +1355,17 @@ def local_node_mapping(self, boxMapping): xi_l.append(1 - xi[i]) lnm[ln] = xi_node_map[tuple(xi_l)] - deriv_map = {'xi1': abs(boxMapping[0]), 'xi3': abs(boxMapping[1]), 'xi2': abs(boxMapping[2])} + deriv_default_to_global_map = {xi_dm[abs(boxMapping_default[0])]: abs(boxMapping[0]), + xi_dm[abs(boxMapping_default[1])]: abs(boxMapping[1]), + xi_dm[abs(boxMapping_default[2])]: abs(boxMapping[2])} signs = [1 if boxMapping[c]*boxMapping_default[c] > 0 else -1 for c in range(3)] - deriv_sign_change = [signs[0], signs[2], signs[1]] + deriv_sign_change = [signs[abs(boxMapping_default[0])-1], signs[abs(boxMapping_default[1])-1], signs[abs(boxMapping_default[2])-1]] - self._xi_mapping = {1: xi_map['xi1'], 2: xi_map['xi2'], 3: xi_map['xi3']} + self._xi_mapping = {1: xi_default_to_global_map['xi1'], 2: xi_default_to_global_map['xi2'], 3: xi_default_to_global_map['xi3']} self._xi_signs = {1: xi_sign_change[0], 2: xi_sign_change[1], 3: xi_sign_change[2]} - self._box_deriv_mapping = {1: deriv_map['xi1'], 2: deriv_map['xi2'], 3: deriv_map['xi3']} + self._box_deriv_mapping = {1: deriv_default_to_global_map['xi1'], + 2: deriv_default_to_global_map['xi2'], + 3: deriv_default_to_global_map['xi3']} self._box_deriv_signs = {1: deriv_sign_change[0], 2: deriv_sign_change[1], 3: deriv_sign_change[2]} return lnm @@ -1612,8 +1612,10 @@ def getNodeId(self, octant_number, n3, n2, n1, n3yo, n1yo): def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivatives=None): """ - Remaps derivatives for common types of nodes. It assumes the directions of derivatives in a certain way. If - directions are different, then we can use the 'derivatives' argument to fix this. This part is done for irregular nodes, + Remaps derivatives for common types of nodes. It also checks if each node needs scale factors. If one of the nodes + of an element needs it, then flags it. It assumes the directions of derivatives in a certain way (based on + default [1, 3, 2] xi directions). + If directions are different, then we can use the 'derivatives' argument to fix this. This part is done for irregular nodes, in the box and for other nodes, derivatives should be given. :param node_type: e.g. corner 1 represents an end node on the axis1. :param derivatives: derivatives to be changed to. @@ -1639,118 +1641,218 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D2_DS1DS2, [])]) if node_type == self.CORNER_1: + if any(c != 1 for c in [-1 * xis[1] * ds[3], 1 * xis[2] * ds[2], 1 * xis[3] * ds[1]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) elif node_type == self.CORNER_2: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.CORNER_3: - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]])]) + if any(c != 1 for c in [-1 * xis[3] * ds[1], -1 * xis[1] * ds[2], 1 * xis[2] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]])]) elif node_type == self.QUADRUPLE_DOWN_LEFT: + if any(c != 1 for c in [-1 * xis[1], 1 * xis[2], 1 * xis[2], -1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) elif node_type == self.QUADRUPLE_RIGHT: + if any(c != 1 for c in [1 * xis[1], 1 * xis[3], 1 * xis[2], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]]), (Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) elif node_type == self.QUADRUPLE_UP: + if any(c != 1 for c in [1 * xis[1], -1 * xis[3], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif node_type == self.QUADRUPLE0_DOWN_LEFT: + if any(c != 1 for c in [1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[1] * ds[1], -1 * xis[1] * ds[2], -1 * xis[1] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif node_type == self.QUADRUPLE0_RIGHT: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], -1 * xis[3] * ds[1], 1 * xis[3] * ds[2], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.QUADRUPLE0_UP: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], -1 * xis[2] * ds[1], 1 * xis[2] * ds[2], 1 * xis[2] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif node_type == self.TRIPLE_12_LEFT: + if any(c != 1 for c in [1 * xis[2] * ds[2], -1 * xis[1] * ds[3], 1 * xis[3] * ds[1]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) elif node_type == self.TRIPLE_12_RIGHT: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE_13_DOWN: + if any(c != 1 for c in [-1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif node_type == self.TRIPLE_13_UP: + if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap elif node_type == self.TRIPLE_23_DOWN: + if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif node_type == self.TRIPLE_23_UP: + if any(c != 1 for c in [1 * xis[1], -1 * xis[3], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif node_type == self.TRIPLE0_12_LEFT: + if any(c != 1 for c in [1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[1] * ds[1], -1 * xis[1] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif node_type == self.TRIPLE0_12_RIGHT: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], -1 * xis[3] * ds[1], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE0_13_DOWN: + if any(c != 1 for c in [1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[1] * ds[1], -1 * xis[1] * ds[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) elif node_type == self.TRIPLE0_13_Up: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], -1 * xis[2] * ds[1], 1 * xis[2] * ds[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) elif node_type == self.TRIPLE0_23_DOWN: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[2], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE0_23_UP: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[2] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif node_type == self.BOUNDARY_12_LEFT: + if any(c != 1 for c in [1 * xis[2] * ds[2], -1 * xis[1] * ds[3], 1 * xis[3] * ds[1]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) elif node_type == self.BOUNDARY_12_RIGHT: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.BOUNDARY_13_DOWN: + if any(c != 1 for c in [-1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif node_type == self.BOUNDARY_13_UP: + if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, [])]) @@ -1758,78 +1860,146 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif node_type == self.BOUNDARY_23_DOWN: + if any(c != 1 for c in [1 * xis[3], 1 * xis[1], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) elif node_type == self.BOUNDARY_23_UP: + if any(c != 1 for c in [1 * xis[1], -1 * xis[3], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif node_type == self.TRIPLE_CURVE_1_DOWN: + if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif node_type == self.TRIPLE_CURVE_1_UP: + if any(c != 1 for c in [1 * xis[1], -1 * xis[3], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif node_type == self.TRIPLE_CURVE_2_DOWN: + if any(c != 1 for c in [-1 * xis[1], 1 * xis[2], -1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) elif node_type == self.TRIPLE_CURVE_2_UP: + if any(c != 1 for c in [1 * xis[1], -1 * xis[3], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif node_type == self.TRIPLE_CURVE_3_LEFT: + if any(c != 1 for c in [1 * xis[2], -1 * xis[1], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif node_type == self.TRIPLE_CURVE_3_RIGHT: + if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif node_type == self.TRIPLE_CURVE0_1_UP: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[2] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif node_type == self.TRIPLE_CURVE0_1_DOWN: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[2], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE_CURVE0_2_DOWN: + if any(c != 1 for c in [1 * xis[2] * ds[2], 1 * xis[3] * ds[3], 1 * xis[1] * ds[1], -1 * xis[1] * ds[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) elif node_type == self.TRIPLE_CURVE0_2_UP: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], -1 * xis[2] * ds[1], 1 * xis[2] * ds[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) elif node_type == self.TRIPLE_CURVE0_3_LEFT: + if any(c != 1 for c in [1 * xis[2] * ds[2], 1 * xis[3] * ds[3], 1 * xis[1] * ds[1], -1 * xis[1] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif node_type == self.TRIPLE_CURVE0_3_RIGHT: + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], -1 * xis[3] * ds[1], 1 * xis[3] * ds[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.SURFACE_REGULAR_DOWN_LEFT: + if any(c != 1 for c in [1 * xis[2], -1 * xis[1], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif node_type == self.SURFACE_REGULAR_DOWN_RIGHT: + if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) elif node_type == self.SURFACE_REGULAR_UP: + if any(c != 1 for c in [1 * xis[1], -1 * xis[3], 1 * xis[2]]): + if not self._element_needs_scale_factor: + self._element_needs_scale_factor = True + setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) @@ -1839,3 +2009,11 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[3]])]) else: raise ValueError("Remapping for derivatives of this 'node type' is not implemented") + + # for ci in range(1, 4): + # expressionTerms = [] + # for di in range(1, 4): + # if default_sign[ci][di-1]: + # expressionTerms.append((expressionLabel[dm[di]], sf[default_sign[ci][di-1] * xis[ci] * ds[di]])) + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[ci]], expressionTerms) + diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index d029a5d6..43cc467a 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -33,7 +33,7 @@ class SphereMesh: def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None, meshGroups=[]): + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxDerivatives=None, meshGroups=[]): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. @@ -47,7 +47,7 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, :param sphereShape: A value from enum SphereShape specifying the shape of sphere. Octant_PPP, for example is the octant in positive axis1, positive axis2 and positive axis3. SPHERE_SHAPE_HALF_AAP is a hemisphere on the positive side of axis3. - :param boxMapping: It is a list of [deriv1,deriv2,deriv3] and is used to change the derivatives names. + :param boxDerivatives: It is a list of [deriv1,deriv2,deriv3] and is used to change the derivatives names. Default is [1, 3, 2] and [3, 1, 2] means swap 1 and 3. """ @@ -71,7 +71,7 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, self._centre = centre - self._boxMapping = boxMapping if boxMapping else [1, 3, 2] + self._boxDerivatives = boxDerivatives if boxDerivatives else [1, 3, 2] self._meshGroups = meshGroups for i in range(3): @@ -119,7 +119,7 @@ def createSphereMesh3d(self, fieldModule, coordinates): elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL - self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode, box_derivatives=[1, 3, 2]) + self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode, box_derivatives=self._boxDerivatives) nodes = fieldModule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) mesh = fieldModule.findMeshByDimension(3) @@ -142,10 +142,10 @@ def createSphereMesh3d(self, fieldModule, coordinates): OctantVariationsType = OctantVariationsAll for octantType in OctantVariationsType: - axes, elementsCountAcross, boxMapping = self.get_octant_axes_and_elements_count(octantType) + axes, elementsCountAcross, boxDerivatives = self.get_octant_axes_and_elements_count(octantType) octant = OctantMesh(self._centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=boxMapping) + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxDerivatives=boxDerivatives) self.copy_octant_nodes_to_sphere_shield(octant, octantType) self.sphere_to_spheroid() @@ -157,10 +157,10 @@ def get_octant_axes_and_elements_count(self, octant_shape): """ Get the octants axes, elements count across and box mapping for 8 octants in 8 different regions. :param octant_shape: A value from enum SphereShape specifying the shape of sphere - :return: axes, elementsCountAcross, boxMapping for the octant. + :return: axes, elementsCountAcross, boxDerivatives for the octant. """ - boxMappingV1 = self._boxMapping - boxMappingV2 = [self._boxMapping[1], self._boxMapping[0], self._boxMapping[2]] + boxDerivativesV1 = self._boxDerivatives + boxDerivativesV2 = [self._boxDerivatives[1], self._boxDerivatives[0], self._boxDerivatives[2]] axesV1 = [self._axes[0], self._axes[1], self._axes[2]] axesV2 = [self._axes[1], self._axes[0], self._axes[2]] elementsCountAcrossV1 = [c for c in self._elementsCount] @@ -190,11 +190,11 @@ def get_octant_axes_and_elements_count(self, octant_shape): signs = self._shield3D.get_octant_signs(octant_number) if octant_number in [2, 4, 5, 7]: - boxMapping = [boxMappingV2[c] * signs[c] for c in range(3)] + boxDerivatives = [boxDerivativesV2[c] * signs[c] for c in range(3)] elementsCountAcross = elementsCountAcrossV2 axes = [vector.scaleVector(axesV2[c], axesSignsV2[c]) for c in range(3)] else: - boxMapping = [boxMappingV1[c] * signs[c] for c in range(3)] + boxDerivatives = [boxDerivativesV1[c] * signs[c] for c in range(3)] elementsCountAcross = elementsCountAcrossV1 axes = [vector.scaleVector(axesV1[c], axesSignsV1[c]) for c in range(3)] @@ -207,7 +207,7 @@ def get_octant_axes_and_elements_count(self, octant_shape): elementsCountAcross[2] = elementsCountAcross[2] // 2 axes = [vector.normalise(v) for v in axes] - return axes, elementsCountAcross, boxMapping + return axes, elementsCountAcross, boxDerivatives def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): """ @@ -347,7 +347,7 @@ class OctantMesh: def __init__(self, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxMapping=None): + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxDerivatives=None): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. @@ -377,7 +377,7 @@ def __init__(self, centre, axes, elementsCountAcross, self._centre = centre - self._boxMapping = boxMapping if boxMapping else [1, 3, 2] + self._boxDerivatives = boxDerivatives if boxDerivatives else [1, 3, 2] for i in range(3): elementsAxis = elementsCountAcross[i] - elementsCountAcrossShell * (1 - shellProportion) @@ -397,7 +397,7 @@ def createOctantMesh3d(self): self.create_boundary_ellipses_nodes() self.create_surface_and_interior_nodes() - self._shield3D.set_derivatives(self._boxMapping) + self._shield3D.set_derivatives(self._boxDerivatives) def create_boundary_ellipses_nodes(self): """ From 326fb3c3247d8047b18c3152df2a559f0b809ada Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Thu, 21 Oct 2021 15:50:11 +1300 Subject: [PATCH 30/37] Change top pole derivatives. --- src/scaffoldmaker/utils/shieldmesh.py | 10 ++++----- src/scaffoldmaker/utils/spheremesh.py | 30 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 40f3d3ee..c624a667 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -880,15 +880,15 @@ def set_derivatives_for_irregualr_nodes(self, octant_number): if octant_number == 1: if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - corner3derivs = [2, -1, 3] + corner3derivs = [-2, 1, 3] else: - corner3derivs = [1, 2, 3] + corner3derivs = [-2, 1, 3] elif octant_number == 2: - corner3derivs = [-2, 1, 3] - elif octant_number == 3: corner3derivs = [-1, -2, 3] - elif octant_number == 4: + elif octant_number == 3: corner3derivs = [2, -1, 3] + elif octant_number == 4: + corner3derivs = [1, 2, 3] elif octant_number == 5: corner3derivs = [-1, -2, 3] elif octant_number == 6: diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 43cc467a..787faa74 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -148,6 +148,7 @@ def createSphereMesh3d(self, fieldModule, coordinates): sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxDerivatives=boxDerivatives) self.copy_octant_nodes_to_sphere_shield(octant, octantType) + self.modify_octant_common_nodes() self.sphere_to_spheroid() self.generateNodes(nodes, fieldModule, coordinates) @@ -296,6 +297,35 @@ def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): self._shield3D.pd2[n3][n2][n1] = octant._shield3D.pd2[n3o][n2o][n1o] self._shield3D.pd3[n3][n2][n1] = octant._shield3D.pd3[n3o][n2o][n1o] + def modify_octant_common_nodes(self): + """ + + :return: + """ + btx = self._shield3D.px + btd1 = self._shield3D.pd1 + btd2 = self._shield3D.pd2 + btd3 = self._shield3D.pd3 + + n1z = self._elementsCount[1] + n1y = n1z - 1 + n2z = self._elementsCount[0] + n3z = self._elementsCount[2] + n3y = n3z - 1 + + # modify pole on highest z. + if self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: + btd1[n3z][n2z][0] = [-c for c in btd1[n3z][n2z][0]] + btd2[n3z][n2z][0] = [-c for c in btd2[n3z][n2z][0]] + elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_AAP: + temp = btd1[n3z][n2z//2][n1z//2] + btd1[n3z][n2z//2][n1z//2] = btd2[n3z][n2z//2][n1z//2] + btd2[n3z][n2z//2][n1z//2] = [-c for c in temp] + elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: + temp = btd1[n3z][n2z//2][n1z//2] + btd1[n3z][n2z//2][n1z//2] = btd2[n3z][n2z//2][n1z//2] + btd2[n3z][n2z//2][n1z//2] = [-c for c in temp] + def sphere_to_spheroid(self): """ Using the radius in each direction,transform the sphere to ellipsoid. From ecfb4d67d5522636691a101413c8202f57c20c0a Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 22 Oct 2021 11:34:30 +1300 Subject: [PATCH 31/37] Refine mesh and test volume and surface area for sphere and ellipsoid. --- .../meshtypes/meshtype_3d_solidsphere2.py | 6 +- tests/test_sphere.py | 134 +++++++++++++++++- 2 files changed, 133 insertions(+), 7 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index ef83954a..3d7a4f6d 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -65,7 +65,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Octant': False, 'Hemisphere': False, 'Full': True, - 'Box derivatives': [1, 3, 2], + 'Box derivatives': [-1, 2, 3], 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements': 1, @@ -251,5 +251,5 @@ def refineMesh(cls, meshRefinement, options): :param options: Dict containing options. See getDefaultOptions(). """ assert isinstance(meshRefinement, MeshRefinement) - refineElementsCountAcross = options['Refine number of elements'] - meshRefinement.refineAllElementsCubeStandard3d(refineElementsCountAcross, refineElementsCountAcross, refineElementsCountAcross) + refineElementsCount = options['Refine number of elements'] + meshRefinement.refineAllElementsCubeStandard3d(refineElementsCount, refineElementsCount, refineElementsCount) diff --git a/tests/test_sphere.py b/tests/test_sphere.py index 4124b720..bdbed98f 100644 --- a/tests/test_sphere.py +++ b/tests/test_sphere.py @@ -7,6 +7,9 @@ from opencmiss.zinc.result import RESULT_OK from scaffoldmaker.meshtypes.meshtype_3d_solidsphere2 import MeshType_3d_solidsphere2 from testutils import assertAlmostEqualList +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup +from scaffoldmaker.annotation.annotationgroup import getAnnotationGroupForTerm +from scaffoldmaker.utils.meshrefinement import MeshRefinement class SphereScaffoldTestCase(unittest.TestCase): @@ -19,7 +22,7 @@ def test_sphere1(self): parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default"]) options = scaffold.getDefaultOptions("Default") - self.assertEqual(15, len(options)) + self.assertEqual(16, len(options)) self.assertEqual(4, options.get("Number of elements across axis 1")) self.assertEqual(4, options.get("Number of elements across axis 2")) self.assertEqual(4, options.get("Number of elements across axis 3")) @@ -29,12 +32,16 @@ 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([-1, 2, 3], options.get("Box derivatives")) + context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = scaffold.generateMesh(region, options) - self.assertEqual(0, len(annotationGroups)) + self.assertEqual(2, len(annotationGroups)) + fieldmodule = region.getFieldmodule() + self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) self.assertEqual(32, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) @@ -51,16 +58,135 @@ def test_sphere1(self): self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) assertAlmostEqualList(self, minimums, [-1.0, -1.0, -1.0], 1.0E-6) - assertAlmostEqualList(self, maximums, [ 1.0, 1.0, 1.0 ], 1.0E-6) + assertAlmostEqualList(self, maximums, [1.0, 1.0, 1.0], 1.0E-6) + with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) + surfaceGroup = AnnotationGroup(region, ("sphere surface", "")) + is_exterior = fieldmodule.createFieldIsExterior() + surfaceMeshGroup = surfaceGroup.getMeshGroup(mesh2d) + surfaceMeshGroup.addElementsConditional(is_exterior) + + surfaceAreaField = fieldmodule.createFieldMeshIntegral(one, coordinates, surfaceMeshGroup) + surfaceAreaField.setNumbersOfPoints(4) volumeField = fieldmodule.createFieldMeshIntegral(one, coordinates, mesh3d) volumeField.setNumbersOfPoints(3) fieldcache = fieldmodule.createFieldcache() + result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(surfaceArea, 12.460033954564986, delta=2.0E-1) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 4.093180374780382, delta=1.0E-3) + self.assertAlmostEqual(volume, 4.132033912594377, delta=1.0E-3) + + # check some annotationGroups: + expectedSizes3d = { + "box group": 8, + "transition group": 24, + } + for name in expectedSizes3d: + group = getAnnotationGroupForTerm(annotationGroups, (name, '')) + size = group.getMeshGroup(mesh3d).getSize() + self.assertEqual(expectedSizes3d[name], size, name) + + # refine 8x8x8 and check result + refineRegion = region.createRegion() + refineFieldmodule = refineRegion.getFieldmodule() + options['Refine number of elements'] = 2 + meshrefinement = MeshRefinement(region, refineRegion, []) + scaffold.refineMesh(meshrefinement, options) + + refineCoordinates = refineFieldmodule.findFieldByName("coordinates").castFiniteElement() + + refineFieldmodule.defineAllFaces() + mesh3d = refineFieldmodule.findMeshByDimension(3) + self.assertEqual(256, mesh3d.getSize()) + mesh2d = refineFieldmodule.findMeshByDimension(2) + self.assertEqual(816, mesh2d.getSize()) + mesh1d = refineFieldmodule.findMeshByDimension(1) + self.assertEqual(880, mesh1d.getSize()) + nodes = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + self.assertEqual(321, nodes.getSize()) + datapoints = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) + self.assertEqual(0, datapoints.getSize()) + + # obtain surface area and volume again. If they are the same as previous, mesh is conform. + with ChangeManager(refineFieldmodule): + one = refineFieldmodule.createFieldConstant(1.0) + surfaceGroup = AnnotationGroup(refineRegion, ("sphere surface", "")) + is_exterior = refineFieldmodule.createFieldIsExterior() + surfaceMeshGroup = surfaceGroup.getMeshGroup(mesh2d) + surfaceMeshGroup.addElementsConditional(is_exterior) + + surfaceAreaField = refineFieldmodule.createFieldMeshIntegral(one, refineCoordinates, surfaceMeshGroup) + surfaceAreaField.setNumbersOfPoints(4) + volumeField = refineFieldmodule.createFieldMeshIntegral(one, refineCoordinates, mesh3d) + volumeField.setNumbersOfPoints(3) + refineFieldcache = refineFieldmodule.createFieldcache() + result, surfaceArea = surfaceAreaField.evaluateReal(refineFieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(surfaceArea, 12.460033954564986, delta=5.0E-1) + result, volume = volumeField.evaluateReal(refineFieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(volume, 4.132033912594377, delta=3.0E-1) + + + # check ellipsoid. + scaffold1 = MeshType_3d_solidsphere2 + parameterSetNames = scaffold1.getParameterSetNames() + self.assertEqual(parameterSetNames, ["Default"]) + options = scaffold1.getDefaultOptions("Default") + 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['Radius1'] = 0.5 + options['Radius2'] = 0.8 + options['Radius3'] = 1.0 + + context2 = Context("Test2") + region = context2.getDefaultRegion() + self.assertTrue(region.isValid()) + annotationGroups = scaffold1.generateMesh(region, options) + self.assertEqual(2, len(annotationGroups)) + fieldmodule = region.getFieldmodule() + self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) + mesh3d = fieldmodule.findMeshByDimension(3) + self.assertEqual(136, mesh3d.getSize()) + mesh2d = fieldmodule.findMeshByDimension(2) + self.assertEqual(452, mesh2d.getSize()) + mesh1d = fieldmodule.findMeshByDimension(1) + self.assertEqual(510, mesh1d.getSize()) + nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + self.assertEqual(195, nodes.getSize()) + datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) + self.assertEqual(0, datapoints.getSize()) + # check coordinates range, sphere volume + coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() + self.assertTrue(coordinates.isValid()) + minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) + assertAlmostEqualList(self, minimums, [-0.5, -0.8, -1.0], 1.0E-6) + assertAlmostEqualList(self, maximums, [0.5, 0.8, 1.0], 1.0E-6) + + with ChangeManager(fieldmodule): + one = fieldmodule.createFieldConstant(1.0) + surfaceGroup = AnnotationGroup(region, ("sphere surface", "")) + is_exterior = fieldmodule.createFieldIsExterior() + surfaceMeshGroup = surfaceGroup.getMeshGroup(mesh2d) + surfaceMeshGroup.addElementsConditional(is_exterior) + + surfaceAreaField = fieldmodule.createFieldMeshIntegral(one, coordinates, surfaceMeshGroup) + surfaceAreaField.setNumbersOfPoints(4) + volumeField = fieldmodule.createFieldMeshIntegral(one, coordinates, mesh3d) + volumeField.setNumbersOfPoints(3) + fieldcache = fieldmodule.createFieldcache() + result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(surfaceArea, 7.3015173697377245, delta=2.0E-1) + result, volume = volumeField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(volume, 1.6741674010981926, delta=1.0E-3) if __name__ == "__main__": unittest.main() From 83c930f139b89b809990a9113e0a76ada4ee0291 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 22 Oct 2021 11:51:53 +1300 Subject: [PATCH 32/37] Change box derivatives default value to [1,2,3]. --- .../meshtypes/meshtype_3d_solidsphere2.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 3d7a4f6d..8b3c179b 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -65,7 +65,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Octant': False, 'Hemisphere': False, 'Full': True, - 'Box derivatives': [-1, 2, 3], + 'Box derivatives': [1, 2, 3], 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements': 1, @@ -172,9 +172,9 @@ def checkOptions(cls, options): options[radius] = 1.0 if not all(abs(d) in [1, 2, 3] for d in options['Box derivatives']): - options['Box derivatives'] = [1, 3, 2] + options['Box derivatives'] = [1, 2, 3] if len(options['Box derivatives']) > len(set(options['Box derivatives'])): - options['Box derivatives'] = [1, 3, 2] + options['Box derivatives'] = [1, 2, 3] # if options['Number of elements across transition'] < 1: # options['Number of elements across transition'] = 1 @@ -208,7 +208,11 @@ def generateBaseMesh(region, options): shellProportion = options['Shell element thickness proportion'] radius = [options['Radius1'], options['Radius2'], options['Radius3']] useCrossDerivatives = options['Use cross derivatives'] - sphereBoxDerivatives = options['Box derivatives'] + 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] + # sphereBoxDerivatives = [1, 3, 2] # consistent with default derivatives of cylinder mesh. + # This is the default value that is used for base sphere. if options['Octant']: sphere_shape = SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP @@ -228,7 +232,6 @@ def generateBaseMesh(region, options): meshGroups = [boxMeshGroup, transitionMeshGroup] annotationGroups = [boxGroup, transitionGroup] - # sphereBoxDerivatives = [1, 3, 2] # consistent with default derivatives of cylinder mesh. centre = [0.0, 0.0, 0.0] axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] From ae86d57514b45bc80afa98f07bfb0a51eb2cdd4f Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 22 Oct 2021 11:53:51 +1300 Subject: [PATCH 33/37] Minor change. --- tests/test_sphere.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sphere.py b/tests/test_sphere.py index bdbed98f..73b7a535 100644 --- a/tests/test_sphere.py +++ b/tests/test_sphere.py @@ -32,7 +32,7 @@ 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([-1, 2, 3], options.get("Box derivatives")) + self.assertEqual([1, 2, 3], options.get("Box derivatives")) context = Context("Test") region = context.getDefaultRegion() From 927e745d4c560554e0e38a6f814832f59838d15f Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 22 Oct 2021 18:03:16 +1300 Subject: [PATCH 34/37] Add a Range of number of elements required in directions option. It makes it enables to have any part of the ellipsoid. --- .../meshtypes/meshtype_3d_solidsphere2.py | 44 ++++++++++++++++++- src/scaffoldmaker/utils/shieldmesh.py | 13 +++++- src/scaffoldmaker/utils/spheremesh.py | 9 ++-- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 8b3c179b..ba78a6c9 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -65,6 +65,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Octant': False, 'Hemisphere': False, 'Full': True, + '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], 'Box derivatives': [1, 2, 3], 'Use cross derivatives': False, 'Refine': False, @@ -88,6 +91,9 @@ def getOrderedOptionNames(): 'Octant', 'Hemisphere', 'Full', + 'Range of elements required in direction 1', + 'Range of elements required in direction 2', + 'Range of elements required in direction 3', 'Box derivatives', 'Refine', 'Refine number of elements' @@ -176,6 +182,38 @@ 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['Range of elements required in direction {}'.format(i)][1] = \ + options['Number of elements across axis {}'.format(i)] + if options['Octant']: + nm = 2 + if options['Hemisphere']: + nm = 3 + elif options['Full']: + nm = 4 + for i in range(1, nm): + if options['Range of elements required in direction {}'.format(i)][0] == 1: + 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]): + 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: + 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] + # if options['Number of elements across transition'] < 1: # options['Number of elements across transition'] = 1 # Rcrit = min(options['Number of elements across major']-4, options['Number of elements across minor']-4)//2 @@ -208,6 +246,9 @@ 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']] 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] @@ -241,7 +282,8 @@ def generateBaseMesh(region, options): sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=sphere_shape, useCrossDerivatives=False, boxDerivatives=sphereBoxDerivatives, meshGroups=meshGroups) + sphereShape=sphere_shape, rangeOfRequiredElements=rangeOfRequiredElements, boxDerivatives=sphereBoxDerivatives, + useCrossDerivatives=False, meshGroups=meshGroups) return annotationGroups diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index c624a667..3dda0d85 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -718,7 +718,7 @@ def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] - def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier): + def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, rangeOfRequiredElements): """ Create shield nodes from coordinates. :param fieldmodule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. @@ -743,6 +743,10 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier): for n2 in range(self.elementsCountAcross[0] + 1): for n3 in range(self.elementsCountAcross[2] + 1): for n1 in range(self.elementsCountAcross[1] + 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 @@ -985,7 +989,7 @@ def get_element_node_identifiers(self, octant_number, e3, e2, e1, e3zo, e1zo): return nids - def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): + def generateElements(self, fieldmodule, coordinates, startElementIdentifier , rangeOfRequiredElements, meshGroups=[]): """ Create shield elements from nodes. :param fieldmodule: Zinc fieldmodule to create elements in. @@ -1010,6 +1014,11 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes for e3 in range(self.elementsCountAcross[2]): for e2 in range(self.elementsCountAcross[0]): for e1 in range(self.elementsCountAcross[1]): + 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 + scalefactors = None self._element_needs_scale_factor = False diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 787faa74..87029fc1 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -33,7 +33,7 @@ class SphereMesh: def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxDerivatives=None, meshGroups=[]): + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, rangeOfRequiredElements=None, boxDerivatives=None, useCrossDerivatives=False, meshGroups=[]): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. @@ -47,6 +47,8 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, :param sphereShape: A value from enum SphereShape specifying the shape of sphere. Octant_PPP, for example is the octant in positive axis1, positive axis2 and positive axis3. SPHERE_SHAPE_HALF_AAP is a hemisphere on the positive side of axis3. + :param rangeOfRequiredElements: Specifies the range of elements required to be created. It can be used to + create the part of sphere required. If None or same as elementsCountAcross the whole part will be created. :param boxDerivatives: It is a list of [deriv1,deriv2,deriv3] and is used to change the derivatives names. Default is [1, 3, 2] and [3, 1, 2] means swap 1 and 3. """ @@ -66,6 +68,7 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, self._endNodeIdentifier = 1 self._endElementIdentifier = 1 self._sphereShape = sphereShape + self._rangeOfRequiredElements = rangeOfRequiredElements self._useCrossDerivatives = useCrossDerivatives @@ -354,7 +357,7 @@ def generateNodes(self, nodes, fieldModule, coordinates): """ nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) self._startNodeIdentifier = nodeIdentifier - nodeIdentifier = self._shield3D.generateNodes(fieldModule, coordinates, nodeIdentifier) + nodeIdentifier = self._shield3D.generateNodes(fieldModule, coordinates, nodeIdentifier, self._rangeOfRequiredElements) self._endNodeIdentifier = nodeIdentifier def generateElements(self, mesh, fieldModule, coordinates): @@ -366,7 +369,7 @@ def generateElements(self, mesh, fieldModule, coordinates): """ elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1) self._startElementIdentifier = elementIdentifier - elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, self._meshGroups) + elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, self._rangeOfRequiredElements, self._meshGroups) self._endElementIdentifier = elementIdentifier From ff4b9ca2896d96b455aee24996bd2e7046c6e828 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 22 Oct 2021 18:26:06 +1300 Subject: [PATCH 35/37] Modify unittest according to recent changes of sphere. --- tests/test_sphere.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_sphere.py b/tests/test_sphere.py index 73b7a535..e05b3272 100644 --- a/tests/test_sphere.py +++ b/tests/test_sphere.py @@ -22,7 +22,7 @@ def test_sphere1(self): parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default"]) options = scaffold.getDefaultOptions("Default") - self.assertEqual(16, len(options)) + self.assertEqual(19, len(options)) self.assertEqual(4, options.get("Number of elements across axis 1")) self.assertEqual(4, options.get("Number of elements across axis 2")) self.assertEqual(4, options.get("Number of elements across axis 3")) @@ -32,6 +32,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([1, 2, 3], options.get("Box derivatives")) context = Context("Test") @@ -139,6 +142,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['Radius1'] = 0.5 options['Radius2'] = 0.8 From 19b8b1091ca81c2c1d916e5ec8c8ea6120e61515 Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Sat, 23 Oct 2021 01:28:39 +1300 Subject: [PATCH 36/37] Remove Octant, Hemisphere and Full options and only create full sphere. For other parts use the range of elements instead. --- .../meshtypes/meshtype_3d_solidsphere2.py | 102 +----- src/scaffoldmaker/utils/shieldmesh.py | 341 +++++++----------- src/scaffoldmaker/utils/spheremesh.py | 9 +- tests/test_sphere.py | 2 +- 4 files changed, 147 insertions(+), 307 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index ba78a6c9..09009ade 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -24,25 +24,6 @@ class MeshType_3d_solidsphere2(Scaffold_base): Generates a solid sphere using a ShieldMesh of all cube elements, with variable numbers of elements across axes and shell directions. """ - # centralPathDefaultScaffoldPackages = { - # 'Cylinder 1': ScaffoldPackage(MeshType_1d_path1, { - # 'scaffoldSettings': { - # 'Coordinate dimensions': 3, - # 'D2 derivatives': True, - # 'D3 derivatives': True, - # 'Length': 3.0, - # 'Number of elements': 3 - # }, - # 'meshEdits': exnodeStringFromNodeValues( - # [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, - # Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - # [[0.0, 0.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], - # [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], - # [[0.0, 0.0, 2.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]], - # [[0.0, 0.0, 3.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 0.0]] - # ]) - # }) - # } @staticmethod def getName(): @@ -50,9 +31,7 @@ def getName(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - # centralPathOption = cls.centralPathDefaultScaffoldPackages['Cylinder 1'] options = { - # 'Central path': copy.deepcopy(centralPathOption), 'Number of elements across axis 1': 4, 'Number of elements across axis 2': 4, 'Number of elements across axis 3': 4, @@ -62,9 +41,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Radius2': 1.0, 'Radius3': 1.0, 'Shell element thickness proportion': 1.0, - 'Octant': False, - 'Hemisphere': False, - 'Full': True, '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], @@ -78,7 +54,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - # 'Central path', 'Number of elements across axis 1', 'Number of elements across axis 2', 'Number of elements across axis 3', @@ -88,9 +63,6 @@ def getOrderedOptionNames(): 'Radius2', 'Radius3', # 'Shell element thickness proportion', - 'Octant', - 'Hemisphere', - 'Full', 'Range of elements required in direction 1', 'Range of elements required in direction 2', 'Range of elements required in direction 3', @@ -99,65 +71,12 @@ def getOrderedOptionNames(): 'Refine number of elements' ] - @classmethod - def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': - return [MeshType_1d_path1] - return [] - - @classmethod - def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) - assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ - cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ - 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() - return scaffoldType.getParameterSetNames() - - @classmethod - def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): - ''' - :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. - :return: ScaffoldPackage. - ''' - if parameterSetName: - assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ - 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ - ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': - if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) - assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' - @classmethod def checkOptions(cls, options): - # if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - # options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) dependentChanges = False - if options['Octant']: - dependentChanges = True - options['Hemisphere'] = False - options['Full'] = False - else: - if options['Hemisphere']: - dependentChanges = True - options['Full'] = False - else: - options['Full'] = True - - if options['Octant']: - min1, min2, min3 = 2, 2, 2 - co1, co2, co3 = 0, 0, 0 - elif options['Hemisphere']: - dependentChanges = True - min1, min2, min3 = 4, 4, 2 - co1, co2, co3 = 1, 1, 0 - else: - dependentChanges = True - min1, min2, min3 = 4, 4, 4 - co1, co2, co3 = 1, 1, 1 + min1, min2, min3 = 4, 4, 4 + co1, co2, co3 = 1, 1, 1 if options['Number of elements across axis 1'] < min1: options['Number of elements across axis 1'] = min1 @@ -187,12 +106,8 @@ def checkOptions(cls, options): options['Number of elements across axis {}'.format(i)] - 1: options['Range of elements required in direction {}'.format(i)][1] = \ options['Number of elements across axis {}'.format(i)] - if options['Octant']: - nm = 2 - if options['Hemisphere']: - nm = 3 - elif options['Full']: - nm = 4 + + nm = 4 for i in range(1, nm): if options['Range of elements required in direction {}'.format(i)][0] == 1: options['Range of elements required in direction {}'.format(i)][0] = 0 @@ -236,7 +151,6 @@ def generateBaseMesh(region, options): :return: None """ - # centralPath = options['Central path'] elementsCountAcrossAxis1 = options['Number of elements across axis 1'] elementsCountAcrossAxis2 = options['Number of elements across axis 2'] elementsCountAcrossAxis3 = options['Number of elements across axis 3'] @@ -254,13 +168,7 @@ def generateBaseMesh(region, options): # consistent with [back, right, up] # sphereBoxDerivatives = [1, 3, 2] # consistent with default derivatives of cylinder mesh. # This is the default value that is used for base sphere. - - if options['Octant']: - sphere_shape = SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP - elif options['Hemisphere']: - sphere_shape = SphereShape.SPHERE_SHAPE_HALF_AAP - else: - sphere_shape = SphereShape.SPHERE_SHAPE_FULL + sphere_shape = SphereShape.SPHERE_SHAPE_FULL fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 3dda0d85..75a5124c 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -671,7 +671,7 @@ class ShieldMesh3D: Generates a 3D shield mesh. """ - def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP, box_derivatives=None): + def __init__(self, elementsCountAcross, elementsCountRim, box_derivatives=None): """ 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the centre. The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a unique node on the @@ -688,7 +688,9 @@ def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape :param elementsCountAcross: number of elements as a list [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] :param elementsCountRim: - :param shieldMode: It can be full or just a section of the whole shield. + :param box_derivatives: It is a list of [deriv1,deriv2,deriv3]. It is used to set the derivative directions. + default is [1, 3, 2] which means it makes -d1, d3 and d2 in direction of axis1, axis2 and axis3. To make + d1, d2 and d3 directions in direction of axis1, axis2 and axis3 use [-1, 2, 3]. """ assert elementsCountRim >= 0 # assert elementsCountAcross >= (elementsCountRim + 4) @@ -698,7 +700,6 @@ def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape # self.elementsCountUpRegular = elementsCountUp - 2 - elementsCountRim # elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim - self._shieldMode = shieldMode self._boxDerivatives = box_derivatives self._element_needs_scale_factor = False self._xi_mapping = None @@ -718,6 +719,68 @@ def __init__(self, elementsCountAcross, elementsCountRim, shieldMode=ShieldShape self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] + # node types + CORNER_1 = 1 + CORNER_2 = 2 + CORNER_3 = 3 + + QUADRUPLE_DOWN_LEFT = 4 + QUADRUPLE_RIGHT = 5 + QUADRUPLE_UP = 6 + QUADRUPLE0_DOWN_LEFT = 7 + QUADRUPLE0_RIGHT = 8 + QUADRUPLE0_UP = 9 + + TRIPLE_12_LEFT = 10 + TRIPLE_12_RIGHT = 11 + TRIPLE_13_DOWN = 12 + TRIPLE_13_UP = 13 + TRIPLE_23_UP = 14 + TRIPLE_23_DOWN = 15 + TRIPLE0_12_LEFT = 16 + TRIPLE0_12_RIGHT = 17 + TRIPLE0_13_DOWN = 18 + TRIPLE0_13_Up = 19 + TRIPLE0_23_DOWN = 20 + TRIPLE0_23_UP = 21 + + BOUNDARY_12_LEFT = 22 + BOUNDARY_12_RIGHT = 23 + BOUNDARY_13_DOWN = 24 + BOUNDARY_13_UP = 25 + BOUNDARY_23_UP = 26 + BOUNDARY_23_DOWN = 27 + + TRIPLE_CURVE_1_DOWN = 28 + TRIPLE_CURVE_1_UP = 29 + TRIPLE_CURVE_2_DOWN = 30 + TRIPLE_CURVE_2_UP = 31 + TRIPLE_CURVE_3_LEFT = 32 + TRIPLE_CURVE_3_RIGHT = 33 + TRIPLE_CURVE0_1_UP = 34 + TRIPLE_CURVE0_1_DOWN = 35 + TRIPLE_CURVE0_2_DOWN = 36 + TRIPLE_CURVE0_2_UP = 37 + TRIPLE_CURVE0_3_LEFT = 38 + TRIPLE_CURVE0_3_RIGHT = 39 + + SURFACE_REGULAR_DOWN_LEFT = 40 + SURFACE_REGULAR_DOWN_RIGHT = 41 + SURFACE_REGULAR_UP = 42 + REGULAR = 43 + + # element types + ELEMENT_REGULAR = 1 + ELEMENT_QUADRUPLE_DOWN_LEFT = 2 + ELEMENT_QUADRUPLE_DOWN_RIGHT = 3 + ELEMENT_QUADRUPLE_UP_LEFT = 4 + ELEMENT_QUADRUPLE_DOWN = 5 + ELEMENT_QUADRUPLE_UP = 6 + ELEMENT_QUADRUPLE_LEFT = 7 + ELEMENT_QUADRUPLE_RIGHT = 8 + ELEMENT_DOWN_RIGHT = 9 + ELEMENT_DOWN_LEFT = 10 + def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, rangeOfRequiredElements): """ Create shield nodes from coordinates. @@ -801,68 +864,6 @@ def is_interior_regular_nodes(self, n3, n2, n1): return n3 <= n3y and n2 >= 1 and n1 <= n1y - # node types - CORNER_1 = 1 - CORNER_2 = 2 - CORNER_3 = 3 - - QUADRUPLE_DOWN_LEFT = 4 - QUADRUPLE_RIGHT = 5 - QUADRUPLE_UP = 6 - QUADRUPLE0_DOWN_LEFT = 7 - QUADRUPLE0_RIGHT = 8 - QUADRUPLE0_UP = 9 - - TRIPLE_12_LEFT = 10 - TRIPLE_12_RIGHT = 11 - TRIPLE_13_DOWN = 12 - TRIPLE_13_UP = 13 - TRIPLE_23_UP = 14 - TRIPLE_23_DOWN = 15 - TRIPLE0_12_LEFT = 16 - TRIPLE0_12_RIGHT = 17 - TRIPLE0_13_DOWN = 18 - TRIPLE0_13_Up = 19 - TRIPLE0_23_DOWN = 20 - TRIPLE0_23_UP = 21 - - BOUNDARY_12_LEFT = 22 - BOUNDARY_12_RIGHT = 23 - BOUNDARY_13_DOWN = 24 - BOUNDARY_13_UP = 25 - BOUNDARY_23_UP = 26 - BOUNDARY_23_DOWN = 27 - - TRIPLE_CURVE_1_DOWN = 28 - TRIPLE_CURVE_1_UP = 29 - TRIPLE_CURVE_2_DOWN = 30 - TRIPLE_CURVE_2_UP = 31 - TRIPLE_CURVE_3_LEFT = 32 - TRIPLE_CURVE_3_RIGHT = 33 - TRIPLE_CURVE0_1_UP = 34 - TRIPLE_CURVE0_1_DOWN = 35 - TRIPLE_CURVE0_2_DOWN = 36 - TRIPLE_CURVE0_2_UP = 37 - TRIPLE_CURVE0_3_LEFT = 38 - TRIPLE_CURVE0_3_RIGHT = 39 - - SURFACE_REGULAR_DOWN_LEFT = 40 - SURFACE_REGULAR_DOWN_RIGHT = 41 - SURFACE_REGULAR_UP = 42 - REGULAR = 43 - - # element types - ELEMENT_REGULAR = 1 - ELEMENT_QUADRUPLE_DOWN_LEFT = 2 - ELEMENT_QUADRUPLE_DOWN_RIGHT = 3 - ELEMENT_QUADRUPLE_UP_LEFT = 4 - ELEMENT_QUADRUPLE_DOWN = 5 - ELEMENT_QUADRUPLE_UP = 6 - ELEMENT_QUADRUPLE_LEFT = 7 - ELEMENT_QUADRUPLE_RIGHT = 8 - ELEMENT_DOWN_RIGHT = 9 - ELEMENT_DOWN_LEFT = 10 - def set_derivatives_for_irregualr_nodes(self, octant_number): """ For irregular nodes such as corners that are common between octants, change local derivatives to be the same @@ -883,10 +884,7 @@ def set_derivatives_for_irregualr_nodes(self, octant_number): triple12rightderivs = default if octant_number == 1: - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - corner3derivs = [-2, 1, 3] - else: - corner3derivs = [-2, 1, 3] + corner3derivs = [-2, 1, 3] elif octant_number == 2: corner3derivs = [-1, -2, 3] elif octant_number == 3: @@ -1384,65 +1382,37 @@ def get_element_type(self, e3, e2, e1): Find element type. :return:octant number, element type and extends for the octant. """ - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - octant_number = 1 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: - if e2 < self.elementsCountAcross[0]//2: - if e1 >= self.elementsCountAcross[1]//2: + if e3 >= self.elementsCountAcross[2] // 2: + if e2 < self.elementsCountAcross[0] // 2: + if e1 >= self.elementsCountAcross[1] // 2: octant_number = 1 else: octant_number = 2 else: - if e1 < self.elementsCountAcross[1]//2: + if e1 < self.elementsCountAcross[1] // 2: octant_number = 3 else: octant_number = 4 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if e3 >= self.elementsCountAcross[2] // 2: - if e2 < self.elementsCountAcross[0] // 2: - if e1 >= self.elementsCountAcross[1] // 2: - octant_number = 1 - else: - octant_number = 2 + else: + if e2 < self.elementsCountAcross[0] // 2: + if e1 >= self.elementsCountAcross[1] // 2: + octant_number = 5 else: - if e1 < self.elementsCountAcross[1] // 2: - octant_number = 3 - else: - octant_number = 4 + octant_number = 6 else: - if e2 < self.elementsCountAcross[0] // 2: - if e1 >= self.elementsCountAcross[1] // 2: - octant_number = 5 - else: - octant_number = 6 + if e1 < self.elementsCountAcross[1] // 2: + octant_number = 7 else: - if e1 < self.elementsCountAcross[1] // 2: - octant_number = 7 - else: - octant_number = 8 - - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[0] - 1 - e1zo = self.elementsCountAcross[1] - 1 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: - if octant_number in [1, 3]: - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[0] // 2 - 1 - e1zo = self.elementsCountAcross[1] // 2 - 1 - else: - e3zo = self.elementsCountAcross[2] - 1 - e2zo = self.elementsCountAcross[1] // 2 - 1 - e1zo = self.elementsCountAcross[0] // 2 - 1 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if octant_number in [2, 4, 5, 7]: - e3zo = self.elementsCountAcross[2] // 2 - 1 - e2zo = self.elementsCountAcross[1] // 2 - 1 - e1zo = self.elementsCountAcross[0] // 2 - 1 - else: - e3zo = self.elementsCountAcross[2] // 2 - 1 - e2zo = self.elementsCountAcross[0] // 2 - 1 - e1zo = self.elementsCountAcross[1] // 2 - 1 + octant_number = 8 + + if octant_number in [2, 4, 5, 7]: + e3zo = self.elementsCountAcross[2] // 2 - 1 + e2zo = self.elementsCountAcross[1] // 2 - 1 + e1zo = self.elementsCountAcross[0] // 2 - 1 + else: + e3zo = self.elementsCountAcross[2] // 2 - 1 + e2zo = self.elementsCountAcross[0] // 2 - 1 + e1zo = self.elementsCountAcross[1] // 2 - 1 e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 e3o, e2o, e1o = self.get_local_element_index(octant_number, e3, e2, e1) @@ -1477,37 +1447,22 @@ def get_local_element_index(self, octant_number, e3, e2, e1): Get octant element index from sphere element index. :return:e3o, e2o, e1o, local octant element indexes. """ - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - e3o, e2o, e1o = e3, e2, e1 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: - if octant_number == 1: - e3o, e2o, e1o = e3, e2, e1 - self.elementsCountAcross[1]//2 - elif octant_number == 2: - e3o, e2o, e1o = e3, e1, self.elementsCountAcross[0]//2 - 1 - e2 - elif octant_number == 3: - e3o, e2o, e1o = e3, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1]//2 - 1 - e1 - elif octant_number == 4: - e3o, e2o, e1o = e3, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0]//2 - - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if octant_number == 1: - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e2, e1 - self.elementsCountAcross[1] // 2 - elif octant_number == 2: - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e1, self.elementsCountAcross[0] // 2 - 1 - e2 - elif octant_number == 3: - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1] // 2 - 1 - e1 - elif octant_number == 4: - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0] // 2 - elif octant_number == 5: - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[1] - 1 - e1, self.elementsCountAcross[0]//2 - 1 - e2 - elif octant_number == 6: - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e2, self.elementsCountAcross[1] // 2 - 1 - e1 - elif octant_number == 7: - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e1, e2 - self.elementsCountAcross[0]//2 - elif octant_number == 8: - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[0] - 1 - e2, e1 - self.elementsCountAcross[1]//2 - else: - raise ValueError("Not implemented.") + if octant_number == 1: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e2, e1 - self.elementsCountAcross[1] // 2 + elif octant_number == 2: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e1, self.elementsCountAcross[0] // 2 - 1 - e2 + elif octant_number == 3: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1] // 2 - 1 - e1 + elif octant_number == 4: + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0] // 2 + elif octant_number == 5: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[1] - 1 - e1, self.elementsCountAcross[0]//2 - 1 - e2 + elif octant_number == 6: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e2, self.elementsCountAcross[1] // 2 - 1 - e1 + elif octant_number == 7: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e1, e2 - self.elementsCountAcross[0]//2 + elif octant_number == 8: + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[0] - 1 - e2, e1 - self.elementsCountAcross[1]//2 return e3o, e2o, e1o @@ -1516,34 +1471,22 @@ def get_global_node_index(self, octant_number, n3o, n2o, n1o): Get octant element index from sphere element index. :return: n3, n2, n1, sphere element indexes. """ - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - n3, n2, n1 = n3o, n2o, n1o - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: - if octant_number == 1: - n3, n2, n1 = n3o, n2o, n1o + self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 - n1o, n2o - elif octant_number == 3: - n3, n2, n1 = n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o - elif octant_number == 4: - n3, n2, n1 = n3o, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if octant_number == 1: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, n2o, n1o + self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 - n1o, n2o - elif octant_number == 3: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o - elif octant_number == 4: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o - elif octant_number == 5: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0]//2 - n1o, self.elementsCountAcross[1] - n2o - elif octant_number == 6: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n2o, self.elementsCountAcross[1]//2 - n1o - elif octant_number == 7: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n1o + self.elementsCountAcross[0]//2, n2o - elif octant_number == 8: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1]//2 + n1o + if octant_number == 1: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, n2o, n1o + self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 - n1o, n2o + elif octant_number == 3: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o + elif octant_number == 4: + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o + elif octant_number == 5: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0]//2 - n1o, self.elementsCountAcross[1] - n2o + elif octant_number == 6: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n2o, self.elementsCountAcross[1]//2 - n1o + elif octant_number == 7: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n1o + self.elementsCountAcross[0]//2, n2o + elif octant_number == 8: + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1]//2 + n1o return n3, n2, n1 @@ -1552,34 +1495,22 @@ def get_octant_node_index(self, octant_number, n3, n2, n1): Get local octant node index from sphere node index. :return: n3o, n2o, n1o, local octant node indexes. """ - if self._shieldMode == ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP: - n3o, n2o, n1o = n3, n2, n1 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_HALF_AAP: - if octant_number == 1: - n3o, n2o, n1o = n3, n2, n1 - self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3o, n2o, n1o = n3, n1, self.elementsCountAcross[0] // 2 - n2 - elif octant_number == 3: - n3o, n2o, n1o = n3, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 - elif octant_number == 4: - n3o, n2o, n1o = n3, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 - elif self._shieldMode == ShieldShape3D.SHIELD_SHAPE_FULL: - if octant_number == 1: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n2, n1 - self.elementsCountAcross[1] // 2 - elif octant_number == 2: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n1, self.elementsCountAcross[0] // 2 - n2 - elif octant_number == 3: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 - elif octant_number == 4: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 - elif octant_number == 5: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[1] - n1, self.elementsCountAcross[0]//2 - n2 - elif octant_number == 6: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n2, self.elementsCountAcross[1]//2 - n1 - elif octant_number == 7: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n1, n2 - self.elementsCountAcross[0]//2 - elif octant_number == 8: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[0] - n2, n1 - self.elementsCountAcross[1]//2 + if octant_number == 1: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n2, n1 - self.elementsCountAcross[1] // 2 + elif octant_number == 2: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n1, self.elementsCountAcross[0] // 2 - n2 + elif octant_number == 3: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 + elif octant_number == 4: + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 + elif octant_number == 5: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[1] - n1, self.elementsCountAcross[0]//2 - n2 + elif octant_number == 6: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n2, self.elementsCountAcross[1]//2 - n1 + elif octant_number == 7: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n1, n2 - self.elementsCountAcross[0]//2 + elif octant_number == 8: + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[0] - n2, n1 - self.elementsCountAcross[1]//2 return n3o, n2o, n1o diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 87029fc1..260db088 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -49,8 +49,9 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, the positive side of axis3. :param rangeOfRequiredElements: Specifies the range of elements required to be created. It can be used to create the part of sphere required. If None or same as elementsCountAcross the whole part will be created. - :param boxDerivatives: It is a list of [deriv1,deriv2,deriv3] and is used to change the derivatives names. - Default is [1, 3, 2] and [3, 1, 2] means swap 1 and 3. + :param boxDerivatives: It is a list of [deriv1,deriv2,deriv3]. It is used to set the derivative directions. + default is [1, 3, 2] which means it makes -d1, d3 and d2 in direction of axis1, axis2 and axis3. To make + d1, d2 and d3 directions in direction of axis1, axis2 and axis3 use [-1, 2, 3]. """ self._axes = axes @@ -122,7 +123,7 @@ def createSphereMesh3d(self, fieldModule, coordinates): elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL - self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=shieldMode, box_derivatives=self._boxDerivatives) + self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, box_derivatives=self._boxDerivatives) nodes = fieldModule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) mesh = fieldModule.findMeshByDimension(3) @@ -426,7 +427,7 @@ def createOctantMesh3d(self): """ elementsCountRim = self._elementsCountAcrossRim - self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, shieldMode=ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP) + self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim) self.create_boundary_ellipses_nodes() self.create_surface_and_interior_nodes() diff --git a/tests/test_sphere.py b/tests/test_sphere.py index e05b3272..0fc06f76 100644 --- a/tests/test_sphere.py +++ b/tests/test_sphere.py @@ -22,7 +22,7 @@ def test_sphere1(self): parameterSetNames = scaffold.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default"]) options = scaffold.getDefaultOptions("Default") - self.assertEqual(19, len(options)) + self.assertEqual(16, len(options)) self.assertEqual(4, options.get("Number of elements across axis 1")) self.assertEqual(4, options.get("Number of elements across axis 2")) self.assertEqual(4, options.get("Number of elements across axis 3")) From 1901db11f8b29fceb3fa49794f020a278a03ef4a Mon Sep 17 00:00:00 2001 From: elias-soltani Date: Fri, 5 Nov 2021 12:55:39 +1300 Subject: [PATCH 37/37] PEP8 fixes --- .../meshtypes/meshtype_3d_solidsphere2.py | 21 +- src/scaffoldmaker/utils/shieldmesh.py | 838 +++++++++++------- src/scaffoldmaker/utils/spheremesh.py | 101 ++- tests/test_sphere.py | 13 +- 4 files changed, 604 insertions(+), 369 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py index 09009ade..5d59cf1c 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_solidsphere2.py @@ -4,19 +4,13 @@ """ from __future__ import division -import math -import copy + from opencmiss.utils.zinc.field import findOrCreateFieldCoordinates +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.utils.meshrefinement import MeshRefinement -from scaffoldmaker.utils.zinc_utils import exnodeStringFromNodeValues -from scaffoldmaker.scaffoldpackage import ScaffoldPackage -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 -from opencmiss.zinc.node import Node -from opencmiss.zinc.field import Field from scaffoldmaker.utils.spheremesh import SphereMesh, SphereShape from scaffoldmaker.utils import vector -from scaffoldmaker.annotation.annotationgroup import AnnotationGroup class MeshType_3d_solidsphere2(Scaffold_base): @@ -185,17 +179,18 @@ def generateBaseMesh(region, options): axis1 = [1.0, 0.0, 0.0] axis2 = [0.0, 1.0, 0.0] axis3 = [0.0, 0.0, 1.0] - axes = [vector.scaleVector(axis1, radius[0]), vector.scaleVector(axis2, radius[1]), vector.scaleVector(axis3, radius[2])] + axes = [vector.scaleVector(axis1, radius[0]), + vector.scaleVector(axis2, radius[1]), + vector.scaleVector(axis3, radius[2])] elementsCountAcross = [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] sphere1 = SphereMesh(fm, coordinates, centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=sphere_shape, rangeOfRequiredElements=rangeOfRequiredElements, boxDerivatives=sphereBoxDerivatives, - useCrossDerivatives=False, meshGroups=meshGroups) + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=sphere_shape, rangeOfRequiredElements=rangeOfRequiredElements, + boxDerivatives=sphereBoxDerivatives, useCrossDerivatives=False, meshGroups=meshGroups) return annotationGroups - @classmethod def refineMesh(cls, meshRefinement, options): """ diff --git a/src/scaffoldmaker/utils/shieldmesh.py b/src/scaffoldmaker/utils/shieldmesh.py index 75a5124c..058441c1 100644 --- a/src/scaffoldmaker/utils/shieldmesh.py +++ b/src/scaffoldmaker/utils/shieldmesh.py @@ -6,18 +6,18 @@ from __future__ import division import copy -import math +from enum import Enum + from opencmiss.zinc.element import Element from opencmiss.zinc.field import Field from opencmiss.zinc.node import Node from scaffoldmaker.utils import vector -from scaffoldmaker.utils.mirror import Mirror from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite from scaffoldmaker.utils.eft_utils import remapEftNodeValueLabel, setEftScaleFactorIds from scaffoldmaker.utils.interpolation import DerivativeScalingMode, sampleCubicHermiteCurves, \ - smoothCubicHermiteDerivativesLine, interpolateSampleCubicHermite -from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition, calculate_surface_axes -from enum import Enum + smoothCubicHermiteDerivativesLine +from scaffoldmaker.utils.mirror import Mirror +from scaffoldmaker.utils.tracksurface import TrackSurface, calculate_surface_axes class ShieldShape2D(Enum): @@ -44,13 +44,14 @@ class ShieldRimDerivativeMode(Enum): class ShieldMesh2D: - ''' + """ Shield mesh generator. - ''' + """ - def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, trackSurface : TrackSurface=None, - elementsCountAlong=1, shieldMode=ShieldShape2D.SHIELD_SHAPE_LOWER_HALF, shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR): - ''' + def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, trackSurface: TrackSurface=None, + elementsCountAlong=1, shieldMode=ShieldShape2D.SHIELD_SHAPE_LOWER_HALF, + shieldType=ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR): + """ Data structure for defining a shield-shaped mesh which is flat on the top and rounded around the bottom and/or the same mirror mirrored on top. It is represented as a regular box of elementsCountAcross x elementsCountUp @@ -72,20 +73,24 @@ def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, t Extra elements up add regular rows of nodes/elements on top, and extra non-rim elements across add regular columns of nodes/elements up the centre. :param elementsCountAcross: Number of elements across top of shield. Must be at least 4 + 2*elementsCountRim. - :param elementsCountUpFull: Number of elements up central axis of shield. Must be at least 2 + elementsCountRim if half and 4 + 2*elementsCountRim if full. - :param elementsCountAlong: Number of elements through wall for ventricle case (only 1 element is supported) and along cylinder axis in cylinder case. + :param elementsCountUpFull: Number of elements up central axis of shield. Must be at least 2 + elementsCountRim + if half and 4 + 2*elementsCountRim if full. + :param elementsCountAlong: Number of elements through wall for ventricle case (only 1 element is supported) and + along cylinder axis in cylinder case. :param elementsCountRim: Number of elements around bottom rim (not top) outside of 'triple points'. :param trackSurface: Optional trackSurface to store or restrict points to. :param shieldMode: It determines if the shield is full or just part of it. - :param shieldType: To distinguish between cylinder and ventricle type. Derivatives and directions are chosen differently for two cases. - ''' + :param shieldType: To distinguish between cylinder and ventricle type. Derivatives and directions are chosen + differently for two cases. + """ assert elementsCountRim >= 0 assert elementsCountAlong >= 1 assert elementsCountAcross >= (elementsCountRim + 4) assert elementsCountUpFull >= (elementsCountRim + 2) self.elementsCountAcross = elementsCountAcross self.elementsCountUpFull = elementsCountUpFull - elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL else elementsCountUpFull + elementsCountUp = elementsCountUpFull//2 if shieldMode == ShieldShape2D.SHIELD_SHAPE_FULL\ + else elementsCountUpFull self.elementsCountUp = elementsCountUp self.elementsCountRim = elementsCountRim self.elementsCountAlong = elementsCountAlong @@ -95,29 +100,30 @@ def __init__(self, elementsCountAcross, elementsCountUpFull, elementsCountRim, t self.trackSurface = trackSurface self._mode = shieldMode self._type = shieldType - self.px = [ [] for _ in range(elementsCountAlong+1) ] - self.pd1 = [ [] for _ in range(elementsCountAlong+1) ] - self.pd2 = [ [] for _ in range(elementsCountAlong+1) ] - self.pd3 = [ [] for _ in range(elementsCountAlong+1) ] - self.nodeId = [ [] for _ in range(elementsCountAlong+1) ] + self.px = [[] for _ in range(elementsCountAlong+1)] + self.pd1 = [[] for _ in range(elementsCountAlong+1)] + self.pd2 = [[] for _ in range(elementsCountAlong+1)] + self.pd3 = [[] for _ in range(elementsCountAlong+1)] + self.nodeId = [[] for _ in range(elementsCountAlong+1)] for n3 in range(elementsCountAlong+1): for n2 in range(elementsCountUpFull + 1): - for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: - p.append([ None ]*(elementsCountAcross + 1)) + for p in [self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3]]: + p.append([None]*(elementsCountAcross + 1)) if trackSurface: - self.pProportions = [ [ None ]*(elementsCountAcross + 1) for n2 in range(elementsCountUp + 1) ] + self.pProportions = [[None]*(elementsCountAcross + 1) for n2 in range(elementsCountUp + 1)] if shieldType == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.elementId = [ [[ None ]*elementsCountAcross for n2 in range(elementsCountUpFull)] for e3 in range(elementsCountAlong) ] + self.elementId = [[[None]*elementsCountAcross for n2 in range(elementsCountUpFull)] + for e3 in range(elementsCountAlong)] else: self.elementId = [[None] * elementsCountAcross for n2 in range(elementsCountUpFull)] def convertRimIndex(self, ix, rx=0): - ''' + """ Convert point index around the lower rim to n1, n2 across and up box. :param ix: index around from 0 to self.elementsCountAroundFull :param rx: rim index from 0 (around outside) to self.elementsCountRim :return: n1, n2 - ''' + """ assert 0 <= ix <= self.elementsCountAroundFull assert 0 <= rx <= self.elementsCountRim if ix <= self.elementsCountUpRegular: @@ -127,12 +133,11 @@ def convertRimIndex(self, ix, rx=0): return self.elementsCountAcross - rx, self.elementsCountUp - mx return self.elementsCountRim + ix - self.elementsCountUpRegular, rx - def getTriplePoints(self, n3): - ''' + """ Compute coordinates and derivatives of points where 3 square elements merge. :param n3: Index of through-wall coordinates to use. - ''' + """ n1a = self.elementsCountRim n1b = n1a + 1 n1c = n1a + 2 @@ -147,93 +152,122 @@ def getTriplePoints(self, n3): if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]],[[(-self.pd1[n3][n2a][n1c][c] - self.pd3[n3][n2a][n1c][c]) for c in range(3)], self.pd1[n3][n2c][n1b]],2, arcLengthDerivatives=True)[0:2] + [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]], + [[(-self.pd1[n3][n2a][n1c][c] - self.pd3[n3][n2a][n1c][c]) for c in range(3)], self.pd1[n3][n2c][n1b]], + 2, arcLengthDerivatives=True)[0:2] ltx.append(tx[1]) # tx, td1 = sampleCubicHermiteCurves( - # [ self.px[n3][n2a][n1b], self.px[n3][n2c][n1c] ], [ [-self.pd3[n3][n2a][n1b][c] for c in range(3)], [ (self.pd1[n3][n2c][n1c][c] + self.pd3[n3][n2c][n1c][c]) for c in range(3) ] ], 2, arcLengthDerivatives = True)[0:2] + # [ self.px[n3][n2a][n1b], self.px[n3][n2c][n1c] ], [ [-self.pd3[n3][n2a][n1b][c] for c in range(3)], + # [ (self.pd1[n3][n2c][n1c][c] + self.pd3[n3][n2c][n1c][c]) for c in range(3) ] ], + # 2, arcLengthDerivatives = True)[0:2] ltx.append(tx[1]) tx, td1 = sampleCubicHermiteCurves( - [ self.px[n3][n2c][n1a], self.px[n3][n2b][n1c] ], [ [ (self.pd1[n3][n2c][n1a][c] - self.pd3[n3][n2c][n1a][c]) for c in range(3) ], self.pd3[n3][n2b][n1c] ], 2, arcLengthDerivatives = True)[0:2] + [self.px[n3][n2c][n1a], self.px[n3][n2b][n1c]], + [[(self.pd1[n3][n2c][n1a][c] - self.pd3[n3][n2c][n1a][c]) for c in range(3)], + self.pd3[n3][n2b][n1c]], 2, arcLengthDerivatives=True)[0:2] ltx.append(tx[1]) elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]], [[(-self.pd1[n3][n2a][n1c][c] + self.pd2[n3][n2a][n1c][c]) for c in range(3)],self.pd2[n3][n2c][n1b]], 2, arcLengthDerivatives = True)[0: 2] + [self.px[n3][n2a][n1c], self.px[n3][n2c][n1b]], + [[(-self.pd1[n3][n2a][n1c][c] + self.pd2[n3][n2a][n1c][c]) for c in range(3)], + self.pd2[n3][n2c][n1b]], 2, arcLengthDerivatives=True)[0: 2] ltx.append(tx[1]) tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][n1b], self.px[n3][n2c][n1c]], [self.pd2[n3][n2a][n1b], [(self.pd1[n3][n2c][n1c][c] + self.pd2[n3][n2c][n1c][c]) for c in range(3)]], 2, arcLengthDerivatives = True)[0: 2] + [self.px[n3][n2a][n1b], self.px[n3][n2c][n1c]], + [self.pd2[n3][n2a][n1b], [(self.pd1[n3][n2c][n1c][c] + self.pd2[n3][n2c][n1c][c]) for c in range(3)]], + 2, arcLengthDerivatives=True)[0: 2] ltx.append(tx[1]) tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2c][n1a], self.px[n3][n2b][n1c]], [[(self.pd1[n3][n2c][n1a][c] - self.pd2[n3][n2c][n1a][c]) for c in range(3)], self.pd1[n3][n2b][n1c]], 2, arcLengthDerivatives = True)[0: 2] + [self.px[n3][n2c][n1a], self.px[n3][n2b][n1c]], + [[(self.pd1[n3][n2c][n1a][c] - self.pd2[n3][n2c][n1a][c]) for c in range(3)], self.pd1[n3][n2b][n1c]], + 2, arcLengthDerivatives=True)[0: 2] ltx.append(tx[1]) - #x = [ (ltx[0][c] + ltx[1][c] + ltx[2][c])/3.0 for c in range(3) ] - x = [ (ltx[0][c] + ltx[2][c])/2.0 for c in range(3) ] + # x = [ (ltx[0][c] + ltx[1][c] + ltx[2][c])/3.0 for c in range(3) ] + x = [(ltx[0][c] + ltx[2][c])/2.0 for c in range(3)] if self.trackSurface: - p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*(self.pProportions[n2b][n1c]))) + p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*( + self.pProportions[n2b][n1c]))) self.pProportions[n2b][n1b] = self.trackSurface.getProportion(p) x, sd1, sd2 = self.trackSurface.evaluateCoordinates(p, derivatives=True) d1, d2, d3 = calculate_surface_axes(sd1, sd2, vector.normalise(sd1)) self.pd3[n3][n2b][n1b] = d3 - self.px [n3][n2b][n1b] = x + self.px[n3][n2b][n1b] = x if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd3[n3][n2b][n1b] = [ (self.px[n3][n2b][n1c][c] - self.px[n3][n2b][n1b][c]) for c in range(3) ] - self.pd1[n3][n2b][n1b] = [ (self.px[n3][n2c][n1b][c] - self.px[n3][n2b][n1b][c]) for c in range(3) ] + self.pd3[n3][n2b][n1b] = [(self.px[n3][n2b][n1c][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] + self.pd1[n3][n2b][n1b] = [(self.px[n3][n2c][n1b][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: self.pd1[n3][n2b][n1b] = [(self.px[n3][n2b][n1c][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] self.pd2[n3][n2b][n1b] = [(self.px[n3][n2c][n1b][c] - self.px[n3][n2b][n1b][c]) for c in range(3)] if not self.trackSurface: if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd2[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][n1b], self.pd1[n3][n2b][n1b])) + self.pd2[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][n1b], + self.pd1[n3][n2b][n1b])) elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - self.pd3[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][n1b], self.pd2[n3][n2b][n1b])) + self.pd3[n3][n2b][n1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][n1b], + self.pd2[n3][n2b][n1b])) # right rtx = [] if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: tx, td1 = sampleCubicHermiteCurves( - [ self.px[n3][n2a][m1c], self.px[n3][n2c][m1b] ], [ [ (self.pd1[n3][n2a][m1c][c] - self.pd3[n3][n2a][m1c][c]) for c in range(3) ], self.pd1[n3][n2c][m1b] ], 2, arcLengthDerivatives = True)[0:2] + [self.px[n3][n2a][m1c], self.px[n3][n2c][m1b]], + [[(self.pd1[n3][n2a][m1c][c] - self.pd3[n3][n2a][m1c][c]) for c in range(3)], self.pd1[n3][n2c][m1b]], + 2, arcLengthDerivatives=True)[0:2] rtx.append(tx[1]) # tx, td1 = sampleCubicHermiteCurves( - # [ self.px[n3][n2a][m1b], self.px[n3][n2c][m1c] ], [ [-self.pd3[n3][n2a][m1b][c] for c in range(3)], [ (-self.pd3[n3][n2c][m1c][c] + self.pd1[n3][n2c][m1c][c]) for c in range(3) ] ], 2, arcLengthDerivatives = True)[0:2] + # [ self.px[n3][n2a][m1b], self.px[n3][n2c][m1c] ], [ [-self.pd3[n3][n2a][m1b][c] for c in range(3)], + # [ (-self.pd3[n3][n2c][m1c][c] + self.pd1[n3][n2c][m1c][c]) for c in range(3) ] ], + # 2, arcLengthDerivatives = True)[0:2] rtx.append(tx[1]) tx, td1 = sampleCubicHermiteCurves( - [ self.px[n3][n2c][m1a], self.px[n3][n2b][m1c] ], [ [ (-self.pd1[n3][n2c][m1a][c] - self.pd3[n3][n2c][m1a][c]) for c in range(3) ], [ -d for d in self.pd3[n3][n2b][m1c] ] ], 2, arcLengthDerivatives = True)[0:2] + [self.px[n3][n2c][m1a], self.px[n3][n2b][m1c]], + [[(-self.pd1[n3][n2c][m1a][c] - self.pd3[n3][n2c][m1a][c]) for c in range(3)], + [-d for d in self.pd3[n3][n2b][m1c]]], 2, arcLengthDerivatives=True)[0:2] rtx.append(tx[1]) elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][m1c], self.px[n3][n2c][m1b]], [[(self.pd1[n3][n2a][m1c][c] + self.pd2[n3][n2a][m1c][c]) for c in range(3)],self.pd2[n3][n2c][m1b]], 2, arcLengthDerivatives = True)[0: 2] + [self.px[n3][n2a][m1c], self.px[n3][n2c][m1b]], + [[(self.pd1[n3][n2a][m1c][c] + self.pd2[n3][n2a][m1c][c]) for c in range(3)], self.pd2[n3][n2c][m1b]], + 2, arcLengthDerivatives=True)[0: 2] rtx.append(tx[1]) tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2a][m1b], self.px[n3][n2c][m1c]], [self.pd2[n3][n2a][m1b], [(-self.pd1[n3][n2c][m1c][c] + self.pd2[n3][n2c][m1c][c]) for c in range(3)]], 2, arcLengthDerivatives = True)[0: 2] + [self.px[n3][n2a][m1b], self.px[n3][n2c][m1c]], + [self.pd2[n3][n2a][m1b], [(-self.pd1[n3][n2c][m1c][c] + self.pd2[n3][n2c][m1c][c]) for c in range(3)]], + 2, arcLengthDerivatives=True)[0: 2] rtx.append(tx[1]) tx, td1 = sampleCubicHermiteCurves( - [self.px[n3][n2c][m1a], self.px[n3][n2b][m1c]], [[(-self.pd1[n3][n2c][m1a][c] - self.pd2[n3][n2c][m1a][c]) for c in range(3)],[-d for d in self.pd1[n3][n2b][m1c]]], 2, arcLengthDerivatives = True)[0: 2] + [self.px[n3][n2c][m1a], self.px[n3][n2b][m1c]], + [[(-self.pd1[n3][n2c][m1a][c] - self.pd2[n3][n2c][m1a][c]) for c in range(3)], + [-d for d in self.pd1[n3][n2b][m1c]]], 2, arcLengthDerivatives=True)[0: 2] rtx.append(tx[1]) - #x = [ (rtx[0][c] + rtx[1][c] + rtx[2][c])/3.0 for c in range(3) ] - x = [ (rtx[0][c] + rtx[2][c])/2.0 for c in range(3) ] + # x = [ (rtx[0][c] + rtx[1][c] + rtx[2][c])/3.0 for c in range(3) ] + x = [(rtx[0][c] + rtx[2][c])/2.0 for c in range(3)] if self.trackSurface: - p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*(self.pProportions[n2b][m1c]))) + p = self.trackSurface.findNearestPosition(x, startPosition=self.trackSurface.createPositionProportion(*( + self.pProportions[n2b][m1c]))) self.pProportions[n2b][m1b] = self.trackSurface.getProportion(p) x, sd1, sd2 = self.trackSurface.evaluateCoordinates(p, derivatives=True) d1, d2, d3 = calculate_surface_axes(sd1, sd2, vector.normalise(sd1)) self.pd3[n3][n2b][m1b] = d3 - self.px [n3][n2b][m1b] = x + self.px[n3][n2b][m1b] = x if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd3[n3][n2b][m1b] = [ (self.px[n3][n2b][m1b][c] - self.px[n3][n2b][m1c][c]) for c in range(3) ] - self.pd1[n3][n2b][m1b] = [ (self.px[n3][n2c][m1b][c] - self.px[n3][n2b][m1b][c]) for c in range(3) ] + self.pd3[n3][n2b][m1b] = [(self.px[n3][n2b][m1b][c] - self.px[n3][n2b][m1c][c]) for c in range(3)] + self.pd1[n3][n2b][m1b] = [(self.px[n3][n2c][m1b][c] - self.px[n3][n2b][m1b][c]) for c in range(3)] elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: self.pd1[n3][n2b][m1b] = [(self.px[n3][n2b][m1b][c] - self.px[n3][n2b][m1c][c]) for c in range(3)] self.pd2[n3][n2b][m1b] = [(self.px[n3][n2c][m1b][c] - self.px[n3][n2b][m1b][c]) for c in range(3)] if not self.trackSurface: if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - self.pd2[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][m1b], self.pd1[n3][n2b][m1b])) + self.pd2[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd3[n3][n2b][m1b], + self.pd1[n3][n2b][m1b])) elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - self.pd3[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][m1b], self.pd2[n3][n2b][m1b])) - + self.pd3[n3][n2b][m1b] = vector.normalise(vector.crossproduct3(self.pd1[n3][n2b][m1b], + self.pd2[n3][n2b][m1b])) def smoothDerivativesToTriplePoints(self, n3, fixAllDirections=False): - ''' + """ Smooth derivatives leading to triple points where 3 square elements merge. :param n3: Index of through-wall coordinates to use. - ''' + """ n1a = self.elementsCountRim n1b = n1a + 1 n1z = self.elementsCountAcross - self.elementsCountRim @@ -252,7 +286,7 @@ def smoothDerivativesToTriplePoints(self, n3, fixAllDirections=False): if n2 < n2b: td3.append([-self.pd3[n3][n2][n1b][c] for c in range(3)]) else: - td3.append([(self.pd1[n3][n2b][n1b][c] + self.pd3[n3][n2b][n1b][c]) for c in range(3)] ) + td3.append([(self.pd1[n3][n2b][n1b][c] + self.pd3[n3][n2b][n1b][c]) for c in range(3)]) td3 = smoothCubicHermiteDerivativesLine(tx, td3, fixStartDirection=True, fixEndDirection=True) @@ -279,28 +313,32 @@ def smoothDerivativesToTriplePoints(self, n3, fixAllDirections=False): tx = [] td2 = [] for n2 in range(0, n2c): - tx .append(self.px [n3][n2][n1b]) - td2.append(self.pd2[n3][n2][n1b] if (n2 < n2b) else [(self.pd1[n3][n2][n1b][c] + self.pd2[n3][n2][n1b][c]) for c in range(3)]) - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections, fixEndDerivative=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) + tx .append(self.px[n3][n2][n1b]) + td2.append(self.pd2[n3][n2][n1b] if (n2 < n2b) else + [(self.pd1[n3][n2][n1b][c] + self.pd2[n3][n2][n1b][c]) for c in range(3)]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections, fixEndDerivative=True, + magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) for n2 in range(0, n2b): self.pd2[n3][n2][n1b] = td2[n2] # right tx = [] td2 = [] for n2 in range(0, n2c): - tx .append(self.px [n3][n2][m1b]) - td2.append(self.pd2[n3][n2][m1b] if (n2 < n2b) else [(-self.pd1[n3][n2][m1b][c] + self.pd2[n3][n2][m1b][c]) for c in range(3)]) - td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections,fixEndDerivative=True,magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) + tx .append(self.px[n3][n2][m1b]) + td2.append(self.pd2[n3][n2][m1b] if (n2 < n2b) else + [(-self.pd1[n3][n2][m1b][c] + self.pd2[n3][n2][m1b][c]) for c in range(3)]) + td2 = smoothCubicHermiteDerivativesLine(tx, td2, fixAllDirections=fixAllDirections, fixEndDerivative=True, + magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) for n2 in range(0, n2b): self.pd2[n3][n2][m1b] = td2[n2] def smoothDerivativesAroundRim(self, n3, n3d=None, rx=0): - ''' + """ Smooth derivatives around rim. :param n3: Index of through-wall coordinates to use. :param n3d: Which n3 index to copy initial derivatives from. If None, use n3. :param rx: rim index from 0 (around outside) to self.elementsCountRim - ''' + """ assert 0 <= rx <= self.elementsCountRim if not n3d: n3d = n3 @@ -314,7 +352,7 @@ def smoothDerivativesAroundRim(self, n3, n3d=None, rx=0): elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: if n2 > self.elementsCountRim: # regular rows if n1 <= self.elementsCountRim: - td1.append([ -d for d in self.pd2[n3d][n2][n1] ]) + td1.append([-d for d in self.pd2[n3d][n2][n1]]) else: td1.append(self.pd2[n3d][n2][n1]) else: @@ -332,7 +370,7 @@ def smoothDerivativesAroundRim(self, n3, n3d=None, rx=0): elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: if n2 > self.elementsCountRim: # regular rows if n1 <= self.elementsCountRim: - self.pd2[n3][n2][n1] = [ -d for d in td1[ix] ] + self.pd2[n3][n2][n1] = [-d for d in td1[ix]] else: self.pd2[n3][n2][n1] = td1[ix] else: @@ -340,9 +378,10 @@ def smoothDerivativesAroundRim(self, n3, n3d=None, rx=0): def remap_derivatives(self, squareMapping, circleMapping=None): """ - It remaps the derivatives as indicated by squareMapping and circleMapping. Limited to SHIELD_RIM_DERIVATIVE_MODE_AROUND. - :param squareMapping: List[up, right]. Determines what derivatives should be in the up and right directions in the - square part. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. + It remaps the derivatives as indicated by squareMapping and circleMapping. + Limited to SHIELD_RIM_DERIVATIVE_MODE_AROUND. + :param squareMapping: List[up, right]. Determines what derivatives should be in the up and right directions in + the square part. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. The negative sign reverses the direction. e.g. [-3,2] means d3 is down and d2 is right. The third derivative is determined by the other two. RH rule applied. Assumes [1,3] initially. :param circleMapping: List[circumferential, radial]. Determines what derivatives should be used for @@ -385,7 +424,7 @@ def generateNodesForOtherHalf(self, mirrorPlane): :param mirrorPlane: plane ax+by+cz=d in form of [a,b,c,d] :return: """ - mirror=Mirror(mirrorPlane) + mirror = Mirror(mirrorPlane) for n2 in range(self.elementsCountUp): for n3 in range(self.elementsCountAlong + 1): for n1 in range(self.elementsCountAcross + 1): @@ -395,7 +434,7 @@ 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, mirrorPlane=None): """ Create shield nodes from coordinates. :param fieldmodule: Zinc fieldmodule to create nodes in. Uses DOMAIN_TYPE_NODES. @@ -414,7 +453,7 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) cache = fieldmodule.createFieldcache() - #for n2 in range(self.elementsCountUp, -1, -1): + # for n2 in range(self.elementsCountUp, -1, -1): # s = "" # for n1 in range(self.elementsCountAcross + 1): # s += str(n1) if self.px[1][n2][n1] else " " @@ -430,7 +469,7 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan node = nodes.createNode(nodeIdentifier, nodetemplate) self.nodeId[n3][n2][n1] = nodeIdentifier cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, self.px [n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, self.px[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, self.pd1[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, self.pd2[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, self.pd3[n3][n2][n1]) @@ -438,7 +477,6 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier,mirrorPlan return nodeIdentifier - def generateElements(self, fieldmodule, coordinates, startElementIdentifier, meshGroups=[]): """ Create shield elements from nodes. @@ -478,22 +516,30 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes eft1 = eft scalefactors = None if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: - nids = [ self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2 + 1][e1], - self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3+1][e2][e1 + 1], self.nodeId[e3+1][e2 + 1][e1 + 1] ] + nids = [self.nodeId[e3][e2][e1], self.nodeId[e3][e2 + 1][e1], + self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2 + 1][e1], + self.nodeId[e3][e2][e1 + 1], self.nodeId[e3][e2 + 1][e1 + 1], + self.nodeId[e3+1][e2][e1 + 1], self.nodeId[e3+1][e2 + 1][e1 + 1]] elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: - nids = [self.nodeId[0][e2][e1], self.nodeId[0][e2][e1 + 1], self.nodeId[0][e2 + 1][e1],self.nodeId[0][e2 + 1][e1 + 1], - self.nodeId[1][e2][e1], self.nodeId[1][e2][e1 + 1], self.nodeId[1][e2 + 1][e1], self.nodeId[1][e2 + 1][e1 + 1]] + nids = [self.nodeId[0][e2][e1], self.nodeId[0][e2][e1 + 1], + self.nodeId[0][e2 + 1][e1], self.nodeId[0][e2 + 1][e1 + 1], + self.nodeId[1][e2][e1], self.nodeId[1][e2][e1 + 1], + self.nodeId[1][e2 + 1][e1], self.nodeId[1][e2 + 1][e1 + 1]] if (e2 < e2b) or (e2 > e2y): if (e1 < e1b) or (e1 > e1y): continue # no element due to triple point closure if (e2 < e2a) or (e2 > e2z): if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: if e2 < e2a: - nids = [self.nodeId[e3][e2+1][e1], self.nodeId[e3][e2+1][e1+1], self.nodeId[e3+1][e2+1][e1], self.nodeId[e3+1][e2+1][e1+1], - self.nodeId[e3][e2][e1], self.nodeId[e3][e2][e1+1], self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2][e1+1]] + nids = [self.nodeId[e3][e2+1][e1], self.nodeId[e3][e2+1][e1+1], + self.nodeId[e3+1][e2+1][e1], self.nodeId[e3+1][e2+1][e1+1], + self.nodeId[e3][e2][e1], self.nodeId[e3][e2][e1+1], + self.nodeId[e3+1][e2][e1], self.nodeId[e3+1][e2][e1+1]] elif e2 > e2z: - nids = [self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2][e1], self.nodeId[e3+1][e2][e1+1], self.nodeId[e3+1][e2][e1], - self.nodeId[e3][e2+1][e1+1], self.nodeId[e3][e2+1][e1], self.nodeId[e3+1][e2+1][e1+1], self.nodeId[e3+1][e2+1][e1]] + nids = [self.nodeId[e3][e2][e1+1], self.nodeId[e3][e2][e1], + self.nodeId[e3+1][e2][e1+1], self.nodeId[e3+1][e2][e1], + self.nodeId[e3][e2+1][e1+1], self.nodeId[e3][e2+1][e1], + self.nodeId[e3+1][e2+1][e1+1], self.nodeId[e3+1][e2+1][e1]] elif (e2 == e2a) or (e2 == e2z): # bottom and top row elements if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: @@ -501,36 +547,52 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS3, [1])]) - remapEftNodeValueLabel(eft1, [1, 3, 5, 7], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [1, 3, 5, 7], + Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft1, [1, 3, 5, 7], + Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS1, [])]) if (e1 == e1b) or (e1 == e1y): # map bottom triple point element if e1 == e1b: - remapEftNodeValueLabel(eft1, [ 2, 4 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [] ), ( Node.VALUE_LABEL_D_DS3, [] ) ]) + remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS3, [])]) else: - remapEftNodeValueLabel(eft1, [ 6, 8 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [] ), ( Node.VALUE_LABEL_D_DS3, [1] ) ]) + remapEftNodeValueLabel(eft1, [6, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS3, [1])]) elif e2 == e2z: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [2, 4, 6, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS3, [])]) if (e1 == e1b) or (e1 == e1y): # map top triple point element if e1 == e1b: - remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [1])]) + remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS3, [1])]) else: - remapEftNodeValueLabel(eft1, [5, 7], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [5, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS3, [])]) elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: if (e1 == e1b) or (e1 == e1y): # map bottom triple point element eft1 = tricubichermite.createEftNoCrossDerivatives() if e1 == e1b: - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS2, [])]) else: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [1]),(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), + (Node.VALUE_LABEL_D_DS2, [])]) elif (e2 == e2b) or (e2 == e2y): if (e1 <= e1a) or (e1 >= e1z): @@ -538,51 +600,64 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes e2r = e1 if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: if e2 == e2b: - nids = [self.nodeId[e3][e2c][e1+1], self.nodeId[e3][e2r+1][e1b], self.nodeId[e3+1][e2c][e1+1], self.nodeId[e3+1][e2r+1][e1b], - self.nodeId[e3][e2c][e1], self.nodeId[e3][e2r][e1b], self.nodeId[e3+1][e2c][e1], self.nodeId[e3+1][e2r][e1b]] + nids = [self.nodeId[e3][e2c][e1+1], self.nodeId[e3][e2r+1][e1b], + self.nodeId[e3+1][e2c][e1+1], self.nodeId[e3+1][e2r+1][e1b], + self.nodeId[e3][e2c][e1], self.nodeId[e3][e2r][e1b], + self.nodeId[e3+1][e2c][e1], self.nodeId[e3+1][e2r][e1b]] if e2 == e2y: e2r = 2*self.elementsCountUp - e1-1 - nids = [self.nodeId[e3][e2r][e1b], self.nodeId[e3][e2y][e1+1], self.nodeId[e3+1][e2r][e1b], self.nodeId[e3+1][e2y][e1+1], - self.nodeId[e3][e2r+1][e1b], self.nodeId[e3][e2y][e1], self.nodeId[e3+1][e2r+1][e1b], self.nodeId[e3+1][e2y][e1]] + nids = [self.nodeId[e3][e2r][e1b], self.nodeId[e3][e2y][e1+1], + self.nodeId[e3+1][e2r][e1b], self.nodeId[e3+1][e2y][e1+1], + self.nodeId[e3][e2r+1][e1b], self.nodeId[e3][e2y][e1], + self.nodeId[e3+1][e2r+1][e1b], self.nodeId[e3+1][e2y][e1]] elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - nids[0] = self.nodeId[0][e2r ][e1b] + nids[0] = self.nodeId[0][e2r][e1b] nids[1] = self.nodeId[0][e2r + 1][e1b] - nids[4] = self.nodeId[1][e2r ][e1b] + nids[4] = self.nodeId[1][e2r][e1b] nids[5] = self.nodeId[1][e2r + 1][e1b] - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS2, [ ( Node.VALUE_LABEL_D_DS1, [1] ) ]) - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS2, [] ) ]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) elif e1 == e1a: eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] + scalefactors = [-1.0] if e2 == e2b: nids[0] = self.nodeId[e3][e2a][e1b] nids[2] = self.nodeId[e3+1][e2a][e1b] tripleN = [5, 7] - remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS3, [])]) elif e2 == e2y: nids[1] = self.nodeId[e3][e2z+1][e1b] nids[3] = self.nodeId[e3+1][e2z+1][e1b] tripleN = [6, 8] - remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS3, [])]) - remapEftNodeValueLabel(eft1, [ 1, 2, 3, 4 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS1, [1] ) ]) - remapEftNodeValueLabel(eft1, [ 1, 2, 3, 4 ], Node.VALUE_LABEL_D_DS3, [ ( Node.VALUE_LABEL_D_DS3, [1] ) ]) + remapEftNodeValueLabel(eft1, tripleN, Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), + (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS3, [1])]) elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] + scalefactors = [-1.0] nids[0] = self.nodeId[0][e2a][e1b] nids[4] = self.nodeId[1][e2a][e1b] - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) elif e1 == e1z: eft1 = tricubichermite.createEftNoCrossDerivatives() if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: @@ -591,27 +666,35 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes scalefactors = [-1.0] nids[4] = self.nodeId[e3][e2a][e1z] nids[6] = self.nodeId[e3+1][e2a][e1z] - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [ 1, 3 ], Node.VALUE_LABEL_D_DS3, [ ( Node.VALUE_LABEL_D_DS1, [1] ), ( Node.VALUE_LABEL_D_DS3, [] ) ]) + remapEftNodeValueLabel(eft1, [1, 3], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, [1]), + (Node.VALUE_LABEL_D_DS3, [])]) elif e2 == e2y: nids[5] = self.nodeId[e3][e2z+1][e1z] nids[7] = self.nodeId[e3+1][e2z+1][e1z] - remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS3,[(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS3, [])]) + remapEftNodeValueLabel(eft1, [2, 4], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS3, [])]) elif self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_REGULAR: setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] nids[1] = self.nodeId[0][e2a][e1z] nids[5] = self.nodeId[1][e2a][e1z] - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS1, []),(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1,[(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2,[(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), + (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) elif e1 > e1z: e2r = self.elementsCountAcross - e1 if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: if e2 == e2b: - nids = [self.nodeId[e3][e2r][e1z], self.nodeId[e3][e2c][e1], self.nodeId[e3+1][e2r][e1z], self.nodeId[e3+1][e2c][e1], - self.nodeId[e3][e2r-1][e1z], self.nodeId[e3][e2c][e1+1], self.nodeId[e3+1][e2r-1][e1z], self.nodeId[e3+1][e2c][e1+1]] + nids = [self.nodeId[e3][e2r][e1z], self.nodeId[e3][e2c][e1], + self.nodeId[e3+1][e2r][e1z], self.nodeId[e3+1][e2c][e1], + self.nodeId[e3][e2r-1][e1z], self.nodeId[e3][e2c][e1+1], + self.nodeId[e3+1][e2r-1][e1z], self.nodeId[e3+1][e2c][e1+1]] elif e2 == e2y: e2r = e2z+e1-e1z nids[1] = self.nodeId[e3][e2r][e1z] @@ -622,26 +705,30 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) scalefactors = [-1.0] - nids[0] = self.nodeId[0][e2r ][e1z] + nids[0] = self.nodeId[0][e2r][e1z] nids[1] = self.nodeId[0][e2r - 1][e1z] - nids[4] = self.nodeId[1][e2r ][e1z] + nids[4] = self.nodeId[1][e2r][e1z] nids[5] = self.nodeId[1][e2r - 1][e1z] - setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS1, [ ( Node.VALUE_LABEL_D_DS2, [1] ) ]) - remapEftNodeValueLabel(eft1, [ 1, 2, 5, 6 ], Node.VALUE_LABEL_D_DS2, [ ( Node.VALUE_LABEL_D_DS1, [] ) ]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 5, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) else: if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: if e1 < e1a: - nids = [ self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3][e2][e1 + 1], self.nodeId[e3+1][e2 + 1][e1 + 1], self.nodeId[e3+1][e2][e1 + 1], - self.nodeId[e3][e2 + 1][e1], self.nodeId[e3][e2][e1], self.nodeId[e3+1][e2 + 1][e1], self.nodeId[e3+1][e2][e1]] + nids = [self.nodeId[e3][e2 + 1][e1 + 1], self.nodeId[e3][e2][e1 + 1], + self.nodeId[e3+1][e2 + 1][e1 + 1], self.nodeId[e3+1][e2][e1 + 1], + self.nodeId[e3][e2 + 1][e1], self.nodeId[e3][e2][e1], + self.nodeId[e3+1][e2 + 1][e1], self.nodeId[e3+1][e2][e1]] elif e1 == e1a: # map left column elements eft1 = tricubichermite.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) - scalefactors = [ -1.0 ] - remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS1, [1])]) - remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS3, [(Node.VALUE_LABEL_D_DS3, [1])]) + scalefactors = [-1.0] + remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 2, 3, 4], Node.VALUE_LABEL_D_DS3, + [(Node.VALUE_LABEL_D_DS3, [1])]) if eft1 is not eft: elementtemplate1.defineField(coordinates, -1, eft1) @@ -653,7 +740,7 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier, mes result3 = element.setScaleFactors(eft1, scalefactors) else: result3 = 7 - #print('create element shield', elementIdentifier, result2, result3, nids) + # print('create element shield', elementIdentifier, result2, result3, nids) if self._type == ShieldRimDerivativeMode.SHIELD_RIM_DERIVATIVE_MODE_AROUND: self.elementId[e3][e2][e1] = elementIdentifier else: @@ -673,20 +760,23 @@ class ShieldMesh3D: def __init__(self, elementsCountAcross, elementsCountRim, box_derivatives=None): """ - 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the centre. + 3D shield structure can be used for a sphere mesh. 3 hex mesh merges to one box in the corner located in the + centre. The structure is a 3D version of the 2D shield structure. It has a 'quadruple point', a unique node on the surface where the elements merge. 'Triple curves' meet at the quadruple point and a fourth curve that connects to another quadruple point which is inside. The structure is like a elementsCountAcross[0] X elementsCountAcross[1] X elementsCountAcross[2] box where - some nodes does not exist and stored as None. The quadruple point is stored at [n3z][0][n1z] (top, front and right most node) - where n3z is top most and n1z is the right most indexes. - Triple curves and surfaces connecting to the quadruple point divide the exterior surface and interior region into 3 regions - (top, left and right). Triple curve 1 connects the quadruple point to the plane 2-3. Similarly, triple curves 2 and 3 - connect the quadruple point to the planes 1-3 and 1-2, respectively. It is the same for the inside quadruple. - Any point on region left has n2 = 0. Similarly on region right -> n1 = n1z and on top -> n3 = n3z. + some nodes does not exist and stored as None. The quadruple point is stored at [n3z][0][n1z] (top, front and + right most node) where n3z is top most and n1z is the right most indexes. + Triple curves and surfaces connecting to the quadruple point divide the exterior surface and interior region + into 3 regions (top, left and right). Triple curve 1 connects the quadruple point to the plane 2-3. + Similarly, triple curves 2 and 3 connect the quadruple point to the planes 1-3 and 1-2, respectively. + It is the same for the inside quadruple. Any point on region left has n2 = 0. Similarly on region + right -> n1 = n1z and on top -> n3 = n3z. There is a gap between node indexes of a node on a triple curve and the next nodes on the surface. - :param elementsCountAcross: number of elements as a list [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] + :param elementsCountAcross: number of elements as + a list [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] :param elementsCountRim: :param box_derivatives: It is a list of [deriv1,deriv2,deriv3]. It is used to set the derivative directions. default is [1, 3, 2] which means it makes -d1, d3 and d2 in direction of axis1, axis2 and axis3. To make @@ -701,23 +791,25 @@ def __init__(self, elementsCountAcross, elementsCountRim, box_derivatives=None): # elementsCountAcrossNonRim = self.elementsCountAcross - 2*elementsCountRim # self.elementsCountAroundFull = 2*self.elementsCountUpRegular + elementsCountAcrossNonRim self._boxDerivatives = box_derivatives + self._boxMapping = None self._element_needs_scale_factor = False self._xi_mapping = None self._xi_signs = None self._box_deriv_mapping = None self._box_deriv_signs = None - self.px = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.pd1 = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.pd2 = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.pd3 = [ [] for _ in range(elementsCountAcross[2] + 1) ] - self.nodeId = [ [] for _ in range(elementsCountAcross[2] + 1) ] + self.px = [[] for _ in range(elementsCountAcross[2] + 1)] + self.pd1 = [[] for _ in range(elementsCountAcross[2] + 1)] + self.pd2 = [[] for _ in range(elementsCountAcross[2] + 1)] + self.pd3 = [[] for _ in range(elementsCountAcross[2] + 1)] + self.nodeId = [[] for _ in range(elementsCountAcross[2] + 1)] for n3 in range(elementsCountAcross[2] + 1): for n2 in range(elementsCountAcross[0] + 1): - for p in [ self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3] ]: - p.append([ None ]*(elementsCountAcross[1] + 1)) + for p in [self.px[n3], self.pd1[n3], self.pd2[n3], self.pd3[n3], self.nodeId[n3]]: + p.append([None]*(elementsCountAcross[1] + 1)) - self.elementId = [ [[ None ]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] for e3 in range(elementsCountAcross[2]) ] + self.elementId = [[[None]*elementsCountAcross[1] for n2 in range(elementsCountAcross[0])] + for e3 in range(elementsCountAcross[2])] # node types CORNER_1 = 1 @@ -787,6 +879,7 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, rangeOfRe :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 ragne is generated. :return: next nodeIdentifier. """ nodeIdentifier = startNodeIdentifier @@ -814,7 +907,7 @@ def generateNodes(self, fieldmodule, coordinates, startNodeIdentifier, rangeOfRe node = nodes.createNode(nodeIdentifier, nodetemplate) self.nodeId[n3][n2][n1] = nodeIdentifier cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, self.px [n3][n2][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, self.px[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, self.pd1[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, self.pd2[n3][n2][n1]) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, self.pd3[n3][n2][n1]) @@ -828,7 +921,8 @@ def set_derivatives(self, box_derivatives): :param box_derivatives: List[d_axis1_negative, d_axis2, d_axis3]. Determines what derivatives should be for back, right and up directions in the box region. Their values are in [1,2,3] range which 1, 2, 3 means d1, d2 and d3 respectively. - The negative sign reverses the direction. e.g. [1, -3,2] means for the right direction use -d3. Default is [1,3, 2]. + The negative sign reverses the direction. e.g. [1, -3,2] means for the right direction use -d3. + Default is [1,3, 2]. :return: """ self._boxMapping = box_derivatives @@ -864,11 +958,12 @@ def is_interior_regular_nodes(self, n3, n2, n1): return n3 <= n3y and n2 >= 1 and n1 <= n1y - def set_derivatives_for_irregualr_nodes(self, octant_number): + def set_derivatives_for_irregular_nodes(self, octant_number): """ For irregular nodes such as corners that are common between octants, change local derivatives to be the same directions of the octant_PPP. This is because the remapping is done for octant_PPP only and for others we need - to make them similar, so similar remapping can be performed. Therefore, always same vectors is used for remapping. + to make them similar, so similar remapping can be performed. Therefore, always same vectors is used for + remapping. e.g. [1, 0, 0] generates curve 1 in octant1. For one octant d1 is [1,0,0] and for another octant -d2. :param octant_number: see get_element_type :return: Derivatives for irregular nodes. @@ -910,7 +1005,8 @@ def set_derivatives_for_irregualr_nodes(self, octant_number): triple12leftderivs = [-1, -2, 3] triple12rightderivs = [-1, -2, 3] - return corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs, triple12leftderivs, triple12rightderivs + return corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs, \ + triple12leftderivs, triple12rightderivs def get_box_mapping_for_other_octants(self, octant_number, octant1_box_derivatives=None): """ @@ -941,10 +1037,10 @@ def get_octant_signs(self, octant_number): if octant_number == 1: signs = [1, 1, 1] elif octant_number == 2: - #y<0 + # y<0 signs = [1, -1, 1] elif octant_number == 3: - #x<0, y<0 + # x<0, y<0 signs = [-1, -1, 1] elif octant_number == 4: # x<0 @@ -968,15 +1064,20 @@ def get_octant_signs(self, octant_number): def get_element_node_identifiers(self, octant_number, e3, e2, e1, e3zo, e1zo): """ - Find node identifiers for given element represented by its indexes (e3,e2,e1). It uses default order of nodes for - [1,3,2] default element axes and finds the mapping between octant default local node numbers and the sphere. + Find node identifiers for given element represented by its indexes (e3,e2,e1). It uses default order of nodes + for [1,3,2] default element axes and finds the mapping between octant default local node numbers and + the sphere. :param octant_number: :return: nids, node s for given element represented by its indexes (e3,e2,e1). """ - nids_default = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo), - self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo), - self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo), - self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo), self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo)] + nids_default = [self.getNodeId(octant_number, e3, e2, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3, e2+1, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2+1, e1, e3zo, e1zo), + self.getNodeId(octant_number, e3, e2, e1+1, e3zo, e1zo), + self.getNodeId(octant_number, e3, e2+1, e1+1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2, e1+1, e3zo, e1zo), + self.getNodeId(octant_number, e3+1, e2+1, e1+1, e3zo, e1zo)] # change the order of nodes according to the box derivatives. boxMappingOctant1 = self.get_box_mapping_for_other_octants(1, octant1_box_derivatives=self._boxDerivatives) @@ -987,12 +1088,14 @@ def get_element_node_identifiers(self, octant_number, e3, e2, e1, e3zo, e1zo): return nids - def generateElements(self, fieldmodule, coordinates, startElementIdentifier , rangeOfRequiredElements, meshGroups=[]): + def generateElements(self, fieldmodule, coordinates, startElementIdentifier, rangeOfRequiredElements, + 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: Zinc mesh groups to add elements to. :return: next elementIdentifier. """ @@ -1024,14 +1127,17 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra e3o, e2o, e1o = self.get_local_element_index(octant_number, e3, e2, e1) e3yo, e2bo, e1yo = e3zo - 1, 1, e1zo - 1 - eft1 = eft if element_type == self.ELEMENT_REGULAR else tricubichermite.createEftNoCrossDerivatives() + eft1 = eft if element_type == self.ELEMENT_REGULAR else\ + tricubichermite.createEftNoCrossDerivatives() nids = self.get_element_node_identifiers(octant_number, e3, e2, e1, e3zo, e1zo) - boxMapping = self.get_box_mapping_for_other_octants(octant_number, octant1_box_derivatives=self._boxDerivatives) + boxMapping = self.get_box_mapping_for_other_octants(octant_number, + octant1_box_derivatives=self._boxDerivatives) lnm = self.local_node_mapping(boxMapping) - corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs, triple12leftderivs,\ - triple12rightderivs = self.set_derivatives_for_irregualr_nodes(octant_number) + corner1derivs, corner2derivs, corner3derivs, boundary12leftderivs, boundary12rightderivs,\ + triple12leftderivs, triple12rightderivs =\ + self.set_derivatives_for_irregular_nodes(octant_number) if element_type == self.ELEMENT_REGULAR: pass @@ -1039,7 +1145,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_DOWN_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.QUADRUPLE0_DOWN_LEFT) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT, derivatives=triple12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT, + derivatives=triple12leftderivs) self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_LEFT) @@ -1048,14 +1155,16 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_13_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, + derivatives=corner1derivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_2_DOWN) self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, + derivatives=boundary12leftderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -1066,16 +1175,20 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, + derivatives=corner1derivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, + derivatives=boundary12leftderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, + derivatives=boundary12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, + derivatives=boundary12leftderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1], lnm[5]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -1085,7 +1198,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[7]], self.QUADRUPLE_RIGHT) if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT, derivatives=triple12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT, + derivatives=triple12rightderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) @@ -1094,14 +1208,16 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE0_23_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, + derivatives=corner2derivs) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.TRIPLE_CURVE0_1_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE_1_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, + derivatives=boundary12rightderivs) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) @@ -1111,15 +1227,18 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_1_DOWN) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, + derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, + derivatives=corner2derivs) else: self.remap_eft_node_value_label(eft1, [lnm[5]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.TRIPLE_CURVE0_1_DOWN) if e3yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.BOUNDARY_12_RIGHT, + derivatives=boundary12rightderivs) else: self.remap_eft_node_value_label(eft1, [lnm[5], lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.TRIPLE_CURVE_1_DOWN) @@ -1133,7 +1252,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_23_UP) if e1yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, + derivatives=corner3derivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) @@ -1153,7 +1273,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_23_UP) self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_1_UP) if e1yo == 0: - self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, + derivatives=corner3derivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_UP) else: self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) @@ -1180,7 +1301,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_UP) if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_13_UP) - self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, + derivatives=corner3derivs) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.TRIPLE_CURVE_2_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) @@ -1196,7 +1318,8 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra elif e2o == e2zo: if e1o == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_UP) - self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, derivatives=corner3derivs) + self.remap_eft_node_value_label(eft1, [lnm[4]], self.CORNER_3, + derivatives=corner3derivs) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_UP) self.remap_eft_node_value_label(eft1, [lnm[4]], self.BOUNDARY_23_UP) @@ -1207,13 +1330,15 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4]], self.BOUNDARY_13_UP) self.remap_eft_node_value_label(eft1, [lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) else: - self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4], lnm[7], lnm[8]], self.SURFACE_REGULAR_UP) + self.remap_eft_node_value_label(eft1, [lnm[3], lnm[4], lnm[7], lnm[8]], + self.SURFACE_REGULAR_UP) elif element_type == self.ELEMENT_QUADRUPLE_LEFT: self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_LEFT) self.remap_eft_node_value_label(eft1, [lnm[8]], self.TRIPLE_CURVE0_3_LEFT) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT, derivatives=triple12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_LEFT, + derivatives=triple12leftderivs) self.remap_eft_node_value_label(eft1, [lnm[6]], self.TRIPLE0_12_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_LEFT) @@ -1221,13 +1346,15 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra if e1yo == 0: self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, + derivatives=corner1derivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_13_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12leftderivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, + derivatives=boundary12leftderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -1236,20 +1363,23 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra self.remap_eft_node_value_label(eft1, [lnm[7]], self.TRIPLE_CURVE_3_RIGHT) if e3o == 0: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE0_12_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT, derivatives=triple12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_12_RIGHT, + derivatives=triple12rightderivs) else: self.remap_eft_node_value_label(eft1, [lnm[1]], self.TRIPLE_CURVE0_3_RIGHT) self.remap_eft_node_value_label(eft1, [lnm[5]], self.TRIPLE_CURVE_3_RIGHT) if e2bo == e2zo: self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, + derivatives=corner2derivs) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, + derivatives=boundary12rightderivs) else: self.remap_eft_node_value_label(eft1, [lnm[6]], self.SURFACE_REGULAR_DOWN_RIGHT) @@ -1257,13 +1387,17 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra if e3o == 0: if e2o == e2zo: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, derivatives=corner2derivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, + derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.CORNER_2, + derivatives=corner2derivs) self.remap_eft_node_value_label(eft1, [lnm[8]], self.BOUNDARY_23_DOWN) else: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) - self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_RIGHT, + derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[6]], self.BOUNDARY_12_RIGHT, + derivatives=boundary12rightderivs) self.remap_eft_node_value_label(eft1, [lnm[8]], self.SURFACE_REGULAR_DOWN_RIGHT) else: self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_RIGHT) @@ -1275,13 +1409,16 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra elif element_type == self.ELEMENT_DOWN_LEFT: if e3o == 0: - self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[5]], self.BOUNDARY_12_LEFT, + derivatives=boundary12rightderivs) self.remap_eft_node_value_label(eft1, [lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) if e1o == 0: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, derivatives=corner1derivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.CORNER_1, + derivatives=corner1derivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.BOUNDARY_13_DOWN) else: - self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, derivatives=boundary12rightderivs) + self.remap_eft_node_value_label(eft1, [lnm[1]], self.BOUNDARY_12_LEFT, + derivatives=boundary12rightderivs) self.remap_eft_node_value_label(eft1, [lnm[3]], self.SURFACE_REGULAR_DOWN_LEFT) else: self.remap_eft_node_value_label(eft1, [lnm[5], lnm[7]], self.SURFACE_REGULAR_DOWN_LEFT) @@ -1323,8 +1460,9 @@ def generateElements(self, fieldmodule, coordinates, startElementIdentifier , ra def local_node_mapping(self, boxMapping): """ Find local node mapping between default local node number of octant and global local node number of sphere. - Obtain xi mapping and box irregular derivatives mapping. they are used for elements in octant that locally might have - different xi directions from their global sphere xi directions. Then they are used in remap_eft_node_value_label. + Obtain xi mapping and box irregular derivatives mapping. they are used for elements in octant that locally + might have different xi directions from their global sphere xi directions. Then they are used in + remap_eft_node_value_label. :return: lnm, local node mapping between local node number of octant and local node number of sphere. """ boxMapping_default = [1, 3, 2] @@ -1342,7 +1480,8 @@ def local_node_mapping(self, boxMapping): xi_dm[abs(boxMapping[1])]: abs(boxMapping_default[1]), xi_dm[abs(boxMapping[2])]: abs(boxMapping_default[2])} signs = [1 if boxMapping[c]*boxMapping_default[c] > 0 else -1 for c in range(3)] - xi_sign_change = [signs[abs(boxMapping_default[0])-1], signs[abs(boxMapping_default[1])-1], signs[abs(boxMapping_default[2])-1]] + xi_sign_change = [signs[abs(boxMapping_default[0])-1], signs[abs(boxMapping_default[1])-1], + signs[abs(boxMapping_default[2])-1]] lnm = {} signs = [xi_sign_change[xi_global_to_default_map['xi1'] - 1], @@ -1363,12 +1502,14 @@ def local_node_mapping(self, boxMapping): lnm[ln] = xi_node_map[tuple(xi_l)] deriv_default_to_global_map = {xi_dm[abs(boxMapping_default[0])]: abs(boxMapping[0]), - xi_dm[abs(boxMapping_default[1])]: abs(boxMapping[1]), - xi_dm[abs(boxMapping_default[2])]: abs(boxMapping[2])} + xi_dm[abs(boxMapping_default[1])]: abs(boxMapping[1]), + xi_dm[abs(boxMapping_default[2])]: abs(boxMapping[2])} signs = [1 if boxMapping[c]*boxMapping_default[c] > 0 else -1 for c in range(3)] - deriv_sign_change = [signs[abs(boxMapping_default[0])-1], signs[abs(boxMapping_default[1])-1], signs[abs(boxMapping_default[2])-1]] + deriv_sign_change = [signs[abs(boxMapping_default[0])-1], signs[abs(boxMapping_default[1])-1], + signs[abs(boxMapping_default[2])-1]] - self._xi_mapping = {1: xi_default_to_global_map['xi1'], 2: xi_default_to_global_map['xi2'], 3: xi_default_to_global_map['xi3']} + self._xi_mapping = {1: xi_default_to_global_map['xi1'], 2: xi_default_to_global_map['xi2'], + 3: xi_default_to_global_map['xi3']} self._xi_signs = {1: xi_sign_change[0], 2: xi_sign_change[1], 3: xi_sign_change[2]} self._box_deriv_mapping = {1: deriv_default_to_global_map['xi1'], 2: deriv_default_to_global_map['xi2'], @@ -1452,17 +1593,21 @@ def get_local_element_index(self, octant_number, e3, e2, e1): elif octant_number == 2: e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, e1, self.elementsCountAcross[0] // 2 - 1 - e2 elif octant_number == 3: - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - 1 - e2, self.elementsCountAcross[1] // 2 - 1 - e1 + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - 1 - e2,\ + self.elementsCountAcross[1] // 2 - 1 - e1 elif octant_number == 4: - e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - 1 - e1, e2 - self.elementsCountAcross[0] // 2 + e3o, e2o, e1o = e3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - 1 - e1,\ + e2 - self.elementsCountAcross[0] // 2 elif octant_number == 5: - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[1] - 1 - e1, self.elementsCountAcross[0]//2 - 1 - e2 + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[1] - 1 - e1,\ + self.elementsCountAcross[0]//2 - 1 - e2 elif octant_number == 6: e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e2, self.elementsCountAcross[1] // 2 - 1 - e1 elif octant_number == 7: e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, e1, e2 - self.elementsCountAcross[0]//2 elif octant_number == 8: - e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[0] - 1 - e2, e1 - self.elementsCountAcross[1]//2 + e3o, e2o, e1o = self.elementsCountAcross[2]//2 - 1 - e3, self.elementsCountAcross[0] - 1 - e2,\ + e1 - self.elementsCountAcross[1]//2 return e3o, e2o, e1o @@ -1476,17 +1621,21 @@ def get_global_node_index(self, octant_number, n3o, n2o, n1o): elif octant_number == 2: n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 - n1o, n2o elif octant_number == 3: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1] // 2 - n1o + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] - n2o,\ + self.elementsCountAcross[1] // 2 - n1o elif octant_number == 4: - n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 + n1o, self.elementsCountAcross[1] - n2o + n3, n2, n1 = n3o + self.elementsCountAcross[2]//2, self.elementsCountAcross[0] // 2 + n1o,\ + self.elementsCountAcross[1] - n2o elif octant_number == 5: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0]//2 - n1o, self.elementsCountAcross[1] - n2o + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0]//2 - n1o,\ + self.elementsCountAcross[1] - n2o elif octant_number == 6: n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n2o, self.elementsCountAcross[1]//2 - n1o elif octant_number == 7: n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, n1o + self.elementsCountAcross[0]//2, n2o elif octant_number == 8: - n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0] - n2o, self.elementsCountAcross[1]//2 + n1o + n3, n2, n1 = self.elementsCountAcross[2] // 2 - n3o, self.elementsCountAcross[0] - n2o,\ + self.elementsCountAcross[1]//2 + n1o return n3, n2, n1 @@ -1500,24 +1649,28 @@ def get_octant_node_index(self, octant_number, n3, n2, n1): elif octant_number == 2: n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, n1, self.elementsCountAcross[0] // 2 - n2 elif octant_number == 3: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - n2, self.elementsCountAcross[1] // 2 - n1 + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[0] - n2,\ + self.elementsCountAcross[1] // 2 - n1 elif octant_number == 4: - n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - n1, n2 - self.elementsCountAcross[0]//2 + n3o, n2o, n1o = n3 - self.elementsCountAcross[2] // 2, self.elementsCountAcross[1] - n1,\ + n2 - self.elementsCountAcross[0]//2 elif octant_number == 5: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[1] - n1, self.elementsCountAcross[0]//2 - n2 + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[1] - n1,\ + self.elementsCountAcross[0]//2 - n2 elif octant_number == 6: n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n2, self.elementsCountAcross[1]//2 - n1 elif octant_number == 7: n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, n1, n2 - self.elementsCountAcross[0]//2 elif octant_number == 8: - n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[0] - n2, n1 - self.elementsCountAcross[1]//2 + n3o, n2o, n1o = self.elementsCountAcross[2] // 2 - n3, self.elementsCountAcross[0] - n2,\ + n1 - self.elementsCountAcross[1]//2 return n3o, n2o, n1o def getNodeId(self, octant_number, n3, n2, n1, n3yo, n1yo): """ - Get node identifier. Use node indexes n3, n2, n1 to find it. If the indexes represent removed nodes in the lattice, - find the right indexes first. + Get node identifier. Use node indexes n3, n2, n1 to find it. If the indexes represent removed nodes in the + lattice, find the right indexes first. :return: Node identifier. """ n1zo = n1yo + 1 @@ -1552,11 +1705,11 @@ def getNodeId(self, octant_number, n3, n2, n1, n3yo, n1yo): def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivatives=None): """ - Remaps derivatives for common types of nodes. It also checks if each node needs scale factors. If one of the nodes - of an element needs it, then flags it. It assumes the directions of derivatives in a certain way (based on - default [1, 3, 2] xi directions). - If directions are different, then we can use the 'derivatives' argument to fix this. This part is done for irregular nodes, - in the box and for other nodes, derivatives should be given. + Remaps derivatives for common types of nodes. It also checks if each node needs scale factors. If one of the + nodes of an element needs it, then flags it. It assumes the directions of derivatives in a certain way + (based on default [1, 3, 2] xi directions). + If directions are different, then we can use the 'derivatives' argument to fix this. This part is done for + irregular nodes, in the box and for other nodes, derivatives should be given. :param node_type: e.g. corner 1 represents an end node on the axis1. :param derivatives: derivatives to be changed to. :return: @@ -1585,25 +1738,34 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], + sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], + sf[1 * xis[3] * ds[1]])]) elif node_type == self.CORNER_2: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) elif node_type == self.CORNER_3: if any(c != 1 for c in [-1 * xis[3] * ds[1], -1 * xis[1] * ds[2], 1 * xis[2] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[2]], + sf[-1 * xis[1] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[3]], + sf[1 * xis[2] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], + sf[-1 * xis[3] * ds[1]])]) elif node_type == self.QUADRUPLE_DOWN_LEFT: if any(c != 1 for c in [-1 * xis[1], 1 * xis[2], 1 * xis[2], -1 * xis[3]]): @@ -1632,49 +1794,70 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS2, sf[-1 * xis[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) elif node_type == self.QUADRUPLE0_DOWN_LEFT: - if any(c != 1 for c in [1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[1] * ds[1], -1 * xis[1] * ds[2], -1 * xis[1] * ds[3]]): + if any(c != 1 for c in [1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[1] * ds[1], -1 * xis[1] * ds[2], + -1 * xis[1] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), + (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]]), + (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif node_type == self.QUADRUPLE0_RIGHT: - if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], -1 * xis[3] * ds[1], 1 * xis[3] * ds[2], 1 * xis[3] * ds[3]]): + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], -1 * xis[3] * ds[1], 1 * xis[3] * ds[2], + 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), + (expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), + (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.QUADRUPLE0_UP: - if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], -1 * xis[2] * ds[1], 1 * xis[2] * ds[2], 1 * xis[2] * ds[3]]): + if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], -1 * xis[2] * ds[1], 1 * xis[2] * ds[2], + 1 * xis[2] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), + (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), + (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif node_type == self.TRIPLE_12_LEFT: if any(c != 1 for c in [1 * xis[2] * ds[2], -1 * xis[1] * ds[3], 1 * xis[3] * ds[1]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], + sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], + sf[1 * xis[3] * ds[1]])]) elif node_type == self.TRIPLE_12_RIGHT: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE_13_DOWN: if any(c != 1 for c in [-1 * xis[1], 1 * xis[2], 1 * xis[3]]): if not self._element_needs_scale_factor: @@ -1689,10 +1872,12 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) + # temporary to enable swap remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swap + # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + # finish swap elif node_type == self.TRIPLE_23_DOWN: if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): if not self._element_needs_scale_factor: @@ -1714,72 +1899,96 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), + (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) elif node_type == self.TRIPLE0_12_RIGHT: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], -1 * xis[3] * ds[1], 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE0_13_DOWN: if any(c != 1 for c in [1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[1] * ds[1], -1 * xis[1] * ds[2]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], + sf[-1 * xis[1] * ds[2]])]) elif node_type == self.TRIPLE0_13_Up: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], -1 * xis[2] * ds[1], 1 * xis[2] * ds[2]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), + (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) elif node_type == self.TRIPLE0_23_DOWN: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[2], 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), + (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE0_23_UP: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], 1 * xis[2] * ds[2], 1 * xis[2] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), + (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) elif node_type == self.BOUNDARY_12_LEFT: if any(c != 1 for c in [1 * xis[2] * ds[2], -1 * xis[1] * ds[3], 1 * xis[3] * ds[1]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], sf[1 * xis[3] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[3]], + sf[-1 * xis[1] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[1]], + sf[1 * xis[3] * ds[1]])]) elif node_type == self.BOUNDARY_12_RIGHT: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) elif node_type == self.BOUNDARY_13_DOWN: if any(c != 1 for c in [-1 * xis[1], 1 * xis[2], 1 * xis[3]]): if not self._element_needs_scale_factor: @@ -1794,9 +2003,11 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[1]])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) # temporary to enable swap + # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D2_DS2DS3, [])]) + # temporary to enable swap # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, [])]) - # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) # finish swaps + # remapEftNodeValueLabel(eft, localNodeIndexes, Node.VALUE_LABEL_D2_DS2DS3, [(Node.VALUE_LABEL_D_DS2, [])]) + # finish swaps remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS3, sf[1 * xis[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif node_type == self.BOUNDARY_23_DOWN: @@ -1869,63 +2080,83 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[2] * ds[3]])]) + [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]]), (expressionLabel[dm[3]], + sf[1 * xis[2] * ds[3]])]) elif node_type == self.TRIPLE_CURVE0_1_DOWN: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], 1 * xis[3] * ds[2], 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + [(expressionLabel[dm[2]], sf[1 * xis[3] * ds[2]]), (expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) elif node_type == self.TRIPLE_CURVE0_2_DOWN: if any(c != 1 for c in [1 * xis[2] * ds[2], 1 * xis[3] * ds[3], 1 * xis[1] * ds[1], -1 * xis[1] * ds[2]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], sf[-1 * xis[1] * ds[2]])]) + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[2]], + sf[-1 * xis[1] * ds[2]])]) elif node_type == self.TRIPLE_CURVE0_2_UP: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[3] * ds[3], -1 * xis[2] * ds[1], 1 * xis[2] * ds[2]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], - [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + [(expressionLabel[dm[1]], sf[-1 * xis[2] * ds[1]]), (expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) elif node_type == self.TRIPLE_CURVE0_3_LEFT: if any(c != 1 for c in [1 * xis[2] * ds[2], 1 * xis[3] * ds[3], 1 * xis[1] * ds[1], -1 * xis[1] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], - [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], sf[-1 * xis[1] * ds[3]])]) + [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]]), (expressionLabel[dm[3]], + sf[-1 * xis[1] * ds[3]])]) elif node_type == self.TRIPLE_CURVE0_3_RIGHT: if any(c != 1 for c in [1 * xis[1] * ds[1], 1 * xis[2] * ds[2], -1 * xis[3] * ds[1], 1 * xis[3] * ds[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], sf[1 * xis[1] * ds[1]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], sf[1 * xis[2] * ds[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(expressionLabel[dm[1]], + sf[1 * xis[1] * ds[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(expressionLabel[dm[2]], + sf[1 * xis[2] * ds[2]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], - [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], sf[1 * xis[3] * ds[3]])]) + [(expressionLabel[dm[1]], sf[-1 * xis[3] * ds[1]]), (expressionLabel[dm[3]], + sf[1 * xis[3] * ds[3]])]) elif node_type == self.SURFACE_REGULAR_DOWN_LEFT: if any(c != 1 for c in [1 * xis[2], -1 * xis[1], 1 * xis[3]]): if not self._element_needs_scale_factor: self._element_needs_scale_factor = True setEftScaleFactorIds(eft, [1], []) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, sf[1 * xis[2]])]) - remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, sf[-1 * xis[1]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[2]], [(Node.VALUE_LABEL_D_DS2, + sf[1 * xis[2]])]) + remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[1]], [(Node.VALUE_LABEL_D_DS3, + sf[-1 * xis[1]])]) remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[3]], [(Node.VALUE_LABEL_D_DS1, sf[1 * xis[3]])]) elif node_type == self.SURFACE_REGULAR_DOWN_RIGHT: if any(c != 1 for c in [1 * xis[1], 1 * xis[2], 1 * xis[3]]): @@ -1956,4 +2187,3 @@ def remap_eft_node_value_label(self, eft, localNodeIndexes, node_type, derivativ # if default_sign[ci][di-1]: # expressionTerms.append((expressionLabel[dm[di]], sf[default_sign[ci][di-1] * xis[ci] * ds[di]])) # remapEftNodeValueLabel(eft, localNodeIndexes, label[xim[ci]], expressionTerms) - diff --git a/src/scaffoldmaker/utils/spheremesh.py b/src/scaffoldmaker/utils/spheremesh.py index 260db088..bd0d4125 100644 --- a/src/scaffoldmaker/utils/spheremesh.py +++ b/src/scaffoldmaker/utils/spheremesh.py @@ -3,14 +3,15 @@ """ from enum import Enum -from scaffoldmaker.utils import vector + import math -from opencmiss.zinc.field import Field + from opencmiss.utils.zinc.finiteelement import getMaximumNodeIdentifier, getMaximumElementIdentifier -from scaffoldmaker.utils.shieldmesh import ShieldMesh3D, ShieldShape3D -from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, interpolateSampleCubicHermite, \ - smoothCubicHermiteDerivativesLine, interpolateSampleLinear, interpolateCubicHermite +from opencmiss.zinc.field import Field +from scaffoldmaker.utils import vector +from scaffoldmaker.utils.interpolation import sampleCubicHermiteCurves, smoothCubicHermiteDerivativesLine from scaffoldmaker.utils.cylindermesh import Ellipse2D, EllipseShape +from scaffoldmaker.utils.shieldmesh import ShieldMesh3D class SphereShape(Enum): @@ -33,7 +34,8 @@ class SphereMesh: def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, rangeOfRequiredElements=None, boxDerivatives=None, useCrossDerivatives=False, meshGroups=[]): + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, rangeOfRequiredElements=None, + boxDerivatives=None, useCrossDerivatives=False, meshGroups=[]): """ :param fieldModule: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define. @@ -77,6 +79,7 @@ def __init__(self, fieldModule, coordinates, centre, axes, elementsCountAcross, self._boxDerivatives = boxDerivatives if boxDerivatives else [1, 3, 2] self._meshGroups = meshGroups + self._shield3D = None for i in range(3): elementsAxis = elementsCountAcross[i] - elementsCountAcrossShell * (1 - shellProportion) @@ -112,17 +115,11 @@ def createSphereMesh3d(self, fieldModule, coordinates): assert (self._sphereShape in [SphereShape.SPHERE_SHAPE_FULL, SphereShape.SPHERE_SHAPE_HALF_AAP, - SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), 'createSphereMesh3d: Invalid sphere mode.' + SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP]), \ + 'createSphereMesh3d: Invalid sphere mode.' elementsCountRim = self._elementsCountAcrossRim - if self._sphereShape == SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP: - shieldMode = ShieldShape3D.SHIELD_SHAPE_OCTANT_PPP - elif self._sphereShape == SphereShape.SPHERE_SHAPE_HALF_AAP: - shieldMode = ShieldShape3D.SHIELD_SHAPE_HALF_AAP - elif self._sphereShape == SphereShape.SPHERE_SHAPE_FULL: - shieldMode = ShieldShape3D.SHIELD_SHAPE_FULL - self._shield3D = ShieldMesh3D(self._elementsCount, elementsCountRim, box_derivatives=self._boxDerivatives) nodes = fieldModule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) @@ -148,8 +145,9 @@ def createSphereMesh3d(self, fieldModule, coordinates): for octantType in OctantVariationsType: axes, elementsCountAcross, boxDerivatives = self.get_octant_axes_and_elements_count(octantType) octant = OctantMesh(self._centre, axes, elementsCountAcross, - elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, - sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxDerivatives=boxDerivatives) + elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, + sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, + useCrossDerivatives=False, boxDerivatives=boxDerivatives) self.copy_octant_nodes_to_sphere_shield(octant, octantType) self.modify_octant_common_nodes() @@ -292,14 +290,15 @@ def copy_octant_nodes_to_sphere_shield(self, octant, octant_shape): else: raise ValueError("Not implemented.") + shield3D = octant.get_shield() for n3 in range(n3a, n3z + 1): for n2 in range(n2a, n2z + 1): for n1 in range(n1a, n1z + 1): n3o, n2o, n1o = self._shield3D.get_octant_node_index(octant_number, n3, n2, n1) - self._shield3D.px[n3][n2][n1] = octant._shield3D.px[n3o][n2o][n1o] - self._shield3D.pd1[n3][n2][n1] = octant._shield3D.pd1[n3o][n2o][n1o] - self._shield3D.pd2[n3][n2][n1] = octant._shield3D.pd2[n3o][n2o][n1o] - self._shield3D.pd3[n3][n2][n1] = octant._shield3D.pd3[n3o][n2o][n1o] + self._shield3D.px[n3][n2][n1] = shield3D.px[n3o][n2o][n1o] + self._shield3D.pd1[n3][n2][n1] = shield3D.pd1[n3o][n2o][n1o] + self._shield3D.pd2[n3][n2][n1] = shield3D.pd2[n3o][n2o][n1o] + self._shield3D.pd3[n3][n2][n1] = shield3D.pd3[n3o][n2o][n1o] def modify_octant_common_nodes(self): """ @@ -358,7 +357,8 @@ def generateNodes(self, nodes, fieldModule, coordinates): """ nodeIdentifier = max(1, getMaximumNodeIdentifier(nodes) + 1) self._startNodeIdentifier = nodeIdentifier - nodeIdentifier = self._shield3D.generateNodes(fieldModule, coordinates, nodeIdentifier, self._rangeOfRequiredElements) + nodeIdentifier = self._shield3D.generateNodes(fieldModule, coordinates, nodeIdentifier, + self._rangeOfRequiredElements) self._endNodeIdentifier = nodeIdentifier def generateElements(self, mesh, fieldModule, coordinates): @@ -370,7 +370,8 @@ def generateElements(self, mesh, fieldModule, coordinates): """ elementIdentifier = max(1, getMaximumElementIdentifier(mesh) + 1) self._startElementIdentifier = elementIdentifier - elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, self._rangeOfRequiredElements, self._meshGroups) + elementIdentifier = self._shield3D.generateElements(fieldModule, coordinates, elementIdentifier, + self._rangeOfRequiredElements, self._meshGroups) self._endElementIdentifier = elementIdentifier @@ -383,17 +384,15 @@ def __init__(self, centre, axes, elementsCountAcross, elementsCountAcrossShell, elementsCountAcrossTransition, shellProportion, sphereShape=SphereShape.SPHERESHIELD_SHAPE_OCTANT_PPP, useCrossDerivatives=False, boxDerivatives=None): """ - :param fieldModule: Zinc fieldModule to create elements in. - :param coordinates: Coordinate field to define. :param centre, axes: centre and axes of the octant. - :param elementsCountAcross: [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] Total number of elements - across the octant axes. + :param elementsCountAcross: [elementsCountAcrossAxis1, elementsCountAcrossAxis2, elementsCountAcrossAxis3] Total + number of elements across the octant axes. :param elementsCountAcrossShell, elementsCountAcrossTransition: Total number of elements across each axis consists of regular elements in the middle cube, transition elements from cube to a sphere (core boundary) and shell elements around it. Shell nodes and derivatives are similar to the core boundary and don't need remapping. The topology of the shield structure is extended to 3D with a quadruple points. - :param sphereShape: A value from enum SphereShape specifying one of the 8 octant regions. Octant_PPP for example, - is the octant in positive axis1, positive axis2 and positive axis3. + :param sphereShape: A value from enum SphereShape specifying one of the 8 octant regions. Octant_PPP for + example, is the octant in positive axis1, positive axis2 and positive axis3. """ self._axes = axes self._radius = [vector.magnitude(axis) for axis in axes] @@ -412,6 +411,7 @@ def __init__(self, centre, axes, elementsCountAcross, self._centre = centre self._boxDerivatives = boxDerivatives if boxDerivatives else [1, 3, 2] + self._shield3D = None for i in range(3): elementsAxis = elementsCountAcross[i] - elementsCountAcrossShell * (1 - shellProportion) @@ -469,9 +469,9 @@ def create_boundary_ellipses_nodes(self): coreMajorRadius = coreRadius[i][0] coreMinorRadius = coreRadius[i][1] ellipse = Ellipse2D(centre, majorAxis, minorAxis, - elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, - elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, - ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) + elementsCountAcrossMajor, elementsCountAcrossMinor, elementsCountAcrossShell, + elementsCountAcrossTransition, shellProportion, coreMajorRadius, coreMinorRadius, + ellipseShape=EllipseShape.Ellipse_SHAPE_FULL) self.copy_ellipses_nodes_to_shield_nodes(ellipse, i+1, squareDerivatives[i], circleDerivatives[i]) @@ -577,7 +577,8 @@ def calculate_surface_quadruple_point(self): phi_3 = calculate_azimuth(theta_3, theta_2) # ratio = -0.1 * (min(self._elementsCount) - 2) + 1 if self._elementsCount[0] <= 2 else 0.2 ratio = 1 - # local_x = intersection_of_two_great_circles_on_sphere(btx[0][0][n1y-1], btx[n3z][n2z][n1z], btx[0][2][n1z], btx[n3z][0][0]) + # local_x = intersection_of_two_great_circles_on_sphere(btx[0][0][n1y-1], + # btx[n3z][n2z][n1z], btx[0][2][n1z], btx[n3z][0][0]) local_x = spherical_to_cartesian(1.0, theta_3, ratio * phi_3 + (1-ratio)*math.pi/2) x = local_to_global_coordinates(local_x, self._axes, self._centre) @@ -597,18 +598,18 @@ def sample_triple_curves_on_sphere(self): # sample on curve 1 of the triple curves and smooth the end derivatives. n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, index_output=True) n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, cx=1, index_output=True) - self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[0] - 1, - [1, None], [1], [1]) + self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], + self._elementsCount[0] - 1, [1, None], [1], [1]) # curve 2 n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, cx=2, index_output=True) n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, index_output=True) - self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[1] - 1, - [1], [-2], [None, -2]) + self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], + self._elementsCount[1] - 1, [1], [-2], [None, -2]) # curve 3. n3r1, n2r1, n1r1 = self.get_triple_curves_end_node_parameters(1, cx=3, index_output=True) n3r2, n2r2, n1r2 = self.get_triple_curves_end_node_parameters(1, index_output=True) - self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], self._elementsCount[2] - 1, - [2], [2], [None, None]) + self.sample_curves_between_two_nodes_on_sphere([n3r1, n2r1, n1r1], [n3r2, n2r2, n1r2], + self._elementsCount[2] - 1, [2], [2], [None, None]) def sample_regular_curves_on_sphere(self): """ @@ -686,7 +687,8 @@ def smooth_derivatives_to_surface(self): td3 = [] tx.append(btx[n3r][n2r][n1r]) td3.append( - [(co[0]*btd1[n3r][n2r][n1r][c] + co[1]*btd2[n3r][n2r][n1r][c] + co[2]*btd3[n3r][n2r][n1r][c]) for c in range(3)]) + [(co[0]*btd1[n3r][n2r][n1r][c] + co[1]*btd2[n3r][n2r][n1r][c] + + co[2]*btd3[n3r][n2r][n1r][c]) for c in range(3)]) tx.append(btx[n3][n2][n1]) td3.append(btd3[n3][n2][n1]) @@ -699,7 +701,8 @@ def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStar Samples curves on the sphere surface between two points given by their indexes. :param id1, id2: [n3,n2,n1] for the first and second points. :param dStart, dBetween, dEnd: Specifies the derivatives that are used for this curve at the beginning, end and - in between. e.g. dStart=[2, -1, None] means d2 for the first node, -d1 for the second node and skip the third one. + in between. e.g. dStart=[2, -1, None] means d2 for the first node, -d1 for the second node and skip the third + one. :return: """ btx = self._shield3D.px @@ -724,7 +727,8 @@ def sample_curves_between_two_nodes_on_sphere(self, id1, id2, elementsOut, dStar btd = {1: btd1, 2: btd2, 3: btd3} idi = {0: id1[0], 1: id1[1], 2: id1[2]} - nx, nd1 = sample_curves_on_sphere(btx[id1[0]][id1[1]][id1[2]], btx[id2[0]][id2[1]][id2[2]], self._centre, elementsOut) + nx, nd1 = sample_curves_on_sphere(btx[id1[0]][id1[1]][id1[2]], btx[id2[0]][id2[1]][id2[2]], self._centre, + elementsOut) nit = 0 for ni in range(elementsCount + 1): @@ -1019,7 +1023,8 @@ def smooth_regular_interior_curves(self): def get_triple_curves_end_node_parameters(self, rx, cx=None, index_output=False): """ - Find the indexes or node parameters for the 6 end nodes of unique curves of triple curves on the surface and inside. + Find the indexes or node parameters for the 6 end nodes of unique curves of triple curves on the surface and + inside. if cx is not given, it returns the quadruple points identified by rx. :param cx: curve index. Curve 1 connects quadruples to ellipse 23. Similarly, curve 2, connects quadruples to ellipse 13 @@ -1075,12 +1080,16 @@ def on_sphere(self, n3, n2, n1): return (n3 == n3z or n2 == 0 or n1 == n1z) and btx[n3][n2][n1] + def get_shield(self): + return self._shield3D + def calculate_azimuth(theta, theta_p): """ Given polar angles of a point on the sphere surfaces, calculate the azimuth angle. :param theta: polar angle. In orthonormal coordinate system (axis1, axis2, axis3) with right-hand rule, - theta is angle between common axis and point projection on plane of theta. In case theta=theta_3 and theta_p = theta_1, theta is between axis2 and projection + theta is angle between common axis and point projection on plane of theta. In case theta=theta_3 and + theta_p = theta_1, theta is between axis2 and projection :param theta_p: polar angle wrt other direction. :return: Azimuth angle. """ @@ -1168,8 +1177,10 @@ def local_to_global_coordinates(local_x, local_axes, local_origin=None): """ Get global coordinates of a point with local coordinates x = [x1, x2, x3] and axes of local coordinate system. :param local_x: Coordinates in local coordinates system as a list of 3 components. - :param local_origin: Origin of local coordinates system specified as a list of 3 components wrt global coordinates system. - :param local_axes: Axes of local coordinates system, specified as a list of list 3X3 with respect to global coordinates system. + :param local_origin: Origin of local coordinates system specified as a list of 3 components wrt global coordinates + system. + :param local_axes: Axes of local coordinates system, specified as a list of list 3X3 with respect to global + coordinates system. :return: Global coordinate system. """ if local_origin is None: diff --git a/tests/test_sphere.py b/tests/test_sphere.py index 0fc06f76..7609026f 100644 --- a/tests/test_sphere.py +++ b/tests/test_sphere.py @@ -1,14 +1,13 @@ import unittest -import copy -from opencmiss.utils.zinc.finiteelement import evaluateFieldNodesetRange -from opencmiss.utils.zinc.general import ChangeManager +from testutils import assertAlmostEqualList + from opencmiss.zinc.context import Context from opencmiss.zinc.field import Field +from opencmiss.utils.zinc.finiteelement import evaluateFieldNodesetRange +from opencmiss.utils.zinc.general import ChangeManager from opencmiss.zinc.result import RESULT_OK +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, getAnnotationGroupForTerm from scaffoldmaker.meshtypes.meshtype_3d_solidsphere2 import MeshType_3d_solidsphere2 -from testutils import assertAlmostEqualList -from scaffoldmaker.annotation.annotationgroup import AnnotationGroup -from scaffoldmaker.annotation.annotationgroup import getAnnotationGroupForTerm from scaffoldmaker.utils.meshrefinement import MeshRefinement @@ -133,7 +132,6 @@ def test_sphere1(self): self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 4.132033912594377, delta=3.0E-1) - # check ellipsoid. scaffold1 = MeshType_3d_solidsphere2 parameterSetNames = scaffold1.getParameterSetNames() @@ -194,5 +192,6 @@ def test_sphere1(self): self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(volume, 1.6741674010981926, delta=1.0E-3) + if __name__ == "__main__": unittest.main()