Location: Stomach Annotator for SPARC @ 9ea33dda840d / digitiser / mapping.py

Author:
rjag008 <rjag008@auckland.ac.nz>
Date:
2018-08-18 17:01:42+12:00
Desc:
Final Release
Permanent Source URI:
https://models.physiomeproject.org/workspace/51d/rawfile/9ea33dda840d259caf68e26d21300bece4eeff3f/digitiser/mapping.py

'''
Created on 12/06/2018

@author: rjag008
'''
import pickle
import numpy as np
from scipy.interpolate import splprep, splev
from opencmiss.zinc.context import Context
from collections import OrderedDict
from opencmiss.zinc.node import Node
from opencmiss.zinc.element import Element, Elementbasis


def pointOnLine(points, line, rtol=1.0e-5, atol=1.0e-8):
    """Determine if a point is on a line segment
    Input
        points: Coordinates of either
                * one point given by sequence [x, y]
                * multiple points given by list of points or Nx2 array
        line: Endpoint coordinates [[x0, y0], [x1, y1]] or
              the equivalent 2x2 numeric array with each row corresponding
              to a point.
        rtol: Relative error for how close a point must be to be accepted
        atol: Absolute error for how close a point must be to be accepted
    Output
        True or False
    Notes
    Line can be degenerate and function still works to discern coinciding
    points from non-coinciding.
    Tolerances rtol and atol are used with numpy.allclose()
    """

    if len(points.shape) == 1:
        # One point only - make into 1 x 2 array
        points = points[np.newaxis, :]
        one_point = True
    else:
        one_point = False

    msg = 'Argument points must be either [x, y] or an Nx[>2] array of points'
    if len(points.shape) != 2:
        raise Exception(msg)
    if not points.shape[0] > 0:
        raise Exception(msg)
    if points.shape[1] < 2:
        raise Exception(msg)

    N = points.shape[0]  # Number of points

    x = points[:, 0]
    y = points[:, 1]
    x0, y0 = line[0]
    x1, y1 = line[1]

    # Vector from beginning of line to point
    a0 = x - x0
    a1 = y - y0

    # It's normal vector
    a_normal0 = a1
    a_normal1 = -a0

    # Vector parallel to line
    b0 = x1 - x0
    b1 = y1 - y0

    # Dot product
    nominator = abs(a_normal0 * b0 + a_normal1 * b1)
    denominator = b0 * b0 + b1 * b1

    # Determine if point vector is parallel to line up to a tolerance
    is_parallel = np.zeros(N, dtype=np.bool)  # All False
    is_parallel[nominator <= atol + rtol * denominator] = True

    # Determine for points parallel to line if they are within end points
    a0p = a0[is_parallel]
    a1p = a1[is_parallel]

    len_a = np.sqrt(a0p * a0p + a1p * a1p)
    len_b = np.sqrt(b0 * b0 + b1 * b1)
    cross = a0p * b0 + a1p * b1

    # Initialise result to all False
    result = np.zeros(N, dtype=np.bool)

    # Result is True only if a0 * b0 + a1 * b1 >= 0 and len_a <= len_b
    result[is_parallel] = (cross >= 0) * (len_a <= len_b)

    # Return either boolean scalar or boolean vector
    if one_point:
        return result[0]
    else:
        return result


class MeshMapper(object):
    '''
    Map material coordinates to anatomical coordinates to region type
    and vice versa
    '''

    def __init__(self,discret=50,boundaryDiscret=50):
        '''
        Constructor
        '''
        self.discret = discret
        self.boundaryDiscret = boundaryDiscret
        self.colors = [[147,231,255],[168,209,141],[162,198,255],[255,0,0],[255,218,104],[255,255,255]]
    
    def setupByFile(self,soureMeshFile,circumferentialElements=8,axialElements=11):
        self.context = Context('MeshMapper')
        region = self.context.getDefaultRegion()
        region.readFile(soureMeshFile)
        self.region = region
        with open(soureMeshFile,'r') as mesh:
            self.mesh = mesh.read()
        self.generateMaps(circumferentialElements,axialElements)
    
    def setupByRegion(self,source,circumferentialElements=8,axialElements=11):            
        self.region = source
        #As of 13 June 2018, no python api for writing to memory from zinc region
        import tempfile,os
        ofile = tempfile.NamedTemporaryFile(delete=False)
        self.region.writeFile(ofile.name)
        with open(ofile.name,'r') as mesh:
            self.mesh = mesh.read()
        os.remove(ofile.name)
        self.generateMaps(circumferentialElements,axialElements)
    
    
    def setupByPickle(self,source):
        self.context = Context('MeshMapper')
        region = self.context.getDefaultRegion()
        self.region = region
        with open(source,'rb') as ser:
            discret,boundaryDiscret,lb,rb,ladder,surfaceCoordinates,anatomicalCoordinates,regionMappings,mesh=pickle.load(ser)
            self.discret = discret
            self.boundaryDiscret = boundaryDiscret
            self.leftWallCoordinates = lb
            self.rightWallCoordinates = rb
            self.ladderCoordinates = ladder
            self.surfaceCoordinates = surfaceCoordinates
            self.anatomicalCoordinates = anatomicalCoordinates
            self.regionMappings = regionMappings
            sir  = region.createStreaminformationRegion()
            sir.createStreamresourceMemoryBuffer(str(mesh)) 
            region.read(sir)
            self.mesh = mesh
        
    def pointsInPolygon(self,surfaceCoordinates,polygon,closed=True):
        '''
        Based on https://github.com/inasafe/python-safe/blob/master/safe/engine/polygon.py
        '''
        # Suppress numpy warnings (as we'll be dividing by zero)
        original_numpy_settings = np.seterr(invalid='ignore', divide='ignore')
        rtol = 0.0
        atol = 0.0
        scShape = surfaceCoordinates.shape
        points = surfaceCoordinates.reshape((-1,scShape[-1]))
        # Get polygon extents to quickly rule out points that
        # are outside its bounding box
        maxpx,maxpy = np.max(polygon,axis=0)
        minpx,minpy = np.min(polygon,axis=0)
    
        M = points.shape[0]
        N = polygon.shape[0]
    
        x = points[:, 0]
        y = points[:, 1]
       
        # Vector keeping track of which points are inside
        inside = np.zeros(M, dtype=np.int)  # All assumed outside initially
    
        # Mask for points can be considered for inclusion
        candidates = np.ones(M, dtype=np.bool)  # All True initially
    
        # Only work on those that are inside polygon bounding box
        outsideBox = (x > maxpx) + (x < minpx) + (y > maxpy) + (y < minpy)
        insideBox = np.logical_not(outsideBox)
        candidates *= insideBox
    
        # Don't continue if all points are outside bounding box
        if not np.sometrue(candidates):
            return inside>0
    
        # Restrict computations to candidates only
        ix = np.where(candidates==True)[0]
        inCandidates = candidates[ix]
        cPoints      = points[ix]
        cInside      = inside[ix]
        cy           = y[ix]
        cx           = x[ix]
        # Find points on polygon boundary
        if closed:
            for i in range(N):
                # Loop through polygon edges
                j = (i + 1) % N
                edge = [polygon[i, :], polygon[j, :]]
        
                # Select those that are on the boundary
                boundaryPoints = pointOnLine(cPoints, edge, rtol, atol)
                cInside[boundaryPoints] = True
        
                # Remove boundary point from further analysis
                inCandidates[boundaryPoints] = False
        else:
            for i in range(N):
                # Loop through polygon edges
                j = (i + 1) % N
                edge = [polygon[i, :], polygon[j, :]]
        
                # Select those that are on the boundary
                boundaryPoints = pointOnLine(cPoints, edge, rtol, atol)
                cInside[boundaryPoints] = False
        
                # Remove boundary point from further analysis
                inCandidates[boundaryPoints] = False
            
        # Algorithm for finding points inside polygon
        for i in range(N):
            # Loop through polygon edges
            j = (i + 1) % N
            px_i, py_i = polygon[i, :]
            px_j, py_j = polygon[j, :]
    
            # Intersection formula
            sigma = (cy - py_i) / (py_j - py_i) * (px_j - px_i)
            seg_i = (py_i < cy) * (py_j >= cy)
            seg_j = (py_j < cy) * (py_i >= cy)
            mask = (px_i + sigma < cx) * (seg_i + seg_j) * inCandidates
    
            cInside[mask] = 1 - cInside[mask]
    
        # Restore numpy warnings
        np.seterr(**original_numpy_settings)
        inside[ix] = cInside
        if len(scShape)==3:
            return inside.reshape((scShape[0],scShape[1]))>0
        return inside>0
    
    def generateMaps(self,circumferentialElements,axialElements):
        fieldModule = self.region.getFieldmodule()
        coordinatesField = fieldModule.findFieldByName('coordinates')
        
        #Get the ladder coordinates
        nodeset = fieldModule.findNodesetByFieldDomainType(coordinatesField.DOMAIN_TYPE_NODES)
        nodeIterator = nodeset.createNodeiterator ()
        nodes = dict()
        node = nodeIterator.next()
        while node.isValid():
            nodes[int(node.getIdentifier())-1] = node
            node = nodeIterator.next()
        fieldCache = fieldModule.createFieldcache()
        coordinates = np.zeros((len(nodes),3))
        for nd,node in nodes.items():
            fieldCache.setNode(node)
            _,coord = coordinatesField.evaluateReal(fieldCache,3)
            coordinates[nd-1] = coord
        
        ladderCoordinates = np.zeros((axialElements+1,6))
        #Fit splines through each axial ring and determine the coordinates for which z = 0
        cds = np.zeros((circumferentialElements,3))
        for a in range(axialElements+1):
            axoff = a*circumferentialElements
            #Find the coordinates of a cross-section nodes number go from start-start+numCircumferentialNodes
            for nd in range(circumferentialElements):
                nid = nd + axoff
                cds[nd] = coordinates[nid]
            #Spline interpolate
            tck, u = splprep(cds.T, u=None, s=0.0, per=1)
            #Get the midpoint
            xs, ys, zs = splev([0.5], tck, der=0)
            ladderCoordinates[a,:3]=cds[0]
            ladderCoordinates[a,3:]=[xs[0],ys[0],zs[0]]      
    
        #Compute the mesh walls using ladder Coordinates
        #Interpolate of left
        tck, u = splprep(ladderCoordinates[:,:2].T, u=None, s=0.0)
        u_new = np.linspace(u.min(), u.max(), self.boundaryDiscret)
        xs, ys = splev(u_new, tck, der=0)
        self.leftWallCoordinates = np.c_[xs,ys]
        #Interpolate of right
        tck, u = splprep(ladderCoordinates[:,3:5].T, u=None, s=0.0)
        u_new = np.linspace(u.min(), u.max(), self.boundaryDiscret)[::-1]
        xs, ys = splev(u_new, tck, der=0)
        self.rightWallCoordinates = np.c_[xs,ys]
        self.ladderCoordinates = ladderCoordinates
        
        mesh = fieldModule.findMeshByDimension(3)
        ei   = mesh.createElementiterator()
        elemDict = dict()
        elem = ei.next()
        while elem.isValid():
            elemDict[int(elem.getIdentifier())] = elem
            elem = ei.next()
        threeDMesh = True
        if len(elemDict)==0: #Surface meshes
            threeDMesh = False
            mesh = fieldModule.findMeshByDimension(2)
            ei   = mesh.createElementiterator()
            elemDict = dict()
            elem = ei.next()
            while elem.isValid():
                elemDict[int(elem.getIdentifier())] = elem
                elem = ei.next()

            
        fieldCache = fieldModule.createFieldcache()    
#       following method uses the mesh, but this causes issues with ladder intersection continuity
#         x2 = np.linspace(0.00001, 1.0-0.00001, self.boundaryDiscret)
#         x1 = x2*0.0
#         xmid = x1+0.5
#         lbcoordXI = np.c_[x1,x2]
#         rbcoordXI = np.c_[xmid,x2]
#         
#         for i,coordXI in enumerate([lbcoordXI,rbcoordXI]):
#             coords = [] 
#             for val in coordXI:
#                 xpos = int(val[0]*circumferentialElements)
#                 xi1  = val[0]*circumferentialElements - xpos    
#                 ypos = int(val[1]*axialElements)
#                 xi2  = val[1]*axialElements - ypos
#                 eid = xpos + ypos*circumferentialElements + 1
#                 fieldCache.setMeshLocation(elemDict[eid],[xi1,xi2,0.0])
#                 _,v = coordinatesField.evaluateReal(fieldCache,3)
#                 coords.append(v)
#             if i==0:
#                 lbcoords = coords
#             else:
#                 rbcoords = coords
#         
#         self.leftWallCoordinates = np.np.array(lbcoords)
#         self.rightWallCoordinates = np.np.array(rbcoords)
#         self.ladderCoordinates = ladderCoordinates
        
        x2 = np.linspace(0.00001, 1.0-0.00001, self.discret)
        surfaceCoordinates = np.zeros((self.discret,self.discret,3))
        xi1,xi2 = np.meshgrid(x2,x2)
        if threeDMesh:
            x = [0.0,0.0,0.0]
        else:
            x = [0.0,0.0]
        
        for i in range(self.discret):
            for j in range(self.discret):
                xpos = int(xi1[i,j]*circumferentialElements)
                xi1s  = xi1[i,j]*circumferentialElements - xpos    
                ypos = int(xi2[i,j]*axialElements)
                xi2s  = xi2[i,j]*axialElements - ypos
                eid = xpos + ypos*circumferentialElements + 1                
                x[0] = xi1s
                x[1] = xi2s                
                fieldCache.setMeshLocation(elemDict[eid],x)
                _,v = coordinatesField.evaluateReal(fieldCache,3)
                surfaceCoordinates[i,j] = v
        anatomicalCoordinates = np.zeros((self.discret,self.discret,2))
        #Columns - x
        for j in range(1,self.discret):        
            anatomicalCoordinates[:,j,0] = anatomicalCoordinates[:,j-1,0] + np.linalg.norm(surfaceCoordinates[:,j-1]-surfaceCoordinates[:,j],axis=1)
        #Rows - y
        for j in range(1,self.discret):        
            anatomicalCoordinates[j,:,1] = anatomicalCoordinates[j-1,:,1] + np.linalg.norm(surfaceCoordinates[j-1,:]-surfaceCoordinates[j,:],axis=1)
        xmax = anatomicalCoordinates[:,:,0].max()
        ymax = anatomicalCoordinates[:,:,1].max()
        #Scaling
        anatomicalCoordinates[:,:,0] = anatomicalCoordinates[:,:,0]/xmax
        anatomicalCoordinates[:,:,1] = anatomicalCoordinates[:,:,1]/ymax
        '''
        #Centering
        for j in range(self.discret):
            xm = anatomicalCoordinates[j,-1,0]/2.0
            anatomicalCoordinates[j,:,0] = anatomicalCoordinates[j,:,0] - xm + 0.5
        for j in range(self.discret):
            ym = anatomicalCoordinates[-1,j,1]/2.0
            anatomicalCoordinates[:,j,1] = anatomicalCoordinates[:,j,1] - ym + 0.5
        '''     
        self.surfaceCoordinates = surfaceCoordinates
        self.anatomicalCoordinates = anatomicalCoordinates
    

    def generateSegmentLengthsAndWeights(self,circumferentialElements,axialElements):
        #Generate node to element xi mapping
        numberOfCircumfrentialNodes = circumferentialElements
        # create node element map
        ev = 0
        nodes = dict()
        #Compute the material coordinates of nodes
        for lengthElementIdx in range(1,axialElements+1):
            for circumfrentialElementIdx in range(1,circumferentialElements+1):
                #Element coord with respect to elements along each dim
                
                localNode1 = circumfrentialElementIdx + (lengthElementIdx - 1)*circumferentialElements 
                if circumfrentialElementIdx == circumferentialElements:
                    localNode2 = 1 + (lengthElementIdx-1)*numberOfCircumfrentialNodes                           
                else: 
                    localNode2 = localNode1 + 1
                    
                localNode3 = localNode1 + numberOfCircumfrentialNodes
                localNode4 = localNode2 + numberOfCircumfrentialNodes

                l1xi = [0.0,0.0]
                l2xi = [1.0,0.0]
                l3xi = [0.0,1.0]
                l4xi = [1.0,1.0]
                
                ev +=1
                nds = [localNode1,localNode2,localNode3,localNode4]
                xis = [l1xi,l2xi,l3xi,l4xi]
                for i,nd in enumerate(nds):
                    if nd in nodes:
                        if xis[i] == [0.0,0.0]:
                            nodes[nd] = [ev,xis[i]]
                        if  nodes[nd][1] != [0.0,0.0] and xis[i]==[0.0,1.0]:
                            nodes[nd] = [ev,xis[i]]
                    else:
                        nodes[nd] = [ev,xis[i]]
        def arcLength(x):
            npts = x.shape[0]
            arc = 0.0
            for k in range(1, npts):
                arc = arc + np.linalg.norm(x[k]-x[k-1])
            return arc 

        segmentLengths = np.zeros((len(nodes),2))
        ndis = 20
        xdiscret = np.linspace(0.0,1.0,ndis)
        fieldModule = self.region.getFieldmodule()
        coordinatesField = fieldModule.findFieldByName('coordinates')
        mesh = fieldModule.findMeshByDimension(3)
        ei   = mesh.createElementiterator()
        elemDict = dict()
        elem = ei.next()
        while elem.isValid():
            elemDict[int(elem.getIdentifier())] = elem
            elem = ei.next()
            
        fieldCache = fieldModule.createFieldcache()  
        coords = np.zeros((ndis,3))
        for nd, xi in nodes.items():
            ev = xi[0]
            xiv = xi[1]
            elem = elemDict[ev]
            if xiv[0] == 0.0:
                if xiv[1] == 0.0: #bottom left node
                    #Get the x1 length
                    for i in range(ndis):
                        fieldCache.setMeshLocation(elem,[xdiscret[i],0.0,0.0])
                        _,v = coordinatesField.evaluateReal(fieldCache,3)
                        coords[i] = v
                    segmentLengths[nd-1,0] = arcLength(coords)
                    #Get the x2 length
                    for i in range(ndis):
                        fieldCache.setMeshLocation(elem,[0.0,xdiscret[i],0.0])
                        _,v = coordinatesField.evaluateReal(fieldCache,3)
                        coords[i] = v
                    segmentLengths[nd-1,1] = arcLength(coords)
                elif xiv[1] == 1.0: #top left node
                    #Get the x1 length
                    for i in range(ndis):
                        fieldCache.setMeshLocation(elem,[xdiscret[i],0.0,0.0])
                        _,v = coordinatesField.evaluateReal(fieldCache,3)
                        coords[i] = v
                    segmentLengths[nd-1,0] = arcLength(coords)
                    
        circumferentialLengths = np.zeros((axialElements+1,1))
        axialLengths = np.zeros((circumferentialElements,1))
        for a in range(axialElements+1):
            snode = a*numberOfCircumfrentialNodes
            for i in range(numberOfCircumfrentialNodes):
                circumferentialLengths[a] += segmentLengths[snode+i,0]
                axialLengths[i] +=segmentLengths[snode+i,1]
        
        segmentWeights = np.zeros(segmentLengths.shape)
        for a in range(axialElements+1):
            snode = a*numberOfCircumfrentialNodes
            for i in range(numberOfCircumfrentialNodes):
                segmentWeights[snode+i,0] = segmentLengths[snode+i,0]/circumferentialLengths[a]
                segmentWeights[snode+i,1] = segmentLengths[snode+i,1]/axialLengths[i]
        
        self.segmentWeights = segmentWeights
        self.segmentLenths = segmentLengths
        self.circumferentialLengths = circumferentialLengths
        self.axialLengths = axialLengths
                
    def generateFlatMesh(self,region,circumferentialElements,axialElements):
        elementsCount1 = circumferentialElements
        elementsCount2 = axialElements
        coordinateDimensions = 3
        #context = Context('pm')
        #region = context.getDefaultRegion()
        fm = region.getFieldmodule()
        fm.beginChange()
        coordinates = fm.createFieldFiniteElement(coordinateDimensions)
        coordinates.setName('coordinates')
        coordinates.setManaged(True)
        coordinates.setTypeCoordinate(True)
        coordinates.setCoordinateSystemType(coordinates.COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN)
        coordinates.setComponentName(1, 'x')
        coordinates.setComponentName(2, 'y')
        coordinates.setComponentName(3, 'z')

        texture = fm.createFieldFiniteElement(2)
        texture.setName('texture')
        texture.setManaged(True)
        texture.setCoordinateSystemType(coordinates.COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN)
        texture.setComponentName(1, 'x')
        texture.setComponentName(2, 'y')


    
        nodes = fm.findNodesetByFieldDomainType(coordinates.DOMAIN_TYPE_NODES)
        nodetemplate = nodes.createNodetemplate()
        nodetemplate.defineField(coordinates)
        nodetemplate.defineField(texture)
        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(texture, -1, Node.VALUE_LABEL_VALUE, 1)
        nodetemplate.setValueNumberOfVersions(texture, -1, Node.VALUE_LABEL_D_DS1, 1)
        nodetemplate.setValueNumberOfVersions(texture, -1, Node.VALUE_LABEL_D_DS2, 1)

    
        mesh = fm.findMeshByDimension(2)
        bicubicHermiteBasis = fm.createElementbasis(2, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE)
        eft = mesh.createElementfieldtemplate(bicubicHermiteBasis)
        for n in range(4):
            eft.setFunctionNumberOfTerms(n*4 + 4, 0)
        elementtemplate = mesh.createElementtemplate()
        elementtemplate.setElementShapeType(Element.SHAPE_TYPE_SQUARE)
        result = elementtemplate.defineField(coordinates, -1, eft)
        result = elementtemplate.defineField(texture, -1, eft)
        cache = fm.createFieldcache()
    
        # create nodes
        nodeIdentifier = 1
        x = [ 0.0, 0.0, 0.0 ]
        dx_ds1 = [ 1.0 / elementsCount1, 0.0, 0.0 ]
        dx_ds2 = [ 0.0, 1.0 / elementsCount2, 0.0 ]
        
        numberOfCircumferentialNodes = elementsCount1 +1
        allNodes = dict()
        for n2 in range(elementsCount2 + 1):
            x[1] = float(n2) / elementsCount2 - 0.5
            yv = 2*x[1]
            for n1 in range(numberOfCircumferentialNodes):
                x[0] = float(n1) / (elementsCount1) - 0.5
                #Use square to circle map
                xv = 2*x[0]
                #Flip along x to match the element orientated opening of the mesh
                xx = xv*np.sqrt(1.0-0.5*yv**2)
                yy = yv*np.sqrt(1.0-0.5*xv**2)
                
                node = nodes.createNode(nodeIdentifier, nodetemplate)
                allNodes[nodeIdentifier] = node
                cache.setNode(node)
                coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, [xx,yy,0.0])
                texture.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, [x[0]+0.5,x[1]+0.5])
                texture.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, dx_ds1)
                texture.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, dx_ds2)                
                nodeIdentifier = nodeIdentifier + 1
        
        #Introduce some kink at the top and bottom
                
        '''
        #Does not produce expected mesh
        #Normalize x1-distribution of nodes
        for a in range(elementsCount2+1):
            snode = a*(elementsCount1 +1 ) + 1
            cylinderNode = a*(elementsCount1) + 1
            enode = snode + elementsCount1 
            cache.setNode(allNodes[snode])
            _,scoord = coordinates.evaluateReal(cache,3)
            cache.setNode(allNodes[enode])
            _,ecoord = coordinates.evaluateReal(cache,3)
            scoord = np.array(scoord)
            vec = np.array(ecoord) - scoord
            length = np.linalg.norm(vec)
            vec = vec/length
            #slength = length/elementsCount1 
            for n1 in range(1,elementsCount1):         
                cnode = snode + n1
                cache.setNode(allNodes[cnode])
                nc = scoord + vec*length*n1*self.segmentWeights[cylinderNode-1,0]
                coordinates.assignReal(cache,list(nc))
        
        #Normalize x2-distribution of nodes
        for i in range(elementsCount1+1):
            for a in range(1,elementsCount2+1):
                snode = (a-1)*(elementsCount1+1) +1+i
                cnode = snode + numberOfCircumferentialNodes
                cylinderNode = (a-1)*(elementsCount1) + 1 + i
                print snode,cylinderNode
                cache.setNode(allNodes[snode])
                _,scoord = coordinates.evaluateReal(cache,3)
                cache.setNode(allNodes[cnode])
                _,ecoord = coordinates.evaluateReal(cache,3)
                scoord = np.array(scoord)
                ecoord = np.array(ecoord)
                vec = scoord-ecoord
                ecoord = scoord +vec*self.segmentWeights[cylinderNode-1,1]
                coordinates.assignReal(cache,list(ecoord))
        '''
        #Manually distort
                     
        NumberOfElements = elementsCount1*elementsCount2
        # create elements
        elementIdentifier = 1
        no2 = (elementsCount1 + 1)
        for e2 in range(elementsCount2):
            for e1 in range(elementsCount1):
                #Note that the xi ordering is different with the top having the lowest element number to the bottom
                element = mesh.createElement(NumberOfElements-elementIdentifier+1, elementtemplate)
                bni = e2*no2 + e1 + 1
                nodeIdentifiers = [ bni, bni + 1, bni + no2, bni + no2 + 1 ]
                result = element.setNodesByIdentifier(eft, nodeIdentifiers)
                elementIdentifier = elementIdentifier + 1
        fm.defineAllFaces()
        smooth = fm.createFieldsmoothing()
        coordinates.smooth(smooth)    
        fm.endChange()
        
                
    def assignRegions(self,regionMappings,colors):
        '''
        Region assignment is in the descending order of regionvalue
        '''
        rnm = list(reversed(regionMappings.keys()))
        shape =self.surfaceCoordinates.shape
        rshape =(shape[0],shape[1])
        if len(shape)==2:
            rshape=(shape[0],1)
        self.regionMappings = np.ones(rshape,dtype=np.int)*len(rnm)
        self.colors = []
        for i,rn in enumerate(rnm):
            self.colors.append(colors[rn])
            poly = regionMappings[rn]
            if isinstance(poly, list):
                poly= np.array(poly)
            spts = self.pointsInPolygon(self.surfaceCoordinates, poly)
            self.regionMappings[spts] = i
        #Add a color for unmapped regions
        self.colors.append([255,255,255])

    def getBoundaryPoints(self):
        '''
        Return the boundary coordinates for the left, right wall and ladder
        '''
        #Senfd copies do that modification are not reflected
        return np.array(self.leftWallCoordinates),np.array(self.rightWallCoordinates),np.array(self.ladderCoordinates)


    def serialize(self,filename):
        with open(filename,'wb') as ser:
            if hasattr(self,'regionMappings'):
                sobj = [self.discret,self.boundaryDiscret,self.leftWallCoordinates,self.rightWallCoordinates, self.ladderCoordinates,\
                        self.surfaceCoordinates,self.anatomicalCoordinates,self.regionMappings,self.mesh]
            else:
                sobj = [self.discret,self.boundaryDiscret,self.leftWallCoordinates,self.rightWallCoordinates, self.ladderCoordinates,\
                        self.surfaceCoordinates,self.anatomicalCoordinates,None,self.mesh]
            pickle.dump(sobj,ser,2)

    
    def createImage(self,filename):
        pic = np.zeros((self.discret,self.discret,3),dtype=np.uint8)
        
        if hasattr(self, 'regionMappings'):
            for i in range(self.discret):
                for j in range(self.discret):
                    pic[i,j] = self.colors[self.regionMappings[i,j]] #Note that the coordinate system for numpy is different from qimage            
        else:
            for i in range(self.discret):
                for j in range(self.discret):
                    x,y = self.anatomicalCoordinates[i,j]
                    x = int(x*self.discret)+1
                    y = int(y*self.discret)+1
                    pic[x,y] = [255, 255, 255] #Note that the coordinate system for numpy is different from qimage
        from PIL import Image
        img = Image.fromarray(pic, 'RGB')
        img = img.resize((400,400),Image.BICUBIC)
        img.save(filename,format="png")
        #img.show()